Skip to content

Commit

Permalink
docs: migration 0.27 to 0.28 (#637)
Browse files Browse the repository at this point in the history
* 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>
  • Loading branch information
vasco-santos and jacobheun committed May 14, 2020
1 parent e25919d commit 37636ea
Show file tree
Hide file tree
Showing 2 changed files with 328 additions and 1 deletion.
2 changes: 1 addition & 1 deletion doc/migrations/v0.26-v0.27.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Migrating to the new API
# Migrating to the libp2p@0.27 API

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

Expand Down
327 changes: 327 additions & 0 deletions doc/migrations/v0.27-v.28.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,327 @@
# Migrating to the libp2p@0.28 API

A migration guide for refactoring your application code from libp2p v0.27.x to v0.28.0.

## Table of Contents

- [PeerStore API](#peerstore-api)
- [Migrating from Peer Info](#migrating-from-peer-info)
- [Create](#create)
- [API Implications](#api-implications)
- [Connection Manager and Registrar](#connection-manager-and-registrar)
- [Events](#events)

## PeerStore API

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`.

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.

### Adding a Peer

**Before**
```js
const peerId = ...
const peerInfo = new PeerInfo(peerId)

peerInfo.protocols.add('/ping/1.0.0')
peerInfo.protocols.add('/ping/2.0.0')
peerInfo.multiaddrs.add('/ip4/127.0.0.1/tcp/0')

libp2p.peerStore.put(peerInfo)
```

**After**
```js
const peerId = ...
const protocols = ['/ping/1.0.0', 'ping/2.0.0']
const multiaddrs = ['/ip4/127.0.0.1/tcp/0']

libp2p.peerStore.protoBook.add(peerId, protocols)
libp2p.peerStore.addressBook.add(peerId, multiaddrs)
```

### Getting a Peer

**Before**
```js
const peerId = ...
const peerInfo = libp2p.peerStore.get(peerId)
// { id: PeerId, multiaddrs: MultiaddrSet, protocols: Set<string>}
```

**After**
```js
const peerId = ...
const peer = libp2p.peerStore.get(peerId)
// { id: PeerId, addresses: Array<{ multiaddr: Multiaddr }>, protocols: Array<string> }
```

### Checking for a Peer

**Before**
```js
const peerId = ...
const hasData = libp2p.peerStore.has(peerId)
```

**After**
```js
const peerId = ...
const hasData = Boolean(libp2p.peerStore.get(peerId))
```

### Removing a Peer

**Before**
```js
libp2p.peerStore.remove(peerId)
```

**After**
```js
// Atomic
libp2p.peerStore.protoBook.delete(peerId)
libp2p.peerStore.addressBook.delete(peerId)
// Remove the peer and ALL of its associated data
libp2p.peerStore.delete(peerId)
```

### Get all known Peers

**Before**
```js
const peers = libp2p.peerStore.peers
// Map<string, PeerInfo>
```

**After**
```js
const peers = libp2p.peerStore.peers
// Similar to libp2p.peerStore.get()
// Map<string, { id: PeerId, addresses: Array<{ multiaddr: Multiaddr }>, protocols: Array<string> }
```

## Migrating from Peer Info

[`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.

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.

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.

### Create

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.

#### Using an existing PeerId

`libp2p.create` receives a `peerId` property instead of a `peerInfo` property.

**Before**
```js
const peerId = ...
const peerInfo = new PeerInfo(peerId)

const libp2p = await Libp2p.create({
peerInfo
// ...
})
```

**After**
```js
const peerId = ...

const libp2p = await Libp2p.create({
peerId
// ...
})
```

#### Providing listen addresses

**Before**
```js
const peerId = ...
const peerInfo = new PeerInfo(peerId)

peerInfo.multiaddrs.add('/ip4/127.0.0.1/tcp/0')

const libp2p = await Libp2p.create({
peerInfo
// ...
})

await libp2p.start()
```

**After**
```js
const peerId = ...

const libp2p = await Libp2p.create({
peerId,
addresses: {
listen: ['/ip4/127.0.0.1/tcp/0']
}
// ...
})
await libp2p.start()
```

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.
This was possible to achieve before, but in a hacky way by removing or adding addresses to the `peerInfo`, after the node starts.

**Before**
```js
const peerId = ...
const peerInfo = new PeerInfo(peerId)

peerInfo.multiaddrs.add('/ip4/127.0.0.1/tcp/8000')

const libp2p = await Libp2p.create({
peerInfo
// ...
})

await libp2p.start()
peerInfo.multiaddrs.add('/dns4/peer.io') // Announce
peerInfo.multiaddrs.delete('/ip4/127.0.0.1/tcp/8000') // Not announce
```

**After**
```js
const peerId = ...

const libp2p = await Libp2p.create({
peerId,
addresses: {
listen: ['/ip4/127.0.0.1/tcp/8000'],
announce: ['/dns4/peer.io'],
noAnnounce: ['/ip4/127.0.0.1/tcp/8000']
}
// ...
})
await libp2p.start()
```

### API Implications

#### Peer Dialing, Hangup and Ping

`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.

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.

**Before**
```js
const peerInfo = ... // PeerInfo containing its multiaddrs

const connection = await libp2p.dial(peerInfo)
```

**After**
```js
const peerId = ...

// Known multiaddrs should be added to the PeerStore
libp2p.peerStore.addressBook.add(peerId, multiaddrs)

const connection = await libp2p.dial(peerId)
```

#### Content Routing and Peer Routing

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.

**Before**
```js
for await (const peerInfo of libp2p.contentRouting.findProviders(cid)) {
// peerInfo is a PeerInfo instance
}
```

**After**
```js
for await (const peer of libp2p.contentRouting.findProviders(cid)) {
// { id: PeerId, multiaddrs: Multiaddr[] }
}
```

**Before**
```js
const peerInfo = await libp2p.peerRouting.findPeer(peerId)
// peerInfo is a PeerInfo instance
```

**After**
```js
const peer = await libp2p.peerRouting.findPeer(peerId)
// { id: PeerId, multiaddrs: Multiaddr[] }
```

## Connection Manager and Registrar

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.

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`.

**Before**
```js
const connection = libp2p.registrar.getConnection(peerId)
```

**After**
```js
const connection = libp2p.connectionManager.get(peerId)
```

## Events

### Connection Events

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.

**Before**
```js
libp2p.on('peer:connect', (peerInfo) => {
// PeerInfo instance
})

libp2p.on('peer:disconnect', (peerInfo) => {
// PeerInfo instance
})
```

**After**
```js
libp2p.connectionManager.on('peer:connect', (connection) => {
// Connection instance
})

libp2p.connectionManager.on('peer:disconnect', (connection) => {
// Connection instance
})
```

### Peer Discovery

**Before**
```js
libp2p.on('peer:discovery', (peerInfo) => {
// PeerInfo instance
})
```

**After**
```js
libp2p.on('peer:discovery', (peerId) => {
// peerId instance
})
```

[connection]: https://github.com/libp2p/js-interfaces/tree/master/src/connection
[multiaddr]: https://github.com/multiformats/js-multiaddr
[peer-id]: https://github.com/libp2p/js-peer-id
[peer-info]: https://github.com/libp2p/js-peer-info

0 comments on commit 37636ea

Please sign in to comment.