Skip to content

Commit 56316b8

Browse files
vasco-santosjacobheun
andcommittedMay 28, 2020
docs: migration 0.27 to 0.28 (#637)
* docs: migration 0.27 to 0.28 * chore: apply suggestions from code review Co-authored-by: Jacob Heun <jacobheun@gmail.com> Co-authored-by: Jacob Heun <jacobheun@gmail.com>
1 parent aaa1155 commit 56316b8

File tree

2 files changed

+328
-1
lines changed

2 files changed

+328
-1
lines changed
 

‎doc/migrations/v0.26-v0.27.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Migrating to the new API
1+
# Migrating to the libp2p@0.27 API
22

33
A migration guide for refactoring your application code from libp2p v0.26.x to v0.27.0.
44

‎doc/migrations/v0.27-v.28.md

+327
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,327 @@
1+
# Migrating to the libp2p@0.28 API
2+
3+
A migration guide for refactoring your application code from libp2p v0.27.x to v0.28.0.
4+
5+
## Table of Contents
6+
7+
- [PeerStore API](#peerstore-api)
8+
- [Migrating from Peer Info](#migrating-from-peer-info)
9+
- [Create](#create)
10+
- [API Implications](#api-implications)
11+
- [Connection Manager and Registrar](#connection-manager-and-registrar)
12+
- [Events](#events)
13+
14+
## PeerStore API
15+
16+
In `libp2p@0.27` we integrated the PeerStore (former [peer-book](https://github.com/libp2p/js-peer-book)) into the codebase. By that time, it was not documented in the [API DOC](../API.md) since it kept the same API as the `peer-book` and it was expected to be completelly rewritten in `libp2p@0.28`.
17+
18+
Moving towards a separation of concerns regarding known peers' data, as well as enabling PeerStore persistence, the PeerStore is now divided into four main components: `AddressBook`, `ProtoBook`, `KeyBook` and `MetadataBook`. This resulted in API changes in the PeerStore, since each type of peer data should now be added in an atomic fashion.
19+
20+
### Adding a Peer
21+
22+
**Before**
23+
```js
24+
const peerId = ...
25+
const peerInfo = new PeerInfo(peerId)
26+
27+
peerInfo.protocols.add('/ping/1.0.0')
28+
peerInfo.protocols.add('/ping/2.0.0')
29+
peerInfo.multiaddrs.add('/ip4/127.0.0.1/tcp/0')
30+
31+
libp2p.peerStore.put(peerInfo)
32+
```
33+
34+
**After**
35+
```js
36+
const peerId = ...
37+
const protocols = ['/ping/1.0.0', 'ping/2.0.0']
38+
const multiaddrs = ['/ip4/127.0.0.1/tcp/0']
39+
40+
libp2p.peerStore.protoBook.add(peerId, protocols)
41+
libp2p.peerStore.addressBook.add(peerId, multiaddrs)
42+
```
43+
44+
### Getting a Peer
45+
46+
**Before**
47+
```js
48+
const peerId = ...
49+
const peerInfo = libp2p.peerStore.get(peerId)
50+
// { id: PeerId, multiaddrs: MultiaddrSet, protocols: Set<string>}
51+
```
52+
53+
**After**
54+
```js
55+
const peerId = ...
56+
const peer = libp2p.peerStore.get(peerId)
57+
// { id: PeerId, addresses: Array<{ multiaddr: Multiaddr }>, protocols: Array<string> }
58+
```
59+
60+
### Checking for a Peer
61+
62+
**Before**
63+
```js
64+
const peerId = ...
65+
const hasData = libp2p.peerStore.has(peerId)
66+
```
67+
68+
**After**
69+
```js
70+
const peerId = ...
71+
const hasData = Boolean(libp2p.peerStore.get(peerId))
72+
```
73+
74+
### Removing a Peer
75+
76+
**Before**
77+
```js
78+
libp2p.peerStore.remove(peerId)
79+
```
80+
81+
**After**
82+
```js
83+
// Atomic
84+
libp2p.peerStore.protoBook.delete(peerId)
85+
libp2p.peerStore.addressBook.delete(peerId)
86+
// Remove the peer and ALL of its associated data
87+
libp2p.peerStore.delete(peerId)
88+
```
89+
90+
### Get all known Peers
91+
92+
**Before**
93+
```js
94+
const peers = libp2p.peerStore.peers
95+
// Map<string, PeerInfo>
96+
```
97+
98+
**After**
99+
```js
100+
const peers = libp2p.peerStore.peers
101+
// Similar to libp2p.peerStore.get()
102+
// Map<string, { id: PeerId, addresses: Array<{ multiaddr: Multiaddr }>, protocols: Array<string> }
103+
```
104+
105+
## Migrating from Peer Info
106+
107+
[`PeerInfo`][peer-info] is a libp2p peer abstraction layer that combines a [`PeerId`][peer-id] with known data of the peer, namely its multiaddrs and protocols. It has been used for a long time by `js-libp2p` and its modules to carry this data around the libp2p stack, as well as by the libp2p API, both for providing this data to the users or to receive it from them.
108+
109+
Since this PeerInfo instances were navigating through the entire codebases, some data inconsistencies could be observed in libp2p. Different libp2p subsystems were running with different visions of the known peers data. For instance, a libp2p subsystem receives a copy of this instance with the peer multiaddrs and protocols, but if new data of the peer is obtained from other subsystem, it would not be updated on the former. Moreover, considering that several subsystems were modifying the peer data, libp2p had no way to determine the accurate data.
110+
111+
Considering the complete revamp of the libp2p PeerStore towards its second version, the PeerStore now acts as the single source of truth, we do not need to carry [`PeerInfo`][peer-info] instances around. This also solves all the problems stated above, since subsystems will report new observations to the PeerStore.
112+
113+
### Create
114+
115+
While it was possible to create a libp2p node without providing a [`PeerInfo`][peer-info], there were 2 use cases where a [`PeerInfo`][peer-info] was provided when creating a libp2p node.
116+
117+
#### Using an existing PeerId
118+
119+
`libp2p.create` receives a `peerId` property instead of a `peerInfo` property.
120+
121+
**Before**
122+
```js
123+
const peerId = ...
124+
const peerInfo = new PeerInfo(peerId)
125+
126+
const libp2p = await Libp2p.create({
127+
peerInfo
128+
// ...
129+
})
130+
```
131+
132+
**After**
133+
```js
134+
const peerId = ...
135+
136+
const libp2p = await Libp2p.create({
137+
peerId
138+
// ...
139+
})
140+
```
141+
142+
#### Providing listen addresses
143+
144+
**Before**
145+
```js
146+
const peerId = ...
147+
const peerInfo = new PeerInfo(peerId)
148+
149+
peerInfo.multiaddrs.add('/ip4/127.0.0.1/tcp/0')
150+
151+
const libp2p = await Libp2p.create({
152+
peerInfo
153+
// ...
154+
})
155+
156+
await libp2p.start()
157+
```
158+
159+
**After**
160+
```js
161+
const peerId = ...
162+
163+
const libp2p = await Libp2p.create({
164+
peerId,
165+
addresses: {
166+
listen: ['/ip4/127.0.0.1/tcp/0']
167+
}
168+
// ...
169+
})
170+
await libp2p.start()
171+
```
172+
173+
There is also a bonus regarding the peer addresses. `libp2p@0.28` comes with an AddressManager that also allows the configuration of `announce` and `noAnnounce` addresses.
174+
This was possible to achieve before, but in a hacky way by removing or adding addresses to the `peerInfo`, after the node starts.
175+
176+
**Before**
177+
```js
178+
const peerId = ...
179+
const peerInfo = new PeerInfo(peerId)
180+
181+
peerInfo.multiaddrs.add('/ip4/127.0.0.1/tcp/8000')
182+
183+
const libp2p = await Libp2p.create({
184+
peerInfo
185+
// ...
186+
})
187+
188+
await libp2p.start()
189+
peerInfo.multiaddrs.add('/dns4/peer.io') // Announce
190+
peerInfo.multiaddrs.delete('/ip4/127.0.0.1/tcp/8000') // Not announce
191+
```
192+
193+
**After**
194+
```js
195+
const peerId = ...
196+
197+
const libp2p = await Libp2p.create({
198+
peerId,
199+
addresses: {
200+
listen: ['/ip4/127.0.0.1/tcp/8000'],
201+
announce: ['/dns4/peer.io'],
202+
noAnnounce: ['/ip4/127.0.0.1/tcp/8000']
203+
}
204+
// ...
205+
})
206+
await libp2p.start()
207+
```
208+
209+
### API Implications
210+
211+
#### Peer Dialing, Hangup and Ping
212+
213+
`libp2p.dial`, `libp2p.dialProtocol`, `libp2p.hangup` and `libp2p.ping` supported as the target parameter a [`PeerInfo`](peer-info), a [`PeerId`](peer-id), a [`Multiaddr`][multiaddr] and a string representation of the multiaddr. Considering that [`PeerInfo`](peer-info) is being removed from libp2p, all these methods will now support the other 3 possibilities.
214+
215+
There is one relevant aspect to consider with this change. When using a [`PeerId`](peer-id), the PeerStore **MUST** have known addresses for that peer in its AddressBook, so that it can perform the request. This was also true in the past, but it is important pointing it out because it might not be enough to switch from using [`PeerInfo`](peer-info) to [`PeerId`](peer-id). When using a [`PeerInfo`](peer-info), the PeerStore was not required to have the multiaddrs when they existed on the PeerInfo instance.
216+
217+
**Before**
218+
```js
219+
const peerInfo = ... // PeerInfo containing its multiaddrs
220+
221+
const connection = await libp2p.dial(peerInfo)
222+
```
223+
224+
**After**
225+
```js
226+
const peerId = ...
227+
228+
// Known multiaddrs should be added to the PeerStore
229+
libp2p.peerStore.addressBook.add(peerId, multiaddrs)
230+
231+
const connection = await libp2p.dial(peerId)
232+
```
233+
234+
#### Content Routing and Peer Routing
235+
236+
Both [content-routing](https://github.com/libp2p/js-libp2p-interfaces/tree/master/src/content-routing) and [peer-routing](https://github.com/libp2p/js-libp2p-interfaces/tree/master/src/peer-routing) interfaces were modified to not return a ['PeerInfo'][peer-info] instance.
237+
238+
**Before**
239+
```js
240+
for await (const peerInfo of libp2p.contentRouting.findProviders(cid)) {
241+
// peerInfo is a PeerInfo instance
242+
}
243+
```
244+
245+
**After**
246+
```js
247+
for await (const peer of libp2p.contentRouting.findProviders(cid)) {
248+
// { id: PeerId, multiaddrs: Multiaddr[] }
249+
}
250+
```
251+
252+
**Before**
253+
```js
254+
const peerInfo = await libp2p.peerRouting.findPeer(peerId)
255+
// peerInfo is a PeerInfo instance
256+
```
257+
258+
**After**
259+
```js
260+
const peer = await libp2p.peerRouting.findPeer(peerId)
261+
// { id: PeerId, multiaddrs: Multiaddr[] }
262+
```
263+
264+
## Connection Manager and Registrar
265+
266+
Registrar was introduced in `libp2p@0.27` along with [libp2p topologies](https://github.com/libp2p/js-libp2p-interfaces/tree/master/src/topology). `Registrar` and `ConnectionManager` were both listening on new connections and keeping their record of the open connections with other peers.
267+
268+
The registrar API was not documented in the [API DOC](../API.md). However, it exposed a useful method for some libp2p users, `libp2p.registrar.getConnection()`. On the other hand, the connection Manager did not provide any methods to access its stored connections. On `libp2p@0.28` we removed this data duplication and the connections are handled solely by the `ConnectionManager`.
269+
270+
**Before**
271+
```js
272+
const connection = libp2p.registrar.getConnection(peerId)
273+
```
274+
275+
**After**
276+
```js
277+
const connection = libp2p.connectionManager.get(peerId)
278+
```
279+
280+
## Events
281+
282+
### Connection Events
283+
284+
Libp2p emits events whenever new connections are established. These emitted events previously providing the [`PeerInfo`](peer-info) of the peer that connected. In `libp2p@0.28` these events are now emitted from the Connection Manager and will now emit the [`connection`](connection) itself.
285+
286+
**Before**
287+
```js
288+
libp2p.on('peer:connect', (peerInfo) => {
289+
// PeerInfo instance
290+
})
291+
292+
libp2p.on('peer:disconnect', (peerInfo) => {
293+
// PeerInfo instance
294+
})
295+
```
296+
297+
**After**
298+
```js
299+
libp2p.connectionManager.on('peer:connect', (connection) => {
300+
// Connection instance
301+
})
302+
303+
libp2p.connectionManager.on('peer:disconnect', (connection) => {
304+
// Connection instance
305+
})
306+
```
307+
308+
### Peer Discovery
309+
310+
**Before**
311+
```js
312+
libp2p.on('peer:discovery', (peerInfo) => {
313+
// PeerInfo instance
314+
})
315+
```
316+
317+
**After**
318+
```js
319+
libp2p.on('peer:discovery', (peerId) => {
320+
// peerId instance
321+
})
322+
```
323+
324+
[connection]: https://github.com/libp2p/js-interfaces/tree/master/src/connection
325+
[multiaddr]: https://github.com/multiformats/js-multiaddr
326+
[peer-id]: https://github.com/libp2p/js-peer-id
327+
[peer-info]: https://github.com/libp2p/js-peer-info

0 commit comments

Comments
 (0)
Please sign in to comment.