mirror of
https://github.com/fluencelabs/js-libp2p
synced 2025-05-29 02:11:18 +00:00
feat: address and proto books (#590)
* feat: address and proto books * chore: apply suggestions from code review Co-Authored-By: Jacob Heun <jacobheun@gmail.com> * chore: minor fixes and initial tests added * chore: integrate new peer-store with code using adapters for other modules * chore: do not use peerstore.put on get-peer-info * chore: apply suggestions from code review Co-Authored-By: Jacob Heun <jacobheun@gmail.com> * chore: add new peer store tests * chore: apply suggestions from code review Co-Authored-By: Jacob Heun <jacobheun@gmail.com> Co-authored-by: Jacob Heun <jacobheun@gmail.com>
This commit is contained in:
parent
2620d46f01
commit
be45fc498f
409
doc/API.md
409
doc/API.md
@ -17,6 +17,18 @@
|
|||||||
* [`contentRouting.put`](#contentroutingput)
|
* [`contentRouting.put`](#contentroutingput)
|
||||||
* [`contentRouting.get`](#contentroutingget)
|
* [`contentRouting.get`](#contentroutingget)
|
||||||
* [`contentRouting.getMany`](#contentroutinggetmany)
|
* [`contentRouting.getMany`](#contentroutinggetmany)
|
||||||
|
* [`peerStore.addressBook.add`](#peerstoreaddressbookadd)
|
||||||
|
* [`peerStore.addressBook.delete`](#peerstoreaddressbookdelete)
|
||||||
|
* [`peerStore.addressBook.get`](#peerstoreaddressbookget)
|
||||||
|
* [`peerStore.addressBook.getMultiaddrsForPeer`](#peerstoreaddressbookgetmultiaddrsforpeer)
|
||||||
|
* [`peerStore.addressBook.set`](#peerstoreaddressbookset)
|
||||||
|
* [`peerStore.protoBook.add`](#peerstoreprotobookadd)
|
||||||
|
* [`peerStore.protoBook.delete`](#peerstoreprotobookdelete)
|
||||||
|
* [`peerStore.protoBook.get`](#peerstoreprotobookget)
|
||||||
|
* [`peerStore.protoBook.set`](#peerstoreprotobookset)
|
||||||
|
* [`peerStore.delete`](#peerstoredelete)
|
||||||
|
* [`peerStore.get`](#peerstoreget)
|
||||||
|
* [`peerStore.peers`](#peerstorepeers)
|
||||||
* [`pubsub.getSubscribers`](#pubsubgetsubscribers)
|
* [`pubsub.getSubscribers`](#pubsubgetsubscribers)
|
||||||
* [`pubsub.getTopics`](#pubsubgettopics)
|
* [`pubsub.getTopics`](#pubsubgettopics)
|
||||||
* [`pubsub.publish`](#pubsubpublish)
|
* [`pubsub.publish`](#pubsubpublish)
|
||||||
@ -44,13 +56,13 @@ Creates an instance of Libp2p.
|
|||||||
|
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
|------|------|-------------|
|
|------|------|-------------|
|
||||||
| options | `Object` | libp2p options |
|
| options | `object` | libp2p options |
|
||||||
| options.modules | `Array<Object>` | libp2p modules to use |
|
| options.modules | `Array<object>` | libp2p modules to use |
|
||||||
| [options.config] | `Object` | libp2p modules configuration and core configuration |
|
| [options.config] | `object` | libp2p modules configuration and core configuration |
|
||||||
| [options.connectionManager] | `Object` | libp2p Connection Manager configuration |
|
| [options.connectionManager] | `object` | libp2p Connection Manager configuration |
|
||||||
| [options.datastore] | `Object` | must implement [ipfs/interface-datastore](https://github.com/ipfs/interface-datastore) (in memory datastore will be used if not provided) |
|
| [options.datastore] | `object` | must implement [ipfs/interface-datastore](https://github.com/ipfs/interface-datastore) (in memory datastore will be used if not provided) |
|
||||||
| [options.dialer] | `Object` | libp2p Dialer configuration
|
| [options.dialer] | `object` | libp2p Dialer configuration
|
||||||
| [options.metrics] | `Object` | libp2p Metrics configuration
|
| [options.metrics] | `object` | libp2p Metrics configuration
|
||||||
| [options.peerInfo] | [`PeerInfo`][peer-info] | peerInfo instance (it will be created if not provided) |
|
| [options.peerInfo] | [`PeerInfo`][peer-info] | peerInfo instance (it will be created if not provided) |
|
||||||
|
|
||||||
For Libp2p configurations and modules details read the [Configuration Document](./CONFIGURATION.md).
|
For Libp2p configurations and modules details read the [Configuration Document](./CONFIGURATION.md).
|
||||||
@ -181,7 +193,7 @@ for (const [peerId, connections] of libp2p.connections) {
|
|||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
|------|------|-------------|
|
|------|------|-------------|
|
||||||
| peer | [`PeerInfo`][peer-info]\|[`PeerId`][peer-id]\|[`Multiaddr`][multiaddr]\|`string` | The peer to dial. If a [`Multiaddr`][multiaddr] or its string is provided, it **must** include the peer id |
|
| peer | [`PeerInfo`][peer-info]\|[`PeerId`][peer-id]\|[`Multiaddr`][multiaddr]\|`string` | The peer to dial. If a [`Multiaddr`][multiaddr] or its string is provided, it **must** include the peer id |
|
||||||
| [options] | `Object` | dial options |
|
| [options] | `object` | dial options |
|
||||||
| [options.signal] | [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) | An `AbortSignal` instance obtained from an [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) that can be used to abort the connection before it completes |
|
| [options.signal] | [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) | An `AbortSignal` instance obtained from an [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) that can be used to abort the connection before it completes |
|
||||||
|
|
||||||
#### Returns
|
#### Returns
|
||||||
@ -216,8 +228,8 @@ Dials to another peer in the network and selects a protocol to communicate with
|
|||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
|------|------|-------------|
|
|------|------|-------------|
|
||||||
| peer | [`PeerInfo`][peer-info]\|[`PeerId`][peer-id]\|[`Multiaddr`][multiaddr]\|`string` | The peer to dial. If a [`Multiaddr`][multiaddr] or its string is provided, it **must** include the peer id |
|
| peer | [`PeerInfo`][peer-info]\|[`PeerId`][peer-id]\|[`Multiaddr`][multiaddr]\|`string` | The peer to dial. If a [`Multiaddr`][multiaddr] or its string is provided, it **must** include the peer id |
|
||||||
| protocols | `String|Array<String>` | A list of protocols (or single protocol) to negotiate with. Protocols are attempted in order until a match is made. (e.g '/ipfs/bitswap/1.1.0') |
|
| protocols | `string|Array<string>` | A list of protocols (or single protocol) to negotiate with. Protocols are attempted in order until a match is made. (e.g '/ipfs/bitswap/1.1.0') |
|
||||||
| [options] | `Object` | dial options |
|
| [options] | `object` | dial options |
|
||||||
| [options.signal] | [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) | An `AbortSignal` instance obtained from an [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) that can be used to abort the connection before it completes |
|
| [options.signal] | [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) | An `AbortSignal` instance obtained from an [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) that can be used to abort the connection before it completes |
|
||||||
|
|
||||||
#### Returns
|
#### Returns
|
||||||
@ -275,7 +287,7 @@ In the event of a new handler for the same protocol being added, the first one i
|
|||||||
|
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
|------|------|-------------|
|
|------|------|-------------|
|
||||||
| protocols | `Array<String>|String` | protocols to register |
|
| protocols | `Array<string>|string` | protocols to register |
|
||||||
| handler | `function({ connection:*, stream:*, protocol:string })` | handler to call |
|
| handler | `function({ connection:*, stream:*, protocol:string })` | handler to call |
|
||||||
|
|
||||||
|
|
||||||
@ -300,7 +312,7 @@ Unregisters all handlers with the given protocols
|
|||||||
|
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
|------|------|-------------|
|
|------|------|-------------|
|
||||||
| protocols | `Array<String>|String` | protocols to unregister |
|
| protocols | `Array<string>|string` | protocols to unregister |
|
||||||
|
|
||||||
#### Example
|
#### Example
|
||||||
|
|
||||||
@ -345,7 +357,7 @@ Iterates over all peer routers in series to find the given peer. If the DHT is e
|
|||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
|------|------|-------------|
|
|------|------|-------------|
|
||||||
| peerId | [`PeerId`][peer-id] | ID of the peer to find |
|
| peerId | [`PeerId`][peer-id] | ID of the peer to find |
|
||||||
| options | `Object` | operation options |
|
| options | `object` | operation options |
|
||||||
| options.timeout | `number` | maximum time the query should run |
|
| options.timeout | `number` | maximum time the query should run |
|
||||||
|
|
||||||
#### Returns
|
#### Returns
|
||||||
@ -373,7 +385,7 @@ Once a content router succeeds, the iteration will stop. If the DHT is enabled,
|
|||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
|------|------|-------------|
|
|------|------|-------------|
|
||||||
| cid | [`CID`][cid] | cid to find |
|
| cid | [`CID`][cid] | cid to find |
|
||||||
| options | `Object` | operation options |
|
| options | `object` | operation options |
|
||||||
| options.timeout | `number` | maximum time the query should run |
|
| options.timeout | `number` | maximum time the query should run |
|
||||||
| options.maxNumProviders | `number` | maximum number of providers to find |
|
| options.maxNumProviders | `number` | maximum number of providers to find |
|
||||||
|
|
||||||
@ -427,9 +439,9 @@ Writes a value to a key in the DHT.
|
|||||||
|
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
|------|------|-------------|
|
|------|------|-------------|
|
||||||
| key | `String` | key to add to the dht |
|
| key | `string` | key to add to the dht |
|
||||||
| value | `Buffer` | value to add to the dht |
|
| value | `Buffer` | value to add to the dht |
|
||||||
| [options] | `Object` | put options |
|
| [options] | `object` | put options |
|
||||||
| [options.minPeers] | `number` | minimum number of peers required to successfully put (default: closestPeers.length) |
|
| [options.minPeers] | `number` | minimum number of peers required to successfully put (default: closestPeers.length) |
|
||||||
|
|
||||||
#### Returns
|
#### Returns
|
||||||
@ -458,8 +470,8 @@ Queries the DHT for a value stored for a given key.
|
|||||||
|
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
|------|------|-------------|
|
|------|------|-------------|
|
||||||
| key | `String` | key to get from the dht |
|
| key | `string` | key to get from the dht |
|
||||||
| [options] | `Object` | get options |
|
| [options] | `object` | get options |
|
||||||
| [options.timeout] | `number` | maximum time the query should run |
|
| [options.timeout] | `number` | maximum time the query should run |
|
||||||
|
|
||||||
#### Returns
|
#### Returns
|
||||||
@ -487,9 +499,9 @@ Queries the DHT for the n values stored for the given key (without sorting).
|
|||||||
|
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
|------|------|-------------|
|
|------|------|-------------|
|
||||||
| key | `String` | key to get from the dht |
|
| key | `string` | key to get from the dht |
|
||||||
| nvals | `number` | number of values aimed |
|
| nvals | `number` | number of values aimed |
|
||||||
| [options] | `Object` | get options |
|
| [options] | `object` | get options |
|
||||||
| [options.timeout] | `number` | maximum time the query should run |
|
| [options.timeout] | `number` | maximum time the query should run |
|
||||||
|
|
||||||
#### Returns
|
#### Returns
|
||||||
@ -507,6 +519,348 @@ const key = '/key'
|
|||||||
const { from, val } = await libp2p.contentRouting.get(key)
|
const { from, val } = await libp2p.contentRouting.get(key)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### peerStore.addressBook.add
|
||||||
|
|
||||||
|
Adds known `multiaddrs` of a given peer. If the peer is not known, it will be set with the provided multiaddrs.
|
||||||
|
|
||||||
|
`peerStore.addressBook.add(peerId, multiaddrs)`
|
||||||
|
|
||||||
|
#### Parameters
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
|------|------|-------------|
|
||||||
|
| peerId | [`PeerId`][peer-id] | peerId to set |
|
||||||
|
| multiaddrs | |`Array<Multiaddr>` | [`Multiaddrs`][multiaddr] to add |
|
||||||
|
|
||||||
|
#### Returns
|
||||||
|
|
||||||
|
| Type | Description |
|
||||||
|
|------|-------------|
|
||||||
|
| `AddressBook` | Returns the Address Book component |
|
||||||
|
|
||||||
|
#### Example
|
||||||
|
|
||||||
|
```js
|
||||||
|
peerStore.addressBook.add(peerId, multiaddr)
|
||||||
|
```
|
||||||
|
|
||||||
|
### peerStore.addressBook.delete
|
||||||
|
|
||||||
|
Delete the provided peer from the book.
|
||||||
|
|
||||||
|
`peerStore.addressBook.delete(peerId)`
|
||||||
|
|
||||||
|
#### Parameters
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
|------|------|-------------|
|
||||||
|
| peerId | [`PeerId`][peer-id] | peerId to remove |
|
||||||
|
|
||||||
|
#### Returns
|
||||||
|
|
||||||
|
| Type | Description |
|
||||||
|
|------|-------------|
|
||||||
|
| `boolean` | true if found and removed |
|
||||||
|
|
||||||
|
#### Example
|
||||||
|
|
||||||
|
```js
|
||||||
|
peerStore.addressBook.delete(peerId)
|
||||||
|
// false
|
||||||
|
peerStore.addressBook.set(peerId, multiaddr)
|
||||||
|
peerStore.addressBook.delete(peerId)
|
||||||
|
// true
|
||||||
|
```
|
||||||
|
|
||||||
|
### peerStore.addressBook.get
|
||||||
|
|
||||||
|
Get the known [`MultiaddrInfos`][multiaddr-info] of a provided peer.
|
||||||
|
|
||||||
|
`peerStore.addressBook.get(peerId)`
|
||||||
|
|
||||||
|
#### Parameters
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
|------|------|-------------|
|
||||||
|
| peerId | [`PeerId`][peer-id] | peerId to get |
|
||||||
|
|
||||||
|
#### Returns
|
||||||
|
|
||||||
|
| Type | Description |
|
||||||
|
|------|-------------|
|
||||||
|
| `Array<MultiaddrInfo>` | Array of peer's multiaddr with their relevant information [`MultiaddrInfo`][multiaddr-info] |
|
||||||
|
|
||||||
|
#### Example
|
||||||
|
|
||||||
|
```js
|
||||||
|
peerStore.addressBook.get(peerId)
|
||||||
|
// undefined
|
||||||
|
peerStore.addressBook.set(peerId, multiaddr)
|
||||||
|
peerStore.addressBook.get(peerId)
|
||||||
|
// [
|
||||||
|
// {
|
||||||
|
// multiaddr: /ip4/140.10.2.1/tcp/8000,
|
||||||
|
// ...
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// multiaddr: /ip4/140.10.2.1/ws/8001
|
||||||
|
// ...
|
||||||
|
// },
|
||||||
|
// ]
|
||||||
|
```
|
||||||
|
|
||||||
|
## peerStore.addressBook.getMultiaddrsForPeer
|
||||||
|
|
||||||
|
Get the known `Multiaddr` of a provided peer. All returned multiaddrs will include the encapsulated `PeerId` of the peer.
|
||||||
|
|
||||||
|
`peerStore.addressBook.getMultiaddrsForPeer(peerId)`
|
||||||
|
|
||||||
|
#### Parameters
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
|------|------|-------------|
|
||||||
|
| peerId | [`PeerId`][peer-id] | peerId to get |
|
||||||
|
|
||||||
|
#### Returns
|
||||||
|
|
||||||
|
| Type | Description |
|
||||||
|
|------|-------------|
|
||||||
|
| `Array<Multiaddr>` | Array of peer's multiaddr |
|
||||||
|
|
||||||
|
#### Example
|
||||||
|
|
||||||
|
```js
|
||||||
|
peerStore.addressBook.getMultiaddrsForPeer(peerId)
|
||||||
|
// undefined
|
||||||
|
peerStore.addressBook.set(peerId, multiaddr)
|
||||||
|
peerStore.addressBook.getMultiaddrsForPeer(peerId)
|
||||||
|
// [
|
||||||
|
// /ip4/140.10.2.1/tcp/8000/p2p/QmW8rAgaaA6sRydK1k6vonShQME47aDxaFidbtMevWs73t
|
||||||
|
// /ip4/140.10.2.1/ws/8001/p2p/QmW8rAgaaA6sRydK1k6vonShQME47aDxaFidbtMevWs73t
|
||||||
|
// ]
|
||||||
|
```
|
||||||
|
|
||||||
|
### peerStore.addressBook.set
|
||||||
|
|
||||||
|
Set known `multiaddrs` of a given peer.
|
||||||
|
|
||||||
|
`peerStore.addressBook.set(peerId, multiaddrs)`
|
||||||
|
|
||||||
|
#### Parameters
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
|------|------|-------------|
|
||||||
|
| peerId | [`PeerId`][peer-id] | peerId to set |
|
||||||
|
| multiaddrs | |`Array<Multiaddr>` | [`Multiaddrs`][multiaddr] to store |
|
||||||
|
|
||||||
|
#### Returns
|
||||||
|
|
||||||
|
| Type | Description |
|
||||||
|
|------|-------------|
|
||||||
|
| `AddressBook` | Returns the Address Book component |
|
||||||
|
|
||||||
|
#### Example
|
||||||
|
|
||||||
|
```js
|
||||||
|
peerStore.addressBook.add(peerId, multiaddr)
|
||||||
|
```
|
||||||
|
|
||||||
|
### peerStore.protoBook.add
|
||||||
|
|
||||||
|
Add known `protocols` of a given peer.
|
||||||
|
|
||||||
|
`peerStore.protoBook.add(peerId, protocols)`
|
||||||
|
|
||||||
|
#### Parameters
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
|------|------|-------------|
|
||||||
|
| peerId | [`PeerId`][peer-id] | peerId to set |
|
||||||
|
| protocols | `Array<string>` | protocols to add |
|
||||||
|
|
||||||
|
#### Returns
|
||||||
|
|
||||||
|
| Type | Description |
|
||||||
|
|------|-------------|
|
||||||
|
| `ProtoBook` | Returns the Proto Book component |
|
||||||
|
|
||||||
|
#### Example
|
||||||
|
|
||||||
|
```js
|
||||||
|
peerStore.protoBook.add(peerId, protocols)
|
||||||
|
```
|
||||||
|
|
||||||
|
### peerStore.protoBook.delete
|
||||||
|
|
||||||
|
Delete the provided peer from the book.
|
||||||
|
|
||||||
|
`peerStore.protoBook.delete(peerId)`
|
||||||
|
|
||||||
|
#### Parameters
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
|------|------|-------------|
|
||||||
|
| peerId | [`PeerId`][peer-id] | peerId to remove |
|
||||||
|
|
||||||
|
#### Returns
|
||||||
|
|
||||||
|
| Type | Description |
|
||||||
|
|------|-------------|
|
||||||
|
| `boolean` | true if found and removed |
|
||||||
|
|
||||||
|
#### Example
|
||||||
|
|
||||||
|
```js
|
||||||
|
peerStore.protoBook.delete(peerId)
|
||||||
|
// false
|
||||||
|
peerStore.protoBook.set(peerId, protocols)
|
||||||
|
peerStore.protoBook.delete(peerId)
|
||||||
|
// true
|
||||||
|
```
|
||||||
|
|
||||||
|
### peerStore.protoBook.get
|
||||||
|
|
||||||
|
Get the known `protocols` of a provided peer.
|
||||||
|
|
||||||
|
`peerStore.protoBook.get(peerId)`
|
||||||
|
|
||||||
|
#### Parameters
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
|------|------|-------------|
|
||||||
|
| peerId | [`PeerId`][peer-id] | peerId to get |
|
||||||
|
|
||||||
|
#### Returns
|
||||||
|
|
||||||
|
| Type | Description |
|
||||||
|
|------|-------------|
|
||||||
|
| `Array<string>` | Array of peer's supported protocols |
|
||||||
|
|
||||||
|
#### Example
|
||||||
|
|
||||||
|
```js
|
||||||
|
peerStore.protoBook.get(peerId)
|
||||||
|
// undefined
|
||||||
|
peerStore.protoBook.set(peerId, [ '/proto/1.0.0', '/proto/1.1.0' ])
|
||||||
|
peerStore.protoBook.get(peerId)
|
||||||
|
// [ '/proto/1.0.0', '/proto/1.1.0' ]
|
||||||
|
```
|
||||||
|
|
||||||
|
### peerStore.protoBook.set
|
||||||
|
|
||||||
|
Set known `protocols` of a given peer.
|
||||||
|
|
||||||
|
`peerStore.protoBook.set(peerId, protocols)`
|
||||||
|
|
||||||
|
#### Parameters
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
|------|------|-------------|
|
||||||
|
| peerId | [`PeerId`][peer-id] | peerId to set |
|
||||||
|
| protocols | `Array<string>` | protocols to store |
|
||||||
|
|
||||||
|
#### Returns
|
||||||
|
|
||||||
|
| Type | Description |
|
||||||
|
|------|-------------|
|
||||||
|
| `ProtoBook` | Returns the Proto Book component |
|
||||||
|
|
||||||
|
#### Example
|
||||||
|
|
||||||
|
```js
|
||||||
|
peerStore.protoBook.set(peerId, protocols)
|
||||||
|
```
|
||||||
|
|
||||||
|
### peerStore.delete
|
||||||
|
|
||||||
|
Delete the provided peer from every book.
|
||||||
|
|
||||||
|
`peerStore.delete(peerId)`
|
||||||
|
|
||||||
|
#### Parameters
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
|------|------|-------------|
|
||||||
|
| peerId | [`PeerId`][peer-id] | peerId to remove |
|
||||||
|
|
||||||
|
#### Returns
|
||||||
|
|
||||||
|
| Type | Description |
|
||||||
|
|------|-------------|
|
||||||
|
| `boolean` | true if found and removed |
|
||||||
|
|
||||||
|
#### Example
|
||||||
|
|
||||||
|
```js
|
||||||
|
peerStore.delete(peerId)
|
||||||
|
// false
|
||||||
|
peerStore.addressBook.set(peerId, multiaddrs)
|
||||||
|
peerStore.protoBook.set(peerId, protocols)
|
||||||
|
peerStore.delete(peerId)
|
||||||
|
// true
|
||||||
|
peerStore.delete(peerId2)
|
||||||
|
// false
|
||||||
|
peerStore.addressBook.set(peerId2, multiaddrs)
|
||||||
|
peerStore.delete(peerId2)
|
||||||
|
// true
|
||||||
|
```
|
||||||
|
|
||||||
|
### peerStore.get
|
||||||
|
|
||||||
|
Get the stored information of a given peer.
|
||||||
|
|
||||||
|
`peerStore.get(peerId)`
|
||||||
|
|
||||||
|
#### Parameters
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
|------|------|-------------|
|
||||||
|
| peerId | [`PeerId`][peer-id] | peerId to get |
|
||||||
|
|
||||||
|
#### Returns
|
||||||
|
|
||||||
|
| Type | Description |
|
||||||
|
|------|-------------|
|
||||||
|
| [`PeerInfo`][peer-info] | Peer information of the provided peer |
|
||||||
|
|
||||||
|
TODO: change when `peer-info` is deprecated to new pointer
|
||||||
|
|
||||||
|
#### Example
|
||||||
|
|
||||||
|
```js
|
||||||
|
peerStore.get(peerId)
|
||||||
|
// false
|
||||||
|
peerStore.addressBook.set(peerId, multiaddrs)
|
||||||
|
peerStore.protoBook.set(peerId, protocols)
|
||||||
|
peerStore.get(peerId)
|
||||||
|
// {
|
||||||
|
// MultiaddrInfos: [...],
|
||||||
|
// protocols: [...]
|
||||||
|
// }
|
||||||
|
```
|
||||||
|
|
||||||
|
### peerStore.peers
|
||||||
|
|
||||||
|
Get all the stored information of every peer.
|
||||||
|
|
||||||
|
`peerStore.peers`
|
||||||
|
|
||||||
|
#### Returns
|
||||||
|
|
||||||
|
| Type | Description |
|
||||||
|
|------|-------------|
|
||||||
|
| `Map<string, PeerInfo>` | Peer information of every peer |
|
||||||
|
|
||||||
|
TODO: change when `peer-info` is deprecated to new pointer (breaking change)
|
||||||
|
|
||||||
|
#### Example
|
||||||
|
|
||||||
|
```js
|
||||||
|
for (let [peerIdString, peerInfo] of peerStore.peers.entries()) {
|
||||||
|
// peerInfo instance
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### pubsub.getSubscribers
|
### pubsub.getSubscribers
|
||||||
|
|
||||||
Gets a list of the peer-ids that are subscribed to one topic.
|
Gets a list of the peer-ids that are subscribed to one topic.
|
||||||
@ -523,7 +877,7 @@ Gets a list of the peer-ids that are subscribed to one topic.
|
|||||||
|
|
||||||
| Type | Description |
|
| Type | Description |
|
||||||
|------|-------------|
|
|------|-------------|
|
||||||
| `Array<String>` | peer-id subscribed to the topic |
|
| `Array<string>` | peer-id subscribed to the topic |
|
||||||
|
|
||||||
#### Example
|
#### Example
|
||||||
|
|
||||||
@ -541,7 +895,7 @@ Gets a list of topics the node is subscribed to.
|
|||||||
|
|
||||||
| Type | Description |
|
| Type | Description |
|
||||||
|------|-------------|
|
|------|-------------|
|
||||||
| `Array<String>` | topics the node is subscribed to |
|
| `Array<string>` | topics the node is subscribed to |
|
||||||
|
|
||||||
#### Example
|
#### Example
|
||||||
|
|
||||||
@ -588,7 +942,7 @@ Subscribes the given handler to a pubsub topic.
|
|||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
|------|------|-------------|
|
|------|------|-------------|
|
||||||
| topic | `string` | topic to subscribe |
|
| topic | `string` | topic to subscribe |
|
||||||
| handler | `function({ from: String, data: Buffer, seqno: Buffer, topicIDs: Array<String>, signature: Buffer, key: Buffer })` | handler for new data on topic |
|
| handler | `function({ from: string, data: Buffer, seqno: Buffer, topicIDs: Array<string>, signature: Buffer, key: Buffer })` | handler for new data on topic |
|
||||||
|
|
||||||
#### Returns
|
#### Returns
|
||||||
|
|
||||||
@ -618,7 +972,7 @@ Unsubscribes the given handler from a pubsub topic. If no handler is provided, a
|
|||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
|------|------|-------------|
|
|------|------|-------------|
|
||||||
| topic | `string` | topic to unsubscribe |
|
| topic | `string` | topic to unsubscribe |
|
||||||
| handler | `function(<Object>)` | handler subscribed |
|
| handler | `function(<object>)` | handler subscribed |
|
||||||
|
|
||||||
#### Returns
|
#### Returns
|
||||||
|
|
||||||
@ -787,9 +1141,9 @@ This event will be triggered anytime we are disconnected from another peer, rega
|
|||||||
- `dataReceived<string>`: The stringified value of total incoming data for this stat.
|
- `dataReceived<string>`: The stringified value of total incoming data for this stat.
|
||||||
- `dataSent<string>`: The stringified value of total outgoing data for this stat.
|
- `dataSent<string>`: The stringified value of total outgoing data for this stat.
|
||||||
- `movingAverages<object>`: The properties are dependent on the configuration of the moving averages interval. Defaults are listed here.
|
- `movingAverages<object>`: The properties are dependent on the configuration of the moving averages interval. Defaults are listed here.
|
||||||
- `['60000']<Number>`: The calculated moving average at a 1 minute interval.
|
- `['60000']<number>`: The calculated moving average at a 1 minute interval.
|
||||||
- `['300000']<Number>`: The calculated moving average at a 5 minute interval.
|
- `['300000']<number>`: The calculated moving average at a 5 minute interval.
|
||||||
- `['900000']<Number>`: The calculated moving average at a 15 minute interval.
|
- `['900000']<number>`: The calculated moving average at a 15 minute interval.
|
||||||
- `snapshot<object>`: A getter that returns a clone of the raw stats.
|
- `snapshot<object>`: A getter that returns a clone of the raw stats.
|
||||||
- `dataReceived<BigNumber>`: A [`BigNumber`](https://github.com/MikeMcl/bignumber.js/) of the amount of incoming data
|
- `dataReceived<BigNumber>`: A [`BigNumber`](https://github.com/MikeMcl/bignumber.js/) of the amount of incoming data
|
||||||
- `dataSent<BigNumber>`: A [`BigNumber`](https://github.com/MikeMcl/bignumber.js/) of the amount of outgoing data
|
- `dataSent<BigNumber>`: A [`BigNumber`](https://github.com/MikeMcl/bignumber.js/) of the amount of outgoing data
|
||||||
@ -798,6 +1152,7 @@ This event will be triggered anytime we are disconnected from another peer, rega
|
|||||||
- `['300000']<MovingAverage>`: The [MovingAverage](https://www.npmjs.com/package/moving-averages) at a 5 minute interval.
|
- `['300000']<MovingAverage>`: The [MovingAverage](https://www.npmjs.com/package/moving-averages) at a 5 minute interval.
|
||||||
- `['900000']<MovingAverage>`: The [MovingAverage](https://www.npmjs.com/package/moving-averages) at a 15 minute interval.
|
- `['900000']<MovingAverage>`: The [MovingAverage](https://www.npmjs.com/package/moving-averages) at a 15 minute interval.
|
||||||
|
|
||||||
|
[multiaddr-info]: https://github.com/libp2p/js-libp2p/tree/master/src/peer-store/address-book.js
|
||||||
[cid]: https://github.com/multiformats/js-cid
|
[cid]: https://github.com/multiformats/js-cid
|
||||||
[connection]: https://github.com/libp2p/js-interfaces/tree/master/src/connection
|
[connection]: https://github.com/libp2p/js-interfaces/tree/master/src/connection
|
||||||
[multiaddr]: https://github.com/multiformats/js-multiaddr
|
[multiaddr]: https://github.com/multiformats/js-multiaddr
|
||||||
|
@ -5,7 +5,6 @@ const errCode = require('err-code')
|
|||||||
const TimeoutController = require('timeout-abort-controller')
|
const TimeoutController = require('timeout-abort-controller')
|
||||||
const anySignal = require('any-signal')
|
const anySignal = require('any-signal')
|
||||||
const PeerId = require('peer-id')
|
const PeerId = require('peer-id')
|
||||||
const PeerInfo = require('peer-info')
|
|
||||||
const debug = require('debug')
|
const debug = require('debug')
|
||||||
const log = debug('libp2p:dialer')
|
const log = debug('libp2p:dialer')
|
||||||
log.error = debug('libp2p:dialer:error')
|
log.error = debug('libp2p:dialer:error')
|
||||||
@ -62,13 +61,13 @@ class Dialer {
|
|||||||
* The dial to the first address that is successfully able to upgrade a connection
|
* The dial to the first address that is successfully able to upgrade a connection
|
||||||
* will be used.
|
* will be used.
|
||||||
*
|
*
|
||||||
* @param {PeerInfo|Multiaddr} peer The peer to dial
|
* @param {PeerId|Multiaddr} peerId The peer to dial
|
||||||
* @param {object} [options]
|
* @param {object} [options]
|
||||||
* @param {AbortSignal} [options.signal] An AbortController signal
|
* @param {AbortSignal} [options.signal] An AbortController signal
|
||||||
* @returns {Promise<Connection>}
|
* @returns {Promise<Connection>}
|
||||||
*/
|
*/
|
||||||
async connectToPeer (peer, options = {}) {
|
async connectToPeer (peerId, options = {}) {
|
||||||
const dialTarget = this._createDialTarget(peer)
|
const dialTarget = this._createDialTarget(peerId)
|
||||||
if (dialTarget.addrs.length === 0) {
|
if (dialTarget.addrs.length === 0) {
|
||||||
throw errCode(new Error('The dial request has no addresses'), codes.ERR_NO_VALID_ADDRESSES)
|
throw errCode(new Error('The dial request has no addresses'), codes.ERR_NO_VALID_ADDRESSES)
|
||||||
}
|
}
|
||||||
@ -100,7 +99,7 @@ class Dialer {
|
|||||||
* Creates a DialTarget. The DialTarget is used to create and track
|
* Creates a DialTarget. The DialTarget is used to create and track
|
||||||
* the DialRequest to a given peer.
|
* the DialRequest to a given peer.
|
||||||
* @private
|
* @private
|
||||||
* @param {PeerInfo|Multiaddr} peer A PeerId or Multiaddr
|
* @param {PeerId|Multiaddr} peer A PeerId or Multiaddr
|
||||||
* @returns {DialTarget}
|
* @returns {DialTarget}
|
||||||
*/
|
*/
|
||||||
_createDialTarget (peer) {
|
_createDialTarget (peer) {
|
||||||
@ -111,7 +110,10 @@ class Dialer {
|
|||||||
addrs: [dialable]
|
addrs: [dialable]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const addrs = this.peerStore.multiaddrsForPeer(dialable)
|
|
||||||
|
dialable.multiaddrs && this.peerStore.addressBook.add(dialable.id, Array.from(dialable.multiaddrs))
|
||||||
|
const addrs = this.peerStore.addressBook.getMultiaddrsForPeer(dialable.id)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: dialable.id.toB58String(),
|
id: dialable.id.toB58String(),
|
||||||
addrs
|
addrs
|
||||||
@ -179,21 +181,27 @@ class Dialer {
|
|||||||
this.tokens.push(token)
|
this.tokens.push(token)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PeerInfo object
|
||||||
|
* @typedef {Object} peerInfo
|
||||||
|
* @property {Multiaddr} multiaddr peer multiaddr.
|
||||||
|
* @property {PeerId} id peer id.
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts the given `peer` into a `PeerInfo` or `Multiaddr`.
|
* Converts the given `peer` into a `PeerInfo` or `Multiaddr`.
|
||||||
* @static
|
* @static
|
||||||
* @param {PeerInfo|PeerId|Multiaddr|string} peer
|
* @param {PeerId|Multiaddr|string} peer
|
||||||
* @returns {PeerInfo|Multiaddr}
|
* @returns {peerInfo|Multiaddr}
|
||||||
*/
|
*/
|
||||||
static getDialable (peer) {
|
static getDialable (peer) {
|
||||||
if (PeerInfo.isPeerInfo(peer)) return peer
|
|
||||||
if (typeof peer === 'string') {
|
if (typeof peer === 'string') {
|
||||||
peer = multiaddr(peer)
|
peer = multiaddr(peer)
|
||||||
}
|
}
|
||||||
|
|
||||||
let addr
|
let addrs
|
||||||
if (multiaddr.isMultiaddr(peer)) {
|
if (multiaddr.isMultiaddr(peer)) {
|
||||||
addr = peer
|
addrs = new Set([peer]) // TODO: after peer-info removal, a Set should not be needed
|
||||||
try {
|
try {
|
||||||
peer = PeerId.createFromCID(peer.getPeerId())
|
peer = PeerId.createFromCID(peer.getPeerId())
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@ -202,10 +210,12 @@ class Dialer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (PeerId.isPeerId(peer)) {
|
if (PeerId.isPeerId(peer)) {
|
||||||
peer = new PeerInfo(peer)
|
peer = {
|
||||||
|
id: peer,
|
||||||
|
multiaddrs: addrs
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
addr && peer.multiaddrs.add(addr)
|
|
||||||
return peer
|
return peer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,12 @@ function getPeerInfo (peer, peerStore) {
|
|||||||
|
|
||||||
addr && peer.multiaddrs.add(addr)
|
addr && peer.multiaddrs.add(addr)
|
||||||
|
|
||||||
return peerStore ? peerStore.put(peer) : peer
|
if (peerStore) {
|
||||||
|
peerStore.addressBook.add(peer.id, peer.multiaddrs.toArray())
|
||||||
|
peerStore.protoBook.add(peer.id, Array.from(peer.protocols))
|
||||||
|
}
|
||||||
|
|
||||||
|
return peer
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -6,7 +6,6 @@ const lp = require('it-length-prefixed')
|
|||||||
const pipe = require('it-pipe')
|
const pipe = require('it-pipe')
|
||||||
const { collect, take, consume } = require('streaming-iterables')
|
const { collect, take, consume } = require('streaming-iterables')
|
||||||
|
|
||||||
const PeerInfo = require('peer-info')
|
|
||||||
const PeerId = require('peer-id')
|
const PeerId = require('peer-id')
|
||||||
const multiaddr = require('multiaddr')
|
const multiaddr = require('multiaddr')
|
||||||
const { toBuffer } = require('it-buffer')
|
const { toBuffer } = require('it-buffer')
|
||||||
@ -27,39 +26,6 @@ const errCode = require('err-code')
|
|||||||
const { codes } = require('../errors')
|
const { codes } = require('../errors')
|
||||||
|
|
||||||
class IdentifyService {
|
class IdentifyService {
|
||||||
/**
|
|
||||||
* Replaces the multiaddrs on the given `peerInfo`,
|
|
||||||
* with the provided `multiaddrs`
|
|
||||||
* @param {PeerInfo} peerInfo
|
|
||||||
* @param {Array<Multiaddr>|Array<Buffer>} multiaddrs
|
|
||||||
*/
|
|
||||||
static updatePeerAddresses (peerInfo, multiaddrs) {
|
|
||||||
if (multiaddrs && multiaddrs.length > 0) {
|
|
||||||
peerInfo.multiaddrs.clear()
|
|
||||||
multiaddrs.forEach(ma => {
|
|
||||||
try {
|
|
||||||
peerInfo.multiaddrs.add(ma)
|
|
||||||
} catch (err) {
|
|
||||||
log.error('could not add multiaddr', err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Replaces the protocols on the given `peerInfo`,
|
|
||||||
* with the provided `protocols`
|
|
||||||
* @static
|
|
||||||
* @param {PeerInfo} peerInfo
|
|
||||||
* @param {Array<string>} protocols
|
|
||||||
*/
|
|
||||||
static updatePeerProtocols (peerInfo, protocols) {
|
|
||||||
if (protocols && protocols.length > 0) {
|
|
||||||
peerInfo.protocols.clear()
|
|
||||||
protocols.forEach(proto => peerInfo.protocols.add(proto))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes the `addr` and converts it to a Multiaddr if possible
|
* Takes the `addr` and converts it to a Multiaddr if possible
|
||||||
* @param {Buffer|String} addr
|
* @param {Buffer|String} addr
|
||||||
@ -181,7 +147,7 @@ class IdentifyService {
|
|||||||
} = message
|
} = message
|
||||||
|
|
||||||
const id = await PeerId.createFromPubKey(publicKey)
|
const id = await PeerId.createFromPubKey(publicKey)
|
||||||
const peerInfo = new PeerInfo(id)
|
|
||||||
if (connection.remotePeer.toB58String() !== id.toB58String()) {
|
if (connection.remotePeer.toB58String() !== id.toB58String()) {
|
||||||
throw errCode(new Error('identified peer does not match the expected peer'), codes.ERR_INVALID_PEER)
|
throw errCode(new Error('identified peer does not match the expected peer'), codes.ERR_INVALID_PEER)
|
||||||
}
|
}
|
||||||
@ -189,11 +155,10 @@ class IdentifyService {
|
|||||||
// Get the observedAddr if there is one
|
// Get the observedAddr if there is one
|
||||||
observedAddr = IdentifyService.getCleanMultiaddr(observedAddr)
|
observedAddr = IdentifyService.getCleanMultiaddr(observedAddr)
|
||||||
|
|
||||||
// Copy the listenAddrs and protocols
|
// Update peers data in PeerStore
|
||||||
IdentifyService.updatePeerAddresses(peerInfo, listenAddrs)
|
this.registrar.peerStore.addressBook.set(id, listenAddrs.map((addr) => multiaddr(addr)))
|
||||||
IdentifyService.updatePeerProtocols(peerInfo, protocols)
|
this.registrar.peerStore.protoBook.set(id, protocols)
|
||||||
|
|
||||||
this.registrar.peerStore.replace(peerInfo)
|
|
||||||
// TODO: Track our observed address so that we can score it
|
// TODO: Track our observed address so that we can score it
|
||||||
log('received observed address of %s', observedAddr)
|
log('received observed address of %s', observedAddr)
|
||||||
}
|
}
|
||||||
@ -273,20 +238,16 @@ class IdentifyService {
|
|||||||
return log.error('received invalid message', err)
|
return log.error('received invalid message', err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the listen addresses
|
// Update peers data in PeerStore
|
||||||
const peerInfo = new PeerInfo(connection.remotePeer)
|
const id = connection.remotePeer
|
||||||
|
|
||||||
try {
|
try {
|
||||||
IdentifyService.updatePeerAddresses(peerInfo, message.listenAddrs)
|
this.registrar.peerStore.addressBook.set(id, message.listenAddrs.map((addr) => multiaddr(addr)))
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return log.error('received invalid listen addrs', err)
|
return log.error('received invalid listen addrs', err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the protocols
|
// Update the protocols
|
||||||
IdentifyService.updatePeerProtocols(peerInfo, message.protocols)
|
this.registrar.peerStore.protoBook.set(id, message.protocols)
|
||||||
|
|
||||||
// Update the peer in the PeerStore
|
|
||||||
this.registrar.peerStore.replace(peerInfo)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
15
src/index.js
15
src/index.js
@ -59,7 +59,7 @@ class Libp2p extends EventEmitter {
|
|||||||
localPeer: this.peerInfo.id,
|
localPeer: this.peerInfo.id,
|
||||||
metrics: this.metrics,
|
metrics: this.metrics,
|
||||||
onConnection: (connection) => {
|
onConnection: (connection) => {
|
||||||
const peerInfo = this.peerStore.put(new PeerInfo(connection.remotePeer), { silent: true })
|
const peerInfo = new PeerInfo(connection.remotePeer)
|
||||||
this.registrar.onConnect(peerInfo, connection)
|
this.registrar.onConnect(peerInfo, connection)
|
||||||
this.connectionManager.onConnect(connection)
|
this.connectionManager.onConnect(connection)
|
||||||
this.emit('peer:connect', peerInfo)
|
this.emit('peer:connect', peerInfo)
|
||||||
@ -289,7 +289,11 @@ class Libp2p extends EventEmitter {
|
|||||||
const dialable = Dialer.getDialable(peer)
|
const dialable = Dialer.getDialable(peer)
|
||||||
let connection
|
let connection
|
||||||
if (PeerInfo.isPeerInfo(dialable)) {
|
if (PeerInfo.isPeerInfo(dialable)) {
|
||||||
this.peerStore.put(dialable, { silent: true })
|
// TODO Inconsistency from: getDialable adds a set, while regular peerInfo uses a Multiaddr set
|
||||||
|
// This should be handled on `peer-info` removal
|
||||||
|
const multiaddrs = dialable.multiaddrs.toArray ? dialable.multiaddrs.toArray() : Array.from(dialable.multiaddrs)
|
||||||
|
this.peerStore.addressBook.add(dialable.id, multiaddrs)
|
||||||
|
|
||||||
connection = this.registrar.getConnection(dialable)
|
connection = this.registrar.getConnection(dialable)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -328,7 +332,7 @@ class Libp2p extends EventEmitter {
|
|||||||
async ping (peer) {
|
async ping (peer) {
|
||||||
const peerInfo = await getPeerInfo(peer, this.peerStore)
|
const peerInfo = await getPeerInfo(peer, this.peerStore)
|
||||||
|
|
||||||
return ping(this, peerInfo)
|
return ping(this, peerInfo.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -430,7 +434,10 @@ class Libp2p extends EventEmitter {
|
|||||||
log.error(new Error(codes.ERR_DISCOVERED_SELF))
|
log.error(new Error(codes.ERR_DISCOVERED_SELF))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.peerStore.put(peerInfo)
|
|
||||||
|
// TODO: once we deprecate peer-info, we should only set if we have data
|
||||||
|
this.peerStore.addressBook.add(peerInfo.id, peerInfo.multiaddrs.toArray())
|
||||||
|
this.peerStore.protoBook.set(peerInfo.id, Array.from(peerInfo.protocols))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,3 +1,89 @@
|
|||||||
# Peerstore
|
# PeerStore
|
||||||
|
|
||||||
WIP
|
Libp2p's PeerStore is responsible for keeping an updated register with the relevant information of the known peers. It should be the single source of truth for all peer data, where a subsystem can learn about peers' data and where someone can listen for updates. The PeerStore comprises four main components: `addressBook`, `keyBook`, `protocolBook` and `metadataBook`.
|
||||||
|
|
||||||
|
The PeerStore manages the high level operations on its inner books. Moreover, the PeerStore should be responsible for notifying interested parties of relevant events, through its Event Emitter.
|
||||||
|
|
||||||
|
## Data gathering
|
||||||
|
|
||||||
|
Several libp2p subsystems will perform operations, which will gather relevant information about peers. Some operations might not have this as an end goal, but can also gather important data.
|
||||||
|
|
||||||
|
In a libp2p node's life, it will discover peers through its discovery protocols. In a typical discovery protocol, addresses of the peer are discovered along with its peer id. Once this happens, the PeerStore should collect this information for future (or immediate) usage by other subsystems. When the information is stored, the PeerStore should inform interested parties of the peer discovered (`peer` event).
|
||||||
|
|
||||||
|
Taking into account a different scenario, a peer might perform/receive a dial request to/from a unkwown peer. In such a scenario, the PeerStore must store the peer's multiaddr once a connection is established.
|
||||||
|
|
||||||
|
After a connection is established with a peer, the Identify protocol will run automatically. A stream is created and peers exchange their information (Multiaddrs, running protocols and their public key). Once this information is obtained, it should be added to the PeerStore. In this specific case, as we are speaking to the source of truth, we should ensure the PeerStore is prioritizing these records. If the recorded `multiaddrs` or `protocols` have changed, interested parties must be informed via the `change:multiaddrs` or `change:protocols` events respectively.
|
||||||
|
|
||||||
|
In the background, the Identify Service is also waiting for protocol change notifications of peers via the IdentifyPush protocol. Peers may leverage the `identify-push` message to communicate protocol changes to all connected peers, so that their PeerStore can be updated with the updated protocols. As the `identify-push` also sends complete and updated information, the data in the PeerStore can be replaced.
|
||||||
|
|
||||||
|
(To consider: Should we not replace until we get to multiaddr confidence? we might loose true information as we will talk with older nodes on the network.)
|
||||||
|
|
||||||
|
While it is currently not supported in js-libp2p, future iterations may also support the [IdentifyDelta protocol](https://github.com/libp2p/specs/pull/176).
|
||||||
|
|
||||||
|
It is also possible to gather relevant information for peers from other protocols / subsystems. For instance, in `DHT` operations, nodes can exchange peer data as part of the `DHT` operation. In this case, we can learn additional information about a peer we already know. In this scenario the PeerStore should not replace the existing data it has, just add it.
|
||||||
|
|
||||||
|
## Data Consumption
|
||||||
|
|
||||||
|
When the PeerStore data is updated, this information might be important for different parties.
|
||||||
|
|
||||||
|
Every time a peer needs to dial another peer, it is essential that it knows the multiaddrs used by the peer, in order to perform a successful dial to it. The same is true for pinging a peer. While the `AddressBook` is going to keep its data updated, it will also emit `change:multiaddrs` events so that subsystems/users interested in knowing these changes can be notified instead of polling the `AddressBook`.
|
||||||
|
|
||||||
|
Everytime a peer starts/stops supporting a protocol, libp2p subsystems or users might need to act accordingly. `js-libp2p` registrar orchestrates known peers, established connections and protocol topologies. This way, once a protocol is supported for a peer, the topology of that protocol should be informed that a new peer may be used and the subsystem can decide if it should open a new stream with that peer or not. For these situations, the `ProtoBook` will emit `change:protocols` events whenever supported protocols of a peer change.
|
||||||
|
|
||||||
|
## PeerStore implementation
|
||||||
|
|
||||||
|
The PeerStore wraps four main components: `addressBook`, `keyBook`, `protocolBook` and `metadataBook`. Moreover, it provides a high level API for those components, as well as data events.
|
||||||
|
|
||||||
|
### Components
|
||||||
|
|
||||||
|
#### Address Book
|
||||||
|
|
||||||
|
The `addressBook` keeps the known multiaddrs of a peer. The multiaddrs of each peer may change over time and the Address Book must account for this.
|
||||||
|
|
||||||
|
`Map<string, multiaddrInfo>`
|
||||||
|
|
||||||
|
A `peerId.toString()` identifier mapping to a `multiaddrInfo` object, which should have the following structure:
|
||||||
|
|
||||||
|
```js
|
||||||
|
{
|
||||||
|
multiaddr: <Multiaddr>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Key Book
|
||||||
|
|
||||||
|
The `keyBook` tracks the keys of the peers.
|
||||||
|
|
||||||
|
**Not Yet Implemented**
|
||||||
|
|
||||||
|
#### Protocol Book
|
||||||
|
|
||||||
|
The `protoBook` holds the identifiers of the protocols supported by each peer. The protocols supported by each peer are dynamic and will change over time.
|
||||||
|
|
||||||
|
`Map<string, Set<string>>`
|
||||||
|
|
||||||
|
A `peerId.toString()` identifier mapping to a `Set` of protocol identifier strings.
|
||||||
|
|
||||||
|
#### Metadata Book
|
||||||
|
|
||||||
|
**Not Yet Implemented**
|
||||||
|
|
||||||
|
### API
|
||||||
|
|
||||||
|
For the complete API documentation, you should check the [API.md](../../doc/API.md).
|
||||||
|
|
||||||
|
Access to its underlying books:
|
||||||
|
|
||||||
|
- `peerStore.protoBook.*`
|
||||||
|
- `peerStore.addressBook.*`
|
||||||
|
|
||||||
|
### Events
|
||||||
|
|
||||||
|
- `peer` - emitted when a new peer is added.
|
||||||
|
- `change:multiaadrs` - emitted when a known peer has a different set of multiaddrs.
|
||||||
|
- `change:protocols` - emitted when a known peer supports a different set of protocols.
|
||||||
|
|
||||||
|
## Future Considerations
|
||||||
|
|
||||||
|
- If multiaddr TTLs are added, the PeerStore may schedule jobs to delete all addresses that exceed the TTL to prevent AddressBook bloating
|
||||||
|
- Further API methods will probably need to be added in the context of multiaddr validity and confidence.
|
||||||
|
214
src/peer-store/address-book.js
Normal file
214
src/peer-store/address-book.js
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const errcode = require('err-code')
|
||||||
|
const debug = require('debug')
|
||||||
|
const log = debug('libp2p:peer-store:address-book')
|
||||||
|
log.error = debug('libp2p:peer-store:address-book:error')
|
||||||
|
|
||||||
|
const multiaddr = require('multiaddr')
|
||||||
|
const PeerId = require('peer-id')
|
||||||
|
const PeerInfo = require('peer-info')
|
||||||
|
|
||||||
|
const Book = require('./book')
|
||||||
|
|
||||||
|
const {
|
||||||
|
ERR_INVALID_PARAMETERS
|
||||||
|
} = require('../errors')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The AddressBook is responsible for keeping the known multiaddrs
|
||||||
|
* of a peer.
|
||||||
|
*/
|
||||||
|
class AddressBook extends Book {
|
||||||
|
/**
|
||||||
|
* MultiaddrInfo object
|
||||||
|
* @typedef {Object} MultiaddrInfo
|
||||||
|
* @property {Multiaddr} multiaddr peer multiaddr.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
* @param {EventEmitter} peerStore
|
||||||
|
*/
|
||||||
|
constructor (peerStore) {
|
||||||
|
/**
|
||||||
|
* PeerStore Event emitter, used by the AddressBook to emit:
|
||||||
|
* "peer" - emitted when a peer is discovered by the node.
|
||||||
|
* "change:multiaddrs" - emitted when the known multiaddrs of a peer change.
|
||||||
|
*/
|
||||||
|
super(peerStore, 'change:multiaddrs', 'multiaddrs')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map known peers to their known multiaddrs.
|
||||||
|
* @type {Map<string, Array<MultiaddrInfo>>}
|
||||||
|
*/
|
||||||
|
this.data = new Map()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set known addresses of a provided peer.
|
||||||
|
* @override
|
||||||
|
* @param {PeerId} peerId
|
||||||
|
* @param {Array<Multiaddr>} addresses
|
||||||
|
* @returns {AddressBook}
|
||||||
|
*/
|
||||||
|
set (peerId, addresses) {
|
||||||
|
if (!PeerId.isPeerId(peerId)) {
|
||||||
|
log.error('peerId must be an instance of peer-id to store data')
|
||||||
|
throw errcode(new Error('peerId must be an instance of peer-id'), ERR_INVALID_PARAMETERS)
|
||||||
|
}
|
||||||
|
|
||||||
|
const multiaddrInfos = this._toMultiaddrInfos(addresses)
|
||||||
|
const id = peerId.toB58String()
|
||||||
|
const rec = this.data.get(id)
|
||||||
|
|
||||||
|
// Not replace multiaddrs
|
||||||
|
if (!multiaddrInfos.length) {
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
// Already knows the peer
|
||||||
|
if (rec && rec.length === multiaddrInfos.length) {
|
||||||
|
const intersection = rec.filter((mi) => multiaddrInfos.some((newMi) => mi.multiaddr.equals(newMi.multiaddr)))
|
||||||
|
|
||||||
|
// Are new addresses equal to the old ones?
|
||||||
|
// If yes, no changes needed!
|
||||||
|
if (intersection.length === rec.length) {
|
||||||
|
log(`the addresses provided to store are equal to the already stored for ${id}`)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.data.set(id, multiaddrInfos)
|
||||||
|
log(`stored provided multiaddrs for ${id}`)
|
||||||
|
|
||||||
|
// TODO: Remove peerInfo and its usage on peer-info deprecate
|
||||||
|
const peerInfo = new PeerInfo(peerId)
|
||||||
|
multiaddrInfos.forEach((mi) => peerInfo.multiaddrs.add(mi.multiaddr))
|
||||||
|
|
||||||
|
// Notify the existance of a new peer
|
||||||
|
if (!rec) {
|
||||||
|
// this._ps.emit('peer', peerId)
|
||||||
|
this._ps.emit('peer', peerInfo)
|
||||||
|
}
|
||||||
|
|
||||||
|
this._ps.emit('change:multiaddrs', {
|
||||||
|
peerId,
|
||||||
|
peerInfo,
|
||||||
|
multiaddrs: multiaddrInfos.map((mi) => mi.multiaddr)
|
||||||
|
})
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add known addresses of a provided peer.
|
||||||
|
* If the peer is not known, it is set with the given addresses.
|
||||||
|
* @override
|
||||||
|
* @param {PeerId} peerId
|
||||||
|
* @param {Array<Multiaddr>} addresses
|
||||||
|
* @returns {AddressBook}
|
||||||
|
*/
|
||||||
|
add (peerId, addresses) {
|
||||||
|
if (!PeerId.isPeerId(peerId)) {
|
||||||
|
log.error('peerId must be an instance of peer-id to store data')
|
||||||
|
throw errcode(new Error('peerId must be an instance of peer-id'), ERR_INVALID_PARAMETERS)
|
||||||
|
}
|
||||||
|
|
||||||
|
const multiaddrInfos = this._toMultiaddrInfos(addresses)
|
||||||
|
const id = peerId.toB58String()
|
||||||
|
const rec = this.data.get(id)
|
||||||
|
|
||||||
|
// Add recorded uniquely to the new array (Union)
|
||||||
|
rec && rec.forEach((mi) => {
|
||||||
|
if (!multiaddrInfos.find(r => r.multiaddr.equals(mi.multiaddr))) {
|
||||||
|
multiaddrInfos.push(mi)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// If the recorded length is equal to the new after the unique union
|
||||||
|
// The content is the same, no need to update.
|
||||||
|
if (rec && rec.length === multiaddrInfos.length) {
|
||||||
|
log(`the addresses provided to store are already stored for ${id}`)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
this.data.set(id, multiaddrInfos)
|
||||||
|
|
||||||
|
log(`added provided multiaddrs for ${id}`)
|
||||||
|
|
||||||
|
// TODO: Remove peerInfo and its usage on peer-info deprecate
|
||||||
|
const peerInfo = new PeerInfo(peerId)
|
||||||
|
multiaddrInfos.forEach((mi) => peerInfo.multiaddrs.add(mi.multiaddr))
|
||||||
|
|
||||||
|
this._ps.emit('change:multiaddrs', {
|
||||||
|
peerId,
|
||||||
|
peerInfo,
|
||||||
|
multiaddrs: multiaddrInfos.map((mi) => mi.multiaddr)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Notify the existance of a new peer
|
||||||
|
if (!rec) {
|
||||||
|
// this._ps.emit('peer', peerId)
|
||||||
|
this._ps.emit('peer', peerInfo)
|
||||||
|
}
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transforms received multiaddrs into MultiaddrInfo.
|
||||||
|
* @param {Array<Multiaddr>} addresses
|
||||||
|
* @returns {Array<MultiaddrInfo>}
|
||||||
|
*/
|
||||||
|
_toMultiaddrInfos (addresses) {
|
||||||
|
if (!addresses) {
|
||||||
|
log.error('addresses must be provided to store data')
|
||||||
|
throw errcode(new Error('addresses must be provided'), ERR_INVALID_PARAMETERS)
|
||||||
|
}
|
||||||
|
|
||||||
|
// create MultiaddrInfo for each address
|
||||||
|
const multiaddrInfos = []
|
||||||
|
addresses.forEach((addr) => {
|
||||||
|
if (!multiaddr.isMultiaddr(addr)) {
|
||||||
|
log.error(`multiaddr ${addr} must be an instance of multiaddr`)
|
||||||
|
throw errcode(new Error(`multiaddr ${addr} must be an instance of multiaddr`), ERR_INVALID_PARAMETERS)
|
||||||
|
}
|
||||||
|
|
||||||
|
multiaddrInfos.push({
|
||||||
|
multiaddr: addr
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
return multiaddrInfos
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the known multiaddrs for a given peer. All returned multiaddrs
|
||||||
|
* will include the encapsulated `PeerId` of the peer.
|
||||||
|
* @param {PeerId} peerId
|
||||||
|
* @returns {Array<Multiaddr>}
|
||||||
|
*/
|
||||||
|
getMultiaddrsForPeer (peerId) {
|
||||||
|
if (!PeerId.isPeerId(peerId)) {
|
||||||
|
throw errcode(new Error('peerId must be an instance of peer-id'), ERR_INVALID_PARAMETERS)
|
||||||
|
}
|
||||||
|
|
||||||
|
const record = this.data.get(peerId.toB58String())
|
||||||
|
|
||||||
|
if (!record) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
return record.map((multiaddrInfo) => {
|
||||||
|
const addr = multiaddrInfo.multiaddr
|
||||||
|
|
||||||
|
const idString = addr.getPeerId()
|
||||||
|
if (idString && idString === peerId.toB58String()) return addr
|
||||||
|
|
||||||
|
return addr.encapsulate(`/p2p/${peerId.toB58String()}`)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = AddressBook
|
87
src/peer-store/book.js
Normal file
87
src/peer-store/book.js
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const errcode = require('err-code')
|
||||||
|
const PeerId = require('peer-id')
|
||||||
|
const PeerInfo = require('peer-info')
|
||||||
|
|
||||||
|
const {
|
||||||
|
ERR_INVALID_PARAMETERS
|
||||||
|
} = require('../errors')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Book is the skeleton for the PeerStore books.
|
||||||
|
*/
|
||||||
|
class Book {
|
||||||
|
constructor (peerStore, eventName, eventProperty) {
|
||||||
|
this._ps = peerStore
|
||||||
|
this.eventName = eventName
|
||||||
|
this.eventProperty = eventProperty
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map known peers to their data.
|
||||||
|
* @type {Map<string, Array<Data>}
|
||||||
|
*/
|
||||||
|
this.data = new Map()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set known data of a provided peer.
|
||||||
|
* @param {PeerId} peerId
|
||||||
|
* @param {Array<Data>|Data} data
|
||||||
|
*/
|
||||||
|
set (peerId, data) {
|
||||||
|
throw errcode(new Error('set must be implemented by the subclass'), 'ERR_NOT_IMPLEMENTED')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add known data of a provided peer.
|
||||||
|
* @param {PeerId} peerId
|
||||||
|
* @param {Array<Data>|Data} data
|
||||||
|
*/
|
||||||
|
add (peerId, data) {
|
||||||
|
throw errcode(new Error('set must be implemented by the subclass'), 'ERR_NOT_IMPLEMENTED')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the known data of a provided peer.
|
||||||
|
* @param {PeerId} peerId
|
||||||
|
* @returns {Array<Data>}
|
||||||
|
*/
|
||||||
|
get (peerId) {
|
||||||
|
if (!PeerId.isPeerId(peerId)) {
|
||||||
|
throw errcode(new Error('peerId must be an instance of peer-id'), ERR_INVALID_PARAMETERS)
|
||||||
|
}
|
||||||
|
|
||||||
|
const rec = this.data.get(peerId.toB58String())
|
||||||
|
|
||||||
|
return rec ? [...rec] : undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes the provided peer from the book.
|
||||||
|
* @param {PeerId} peerId
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
delete (peerId) {
|
||||||
|
if (!PeerId.isPeerId(peerId)) {
|
||||||
|
throw errcode(new Error('peerId must be an instance of peer-id'), ERR_INVALID_PARAMETERS)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.data.delete(peerId.toB58String())) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Remove peerInfo and its usage on peer-info deprecate
|
||||||
|
const peerInfo = new PeerInfo(peerId)
|
||||||
|
|
||||||
|
this._ps.emit(this.eventName, {
|
||||||
|
peerId,
|
||||||
|
peerInfo,
|
||||||
|
[this.eventProperty]: []
|
||||||
|
})
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Book
|
@ -9,244 +9,212 @@ const { EventEmitter } = require('events')
|
|||||||
|
|
||||||
const PeerId = require('peer-id')
|
const PeerId = require('peer-id')
|
||||||
const PeerInfo = require('peer-info')
|
const PeerInfo = require('peer-info')
|
||||||
|
|
||||||
|
const AddressBook = require('./address-book')
|
||||||
|
const ProtoBook = require('./proto-book')
|
||||||
|
|
||||||
const {
|
const {
|
||||||
ERR_INVALID_PARAMETERS
|
ERR_INVALID_PARAMETERS
|
||||||
} = require('../errors')
|
} = require('../errors')
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Responsible for managing known peers, as well as their addresses and metadata
|
* Responsible for managing known peers, as well as their addresses, protocols and metadata.
|
||||||
* @fires PeerStore#peer Emitted when a peer is connected to this node
|
* @fires PeerStore#peer Emitted when a new peer is added.
|
||||||
* @fires PeerStore#change:protocols
|
* @fires PeerStore#change:protocols Emitted when a known peer supports a different set of protocols.
|
||||||
* @fires PeerStore#change:multiaddrs
|
* @fires PeerStore#change:multiaddrs Emitted when a known peer has a different set of multiaddrs.
|
||||||
*/
|
*/
|
||||||
class PeerStore extends EventEmitter {
|
class PeerStore extends EventEmitter {
|
||||||
|
/**
|
||||||
|
* PeerInfo object
|
||||||
|
* @typedef {Object} peerInfo
|
||||||
|
* @property {Array<multiaddrInfo>} multiaddrsInfos peer's information of the multiaddrs.
|
||||||
|
* @property {Array<string>} protocols peer's supported protocols.
|
||||||
|
*/
|
||||||
|
|
||||||
constructor () {
|
constructor () {
|
||||||
super()
|
super()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map of peers
|
* AddressBook containing a map of peerIdStr to multiaddrsInfo
|
||||||
*
|
|
||||||
* @type {Map<string, PeerInfo>}
|
|
||||||
*/
|
*/
|
||||||
this.peers = new Map()
|
this.addressBook = new AddressBook(this)
|
||||||
|
|
||||||
// TODO: Track ourselves. We should split `peerInfo` up into its pieces so we get better
|
/**
|
||||||
// control and observability. This will be the initial step for removing PeerInfo
|
* ProtoBook containing a map of peerIdStr to supported protocols.
|
||||||
// https://github.com/libp2p/go-libp2p-core/blob/master/peerstore/peerstore.go
|
*/
|
||||||
// this.addressBook = new Map()
|
this.protoBook = new ProtoBook(this)
|
||||||
// this.protoBook = new Map()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Temporary adapter for modules using PeerStore
|
||||||
|
// This should be removed under a breaking change
|
||||||
/**
|
/**
|
||||||
* Stores the peerInfo of a new peer.
|
* Stores the peerInfo of a new peer on each book.
|
||||||
* If already exist, its info is updated. If `silent` is set to
|
|
||||||
* true, no 'peer' event will be emitted. This can be useful if you
|
|
||||||
* are already in the process of dialing the peer. The peer is technically
|
|
||||||
* known, but may not have been added to the PeerStore yet.
|
|
||||||
* @param {PeerInfo} peerInfo
|
* @param {PeerInfo} peerInfo
|
||||||
* @param {object} [options]
|
* @param {object} [options]
|
||||||
* @param {boolean} [options.silent] (Default=false)
|
* @param {boolean} [options.replace = true]
|
||||||
* @return {PeerInfo}
|
* @return {PeerInfo}
|
||||||
*/
|
*/
|
||||||
put (peerInfo, options = { silent: false }) {
|
put (peerInfo, options) {
|
||||||
if (!PeerInfo.isPeerInfo(peerInfo)) {
|
const multiaddrs = peerInfo.multiaddrs.toArray()
|
||||||
throw errcode(new Error('peerInfo must be an instance of peer-info'), ERR_INVALID_PARAMETERS)
|
const protocols = Array.from(peerInfo.protocols || new Set())
|
||||||
|
|
||||||
|
this.addressBook.set(peerInfo.id, multiaddrs, options)
|
||||||
|
this.protoBook.set(peerInfo.id, protocols, options)
|
||||||
|
|
||||||
|
const peer = this.find(peerInfo.id)
|
||||||
|
const pInfo = new PeerInfo(peerInfo.id)
|
||||||
|
|
||||||
|
if (!peer) {
|
||||||
|
return pInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
let peer
|
peer.protocols.forEach((p) => pInfo.protocols.add(p))
|
||||||
// Already know the peer?
|
peer.multiaddrInfos.forEach((mi) => pInfo.multiaddrs.add(mi.multiaddr))
|
||||||
if (this.has(peerInfo.id)) {
|
|
||||||
peer = this.update(peerInfo)
|
|
||||||
} else {
|
|
||||||
peer = this.add(peerInfo)
|
|
||||||
|
|
||||||
// Emit the peer if silent = false
|
return pInfo
|
||||||
!options.silent && this.emit('peer', peerInfo)
|
|
||||||
}
|
|
||||||
return peer
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Temporary adapter for modules using PeerStore
|
||||||
|
// This should be removed under a breaking change
|
||||||
/**
|
/**
|
||||||
* Add a new peer to the store.
|
* Get the info of the given id.
|
||||||
* @param {PeerInfo} peerInfo
|
* @param {peerId} peerId
|
||||||
* @return {PeerInfo}
|
|
||||||
*/
|
|
||||||
add (peerInfo) {
|
|
||||||
if (!PeerInfo.isPeerInfo(peerInfo)) {
|
|
||||||
throw errcode(new Error('peerInfo must be an instance of peer-info'), ERR_INVALID_PARAMETERS)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create new instance and add values to it
|
|
||||||
const newPeerInfo = new PeerInfo(peerInfo.id)
|
|
||||||
|
|
||||||
peerInfo.multiaddrs.forEach((ma) => newPeerInfo.multiaddrs.add(ma))
|
|
||||||
peerInfo.protocols.forEach((p) => newPeerInfo.protocols.add(p))
|
|
||||||
|
|
||||||
const connectedMa = peerInfo.isConnected()
|
|
||||||
connectedMa && newPeerInfo.connect(connectedMa)
|
|
||||||
|
|
||||||
const peerProxy = new Proxy(newPeerInfo, {
|
|
||||||
set: (obj, prop, value) => {
|
|
||||||
if (prop === 'multiaddrs') {
|
|
||||||
this.emit('change:multiaddrs', {
|
|
||||||
peerInfo: obj,
|
|
||||||
multiaddrs: value.toArray()
|
|
||||||
})
|
|
||||||
} else if (prop === 'protocols') {
|
|
||||||
this.emit('change:protocols', {
|
|
||||||
peerInfo: obj,
|
|
||||||
protocols: Array.from(value)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return Reflect.set(...arguments)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
this.peers.set(peerInfo.id.toB58String(), peerProxy)
|
|
||||||
return peerProxy
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates an already known peer.
|
|
||||||
* @param {PeerInfo} peerInfo
|
|
||||||
* @return {PeerInfo}
|
|
||||||
*/
|
|
||||||
update (peerInfo) {
|
|
||||||
if (!PeerInfo.isPeerInfo(peerInfo)) {
|
|
||||||
throw errcode(new Error('peerInfo must be an instance of peer-info'), ERR_INVALID_PARAMETERS)
|
|
||||||
}
|
|
||||||
|
|
||||||
const id = peerInfo.id.toB58String()
|
|
||||||
const recorded = this.peers.get(id)
|
|
||||||
|
|
||||||
// pass active connection state
|
|
||||||
const ma = peerInfo.isConnected()
|
|
||||||
if (ma) {
|
|
||||||
recorded.connect(ma)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify new multiaddrs
|
|
||||||
// TODO: better track added and removed multiaddrs
|
|
||||||
const multiaddrsIntersection = [
|
|
||||||
...recorded.multiaddrs.toArray()
|
|
||||||
].filter((m) => peerInfo.multiaddrs.has(m))
|
|
||||||
|
|
||||||
if (multiaddrsIntersection.length !== peerInfo.multiaddrs.size ||
|
|
||||||
multiaddrsIntersection.length !== recorded.multiaddrs.size) {
|
|
||||||
for (const ma of peerInfo.multiaddrs.toArray()) {
|
|
||||||
recorded.multiaddrs.add(ma)
|
|
||||||
}
|
|
||||||
|
|
||||||
this.emit('change:multiaddrs', {
|
|
||||||
peerInfo: recorded,
|
|
||||||
multiaddrs: recorded.multiaddrs.toArray()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update protocols
|
|
||||||
// TODO: better track added and removed protocols
|
|
||||||
const protocolsIntersection = new Set(
|
|
||||||
[...recorded.protocols].filter((p) => peerInfo.protocols.has(p))
|
|
||||||
)
|
|
||||||
|
|
||||||
if (protocolsIntersection.size !== peerInfo.protocols.size ||
|
|
||||||
protocolsIntersection.size !== recorded.protocols.size) {
|
|
||||||
for (const protocol of peerInfo.protocols) {
|
|
||||||
recorded.protocols.add(protocol)
|
|
||||||
}
|
|
||||||
|
|
||||||
this.emit('change:protocols', {
|
|
||||||
peerInfo: recorded,
|
|
||||||
protocols: Array.from(recorded.protocols)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the public key if missing
|
|
||||||
if (!recorded.id.pubKey && peerInfo.id.pubKey) {
|
|
||||||
recorded.id.pubKey = peerInfo.id.pubKey
|
|
||||||
}
|
|
||||||
|
|
||||||
return recorded
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the info to the given id.
|
|
||||||
* @param {PeerId|string} peerId b58str id
|
|
||||||
* @returns {PeerInfo}
|
* @returns {PeerInfo}
|
||||||
*/
|
*/
|
||||||
get (peerId) {
|
get (peerId) {
|
||||||
// TODO: deprecate this and just accept `PeerId` instances
|
const peer = this.find(peerId)
|
||||||
if (PeerId.isPeerId(peerId)) {
|
|
||||||
peerId = peerId.toB58String()
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.peers.get(peerId)
|
const pInfo = new PeerInfo(peerId)
|
||||||
|
peer.protocols.forEach((p) => pInfo.protocols.add(p))
|
||||||
|
peer.multiaddrInfos.forEach((mi) => pInfo.multiaddrs.add(mi.multiaddr))
|
||||||
|
|
||||||
|
return pInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Temporary adapter for modules using PeerStore
|
||||||
|
// This should be removed under a breaking change
|
||||||
/**
|
/**
|
||||||
* Has the info to the given id.
|
* Has the info to the given id.
|
||||||
* @param {PeerId|string} peerId b58str id
|
* @param {PeerId} peerId
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
has (peerId) {
|
has (peerId) {
|
||||||
// TODO: deprecate this and just accept `PeerId` instances
|
return Boolean(this.find(peerId))
|
||||||
if (PeerId.isPeerId(peerId)) {
|
|
||||||
peerId = peerId.toB58String()
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.peers.has(peerId)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Temporary adapter for modules using PeerStore
|
||||||
|
// This should be removed under a breaking change
|
||||||
/**
|
/**
|
||||||
* Removes the Peer with the matching `peerId` from the PeerStore
|
* Removes the peer provided.
|
||||||
* @param {PeerId|string} peerId b58str id
|
* @param {PeerId} peerId
|
||||||
* @returns {boolean} true if found and removed
|
* @returns {boolean} true if found and removed
|
||||||
*/
|
*/
|
||||||
remove (peerId) {
|
remove (peerId) {
|
||||||
// TODO: deprecate this and just accept `PeerId` instances
|
return this.delete(peerId)
|
||||||
if (PeerId.isPeerId(peerId)) {
|
|
||||||
peerId = peerId.toB58String()
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.peers.delete(peerId)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Temporary adapter for modules using PeerStore
|
||||||
|
// This should be removed under a breaking change
|
||||||
/**
|
/**
|
||||||
* Completely replaces the existing peers metadata with the given `peerInfo`
|
* Completely replaces the existing peers metadata with the given `peerInfo`
|
||||||
* @param {PeerInfo} peerInfo
|
* @param {PeerInfo} peerInfo
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
replace (peerInfo) {
|
replace (peerInfo) {
|
||||||
if (!PeerInfo.isPeerInfo(peerInfo)) {
|
this.put(peerInfo)
|
||||||
throw errcode(new Error('peerInfo must be an instance of peer-info'), ERR_INVALID_PARAMETERS)
|
|
||||||
}
|
|
||||||
|
|
||||||
this.remove(peerInfo.id.toB58String())
|
|
||||||
this.add(peerInfo)
|
|
||||||
|
|
||||||
// This should be cleaned up in PeerStore v2
|
|
||||||
this.emit('change:multiaddrs', {
|
|
||||||
peerInfo,
|
|
||||||
multiaddrs: peerInfo.multiaddrs.toArray()
|
|
||||||
})
|
|
||||||
this.emit('change:protocols', {
|
|
||||||
peerInfo,
|
|
||||||
protocols: Array.from(peerInfo.protocols)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Temporary adapter for modules using PeerStore
|
||||||
|
// This should be removed under a breaking change
|
||||||
/**
|
/**
|
||||||
* Returns the known multiaddrs for a given `PeerInfo`. All returned multiaddrs
|
* Returns the known multiaddrs for a given `PeerInfo`. All returned multiaddrs
|
||||||
* will include the encapsulated `PeerId` of the peer.
|
* will include the encapsulated `PeerId` of the peer.
|
||||||
* @param {PeerInfo} peer
|
* @param {PeerInfo} peerInfo
|
||||||
* @returns {Array<Multiaddr>}
|
* @returns {Array<Multiaddr>}
|
||||||
*/
|
*/
|
||||||
multiaddrsForPeer (peer) {
|
multiaddrsForPeer (peerInfo) {
|
||||||
return this.put(peer, true).multiaddrs.toArray().map(addr => {
|
return this.addressBook.getMultiaddrsForPeer(peerInfo.id)
|
||||||
const idString = addr.getPeerId()
|
}
|
||||||
if (idString && idString === peer.id.toB58String()) return addr
|
|
||||||
return addr.encapsulate(`/p2p/${peer.id.toB58String()}`)
|
/**
|
||||||
})
|
* Get all the stored information of every peer.
|
||||||
|
* @returns {Map<string, peerInfo>}
|
||||||
|
*/
|
||||||
|
get peers () {
|
||||||
|
const peerInfos = new Map()
|
||||||
|
|
||||||
|
// AddressBook
|
||||||
|
for (const [idStr, multiaddrInfos] of this.addressBook.data.entries()) {
|
||||||
|
// TODO: Remove peerInfo and its usage on peer-info deprecate
|
||||||
|
const peerInfo = new PeerInfo(PeerId.createFromCID(idStr))
|
||||||
|
|
||||||
|
multiaddrInfos.forEach((mi) => peerInfo.multiaddrs.add((mi.multiaddr)))
|
||||||
|
|
||||||
|
const protocols = this.protoBook.data.get(idStr) || []
|
||||||
|
protocols.forEach((p) => peerInfo.protocols.add(p))
|
||||||
|
|
||||||
|
peerInfos.set(idStr, peerInfo)
|
||||||
|
// TODO
|
||||||
|
// peerInfos.set(idStr, {
|
||||||
|
// id: PeerId.createFromCID(idStr),
|
||||||
|
// multiaddrInfos,
|
||||||
|
// protocols: this.protoBook.data.get(idStr) || []
|
||||||
|
// })
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProtoBook
|
||||||
|
for (const [idStr, protocols] of this.protoBook.data.entries()) {
|
||||||
|
// TODO: Remove peerInfo and its usage on peer-info deprecate
|
||||||
|
const peerInfo = peerInfos.get(idStr)
|
||||||
|
|
||||||
|
if (!peerInfo) {
|
||||||
|
const peerInfo = new PeerInfo(PeerId.createFromCID(idStr))
|
||||||
|
|
||||||
|
protocols.forEach((p) => peerInfo.protocols.add(p))
|
||||||
|
peerInfos.set(idStr, peerInfo)
|
||||||
|
// peerInfos.set(idStr, {
|
||||||
|
// id: PeerId.createFromCID(idStr),
|
||||||
|
// multiaddrInfos: [],
|
||||||
|
// protocols: protocols
|
||||||
|
// })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return peerInfos
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete the information of the given peer in every book.
|
||||||
|
* @param {PeerId} peerId
|
||||||
|
* @returns {boolean} true if found and removed
|
||||||
|
*/
|
||||||
|
delete (peerId) {
|
||||||
|
const addressesDeleted = this.addressBook.delete(peerId)
|
||||||
|
const protocolsDeleted = this.protoBook.delete(peerId)
|
||||||
|
return addressesDeleted || protocolsDeleted
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the stored information of a given peer.
|
||||||
|
* @param {PeerId} peerId
|
||||||
|
* @returns {peerInfo}
|
||||||
|
*/
|
||||||
|
find (peerId) {
|
||||||
|
if (!PeerId.isPeerId(peerId)) {
|
||||||
|
throw errcode(new Error('peerId must be an instance of peer-id'), ERR_INVALID_PARAMETERS)
|
||||||
|
}
|
||||||
|
|
||||||
|
const multiaddrInfos = this.addressBook.get(peerId)
|
||||||
|
const protocols = this.protoBook.get(peerId)
|
||||||
|
|
||||||
|
if (!multiaddrInfos && !protocols) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
multiaddrInfos: multiaddrInfos || [],
|
||||||
|
protocols: protocols || []
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
137
src/peer-store/proto-book.js
Normal file
137
src/peer-store/proto-book.js
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const errcode = require('err-code')
|
||||||
|
const debug = require('debug')
|
||||||
|
const log = debug('libp2p:peer-store:proto-book')
|
||||||
|
log.error = debug('libp2p:peer-store:proto-book:error')
|
||||||
|
|
||||||
|
const PeerId = require('peer-id')
|
||||||
|
const PeerInfo = require('peer-info')
|
||||||
|
|
||||||
|
const Book = require('./book')
|
||||||
|
|
||||||
|
const {
|
||||||
|
ERR_INVALID_PARAMETERS
|
||||||
|
} = require('../errors')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ProtoBook is responsible for keeping the known supported
|
||||||
|
* protocols of a peer.
|
||||||
|
* @fires ProtoBook#change:protocols
|
||||||
|
*/
|
||||||
|
class ProtoBook extends Book {
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
* @param {EventEmitter} peerStore
|
||||||
|
*/
|
||||||
|
constructor (peerStore) {
|
||||||
|
/**
|
||||||
|
* PeerStore Event emitter, used by the ProtoBook to emit:
|
||||||
|
* "change:protocols" - emitted when the known protocols of a peer change.
|
||||||
|
*/
|
||||||
|
super(peerStore, 'change:protocols', 'protocols')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map known peers to their known protocols.
|
||||||
|
* @type {Map<string, Set<string>>}
|
||||||
|
*/
|
||||||
|
this.data = new Map()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set known protocols of a provided peer.
|
||||||
|
* If the peer was not known before, it will be added.
|
||||||
|
* @override
|
||||||
|
* @param {PeerId} peerId
|
||||||
|
* @param {Array<string>} protocols
|
||||||
|
* @returns {ProtoBook}
|
||||||
|
*/
|
||||||
|
set (peerId, protocols) {
|
||||||
|
if (!PeerId.isPeerId(peerId)) {
|
||||||
|
log.error('peerId must be an instance of peer-id to store data')
|
||||||
|
throw errcode(new Error('peerId must be an instance of peer-id'), ERR_INVALID_PARAMETERS)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!protocols) {
|
||||||
|
log.error('protocols must be provided to store data')
|
||||||
|
throw errcode(new Error('protocols must be provided'), ERR_INVALID_PARAMETERS)
|
||||||
|
}
|
||||||
|
|
||||||
|
const id = peerId.toB58String()
|
||||||
|
const recSet = this.data.get(id)
|
||||||
|
const newSet = new Set(protocols)
|
||||||
|
|
||||||
|
const isSetEqual = (a, b) => a.size === b.size && [...a].every(value => b.has(value))
|
||||||
|
|
||||||
|
// Already knows the peer and the recorded protocols are the same?
|
||||||
|
// If yes, no changes needed!
|
||||||
|
if (recSet && isSetEqual(recSet, newSet)) {
|
||||||
|
log(`the protocols provided to store are equal to the already stored for ${id}`)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
this.data.set(id, newSet)
|
||||||
|
log(`stored provided protocols for ${id}`)
|
||||||
|
|
||||||
|
// TODO: Remove peerInfo and its usage on peer-info deprecate
|
||||||
|
const peerInfo = new PeerInfo(peerId)
|
||||||
|
protocols.forEach((p) => peerInfo.protocols.add(p))
|
||||||
|
|
||||||
|
this._ps.emit('change:protocols', {
|
||||||
|
peerId,
|
||||||
|
peerInfo,
|
||||||
|
protocols
|
||||||
|
})
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds known protocols of a provided peer.
|
||||||
|
* If the peer was not known before, it will be added.
|
||||||
|
* @override
|
||||||
|
* @param {PeerId} peerId
|
||||||
|
* @param {Array<string>} protocols
|
||||||
|
* @returns {ProtoBook}
|
||||||
|
*/
|
||||||
|
add (peerId, protocols) {
|
||||||
|
if (!PeerId.isPeerId(peerId)) {
|
||||||
|
log.error('peerId must be an instance of peer-id to store data')
|
||||||
|
throw errcode(new Error('peerId must be an instance of peer-id'), ERR_INVALID_PARAMETERS)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!protocols) {
|
||||||
|
log.error('protocols must be provided to store data')
|
||||||
|
throw errcode(new Error('protocols must be provided'), ERR_INVALID_PARAMETERS)
|
||||||
|
}
|
||||||
|
|
||||||
|
const id = peerId.toB58String()
|
||||||
|
const recSet = this.data.get(id) || new Set()
|
||||||
|
const newSet = new Set([...recSet, ...protocols]) // Set Union
|
||||||
|
|
||||||
|
// Any new protocol added?
|
||||||
|
if (recSet.size === newSet.size) {
|
||||||
|
log(`the protocols provided to store are already stored for ${id}`)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
protocols = [...newSet]
|
||||||
|
|
||||||
|
this.data.set(id, newSet)
|
||||||
|
log(`added provided protocols for ${id}`)
|
||||||
|
|
||||||
|
// TODO: Remove peerInfo and its usage on peer-info deprecate
|
||||||
|
const peerInfo = new PeerInfo(peerId)
|
||||||
|
protocols.forEach((p) => peerInfo.protocols.add(p))
|
||||||
|
|
||||||
|
this._ps.emit('change:protocols', {
|
||||||
|
peerId,
|
||||||
|
peerInfo,
|
||||||
|
protocols
|
||||||
|
})
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = ProtoBook
|
@ -15,11 +15,11 @@ const { PROTOCOL, PING_LENGTH } = require('./constants')
|
|||||||
/**
|
/**
|
||||||
* Ping a given peer and wait for its response, getting the operation latency.
|
* Ping a given peer and wait for its response, getting the operation latency.
|
||||||
* @param {Libp2p} node
|
* @param {Libp2p} node
|
||||||
* @param {PeerInfo} peer
|
* @param {PeerId} peer
|
||||||
* @returns {Promise<Number>}
|
* @returns {Promise<Number>}
|
||||||
*/
|
*/
|
||||||
async function ping (node, peer) {
|
async function ping (node, peer) {
|
||||||
log('dialing %s to %s', PROTOCOL, peer.id.toB58String())
|
log('dialing %s to %s', PROTOCOL, peer.toB58String())
|
||||||
|
|
||||||
const { stream } = await node.dialProtocol(peer, PROTOCOL)
|
const { stream } = await node.dialProtocol(peer, PROTOCOL)
|
||||||
|
|
||||||
|
@ -10,7 +10,6 @@ const {
|
|||||||
} = require('./errors')
|
} = require('./errors')
|
||||||
const Topology = require('libp2p-interfaces/src/topology')
|
const Topology = require('libp2p-interfaces/src/topology')
|
||||||
const { Connection } = require('libp2p-interfaces/src/connection')
|
const { Connection } = require('libp2p-interfaces/src/connection')
|
||||||
const PeerInfo = require('peer-info')
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Responsible for notifying registered protocols of events in the network.
|
* Responsible for notifying registered protocols of events in the network.
|
||||||
@ -22,6 +21,7 @@ class Registrar {
|
|||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
constructor ({ peerStore }) {
|
constructor ({ peerStore }) {
|
||||||
|
// Used on topology to listen for protocol changes
|
||||||
this.peerStore = peerStore
|
this.peerStore = peerStore
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -74,9 +74,11 @@ class Registrar {
|
|||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
onConnect (peerInfo, conn) {
|
onConnect (peerInfo, conn) {
|
||||||
if (!PeerInfo.isPeerInfo(peerInfo)) {
|
// TODO: This is not a `peer-info` instance anymore, but an object with the data.
|
||||||
throw errcode(new Error('peerInfo must be an instance of peer-info'), ERR_INVALID_PARAMETERS)
|
// This can be modified to `peer-id` though, once `peer-info` is deprecated.
|
||||||
}
|
// if (!PeerInfo.isPeerInfo(peerInfo)) {
|
||||||
|
// throw errcode(new Error('peerInfo must be an instance of peer-info'), ERR_INVALID_PARAMETERS)
|
||||||
|
// }
|
||||||
|
|
||||||
if (!Connection.isConnection(conn)) {
|
if (!Connection.isConnection(conn)) {
|
||||||
throw errcode(new Error('conn must be an instance of interface-connection'), ERR_INVALID_PARAMETERS)
|
throw errcode(new Error('conn must be an instance of interface-connection'), ERR_INVALID_PARAMETERS)
|
||||||
@ -101,9 +103,11 @@ class Registrar {
|
|||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
onDisconnect (peerInfo, connection, error) {
|
onDisconnect (peerInfo, connection, error) {
|
||||||
if (!PeerInfo.isPeerInfo(peerInfo)) {
|
// TODO: This is not a `peer-info` instance anymore, but an object with the data.
|
||||||
throw errcode(new Error('peerInfo must be an instance of peer-info'), ERR_INVALID_PARAMETERS)
|
// This can be modified to `peer-id` though, once `peer-info` is deprecated.
|
||||||
}
|
// if (!PeerInfo.isPeerInfo(peerInfo)) {
|
||||||
|
// throw errcode(new Error('peerInfo must be an instance of peer-info'), ERR_INVALID_PARAMETERS)
|
||||||
|
// }
|
||||||
|
|
||||||
const id = peerInfo.id.toB58String()
|
const id = peerInfo.id.toB58String()
|
||||||
let storedConn = this.connections.get(id)
|
let storedConn = this.connections.get(id)
|
||||||
@ -126,9 +130,11 @@ class Registrar {
|
|||||||
* @returns {Connection}
|
* @returns {Connection}
|
||||||
*/
|
*/
|
||||||
getConnection (peerInfo) {
|
getConnection (peerInfo) {
|
||||||
if (!PeerInfo.isPeerInfo(peerInfo)) {
|
// TODO: This is not a `peer-info` instance anymore, but an object with the data.
|
||||||
throw errcode(new Error('peerInfo must be an instance of peer-info'), ERR_INVALID_PARAMETERS)
|
// This can be modified to `peer-id` though, once `peer-info` is deprecated.
|
||||||
}
|
// if (!PeerInfo.isPeerInfo(peerInfo)) {
|
||||||
|
// throw errcode(new Error('peerInfo must be an instance of peer-info'), ERR_INVALID_PARAMETERS)
|
||||||
|
// }
|
||||||
|
|
||||||
const connections = this.connections.get(peerInfo.id.toB58String())
|
const connections = this.connections.get(peerInfo.id.toB58String())
|
||||||
// Return the first, open connection
|
// Return the first, open connection
|
||||||
|
@ -317,7 +317,7 @@ class Upgrader {
|
|||||||
* Attempts to encrypt the incoming `connection` with the provided `cryptos`.
|
* Attempts to encrypt the incoming `connection` with the provided `cryptos`.
|
||||||
* @private
|
* @private
|
||||||
* @async
|
* @async
|
||||||
* @param {PeerId} localPeer The initiators PeerInfo
|
* @param {PeerId} localPeer The initiators PeerId
|
||||||
* @param {*} connection
|
* @param {*} connection
|
||||||
* @param {Map<string, Crypto>} cryptos
|
* @param {Map<string, Crypto>} cryptos
|
||||||
* @returns {CryptoResult} An encrypted connection, remote peer `PeerId` and the protocol of the `Crypto` used
|
* @returns {CryptoResult} An encrypted connection, remote peer `PeerId` and the protocol of the `Crypto` used
|
||||||
@ -346,7 +346,7 @@ class Upgrader {
|
|||||||
* The first `Crypto` module to succeed will be used
|
* The first `Crypto` module to succeed will be used
|
||||||
* @private
|
* @private
|
||||||
* @async
|
* @async
|
||||||
* @param {PeerId} localPeer The initiators PeerInfo
|
* @param {PeerId} localPeer The initiators PeerId
|
||||||
* @param {*} connection
|
* @param {*} connection
|
||||||
* @param {PeerId} remotePeerId
|
* @param {PeerId} remotePeerId
|
||||||
* @param {Map<string, Crypto>} cryptos
|
* @param {Map<string, Crypto>} cryptos
|
||||||
|
@ -43,7 +43,8 @@ describe('DHT subsystem operates correctly', () => {
|
|||||||
remoteLibp2p.start()
|
remoteLibp2p.start()
|
||||||
])
|
])
|
||||||
|
|
||||||
remAddr = libp2p.peerStore.multiaddrsForPeer(remotePeerInfo)[0]
|
libp2p.peerStore.addressBook.set(remotePeerInfo.id, [remoteListenAddr])
|
||||||
|
remAddr = libp2p.peerStore.addressBook.getMultiaddrsForPeer(remotePeerInfo.id)[0]
|
||||||
})
|
})
|
||||||
|
|
||||||
afterEach(() => Promise.all([
|
afterEach(() => Promise.all([
|
||||||
@ -67,7 +68,6 @@ describe('DHT subsystem operates correctly', () => {
|
|||||||
const value = Buffer.from('world')
|
const value = Buffer.from('world')
|
||||||
|
|
||||||
await libp2p.dialProtocol(remAddr, subsystemMulticodecs)
|
await libp2p.dialProtocol(remAddr, subsystemMulticodecs)
|
||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
pWaitFor(() => libp2p._dht.routingTable.size === 1),
|
pWaitFor(() => libp2p._dht.routingTable.size === 1),
|
||||||
pWaitFor(() => remoteLibp2p._dht.routingTable.size === 1)
|
pWaitFor(() => remoteLibp2p._dht.routingTable.size === 1)
|
||||||
@ -98,7 +98,8 @@ describe('DHT subsystem operates correctly', () => {
|
|||||||
await libp2p.start()
|
await libp2p.start()
|
||||||
await remoteLibp2p.start()
|
await remoteLibp2p.start()
|
||||||
|
|
||||||
remAddr = libp2p.peerStore.multiaddrsForPeer(remotePeerInfo)[0]
|
libp2p.peerStore.addressBook.set(remotePeerInfo.id, [remoteListenAddr])
|
||||||
|
remAddr = libp2p.peerStore.addressBook.getMultiaddrsForPeer(remotePeerInfo.id)[0]
|
||||||
})
|
})
|
||||||
|
|
||||||
afterEach(() => Promise.all([
|
afterEach(() => Promise.all([
|
||||||
|
@ -99,7 +99,10 @@ describe('Dialing (direct, TCP)', () => {
|
|||||||
const dialer = new Dialer({
|
const dialer = new Dialer({
|
||||||
transportManager: localTM,
|
transportManager: localTM,
|
||||||
peerStore: {
|
peerStore: {
|
||||||
multiaddrsForPeer: () => [remoteAddr]
|
addressBook: {
|
||||||
|
add: () => {},
|
||||||
|
getMultiaddrsForPeer: () => [remoteAddr]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const peerId = await PeerId.createFromJSON(Peers[0])
|
const peerId = await PeerId.createFromJSON(Peers[0])
|
||||||
@ -120,7 +123,7 @@ describe('Dialing (direct, TCP)', () => {
|
|||||||
const peerId = await PeerId.createFromJSON(Peers[0])
|
const peerId = await PeerId.createFromJSON(Peers[0])
|
||||||
const peerInfo = new PeerInfo(peerId)
|
const peerInfo = new PeerInfo(peerId)
|
||||||
peerInfo.multiaddrs.add(remoteAddr)
|
peerInfo.multiaddrs.add(remoteAddr)
|
||||||
peerStore.put(peerInfo)
|
peerStore.addressBook.set(peerInfo.id, peerInfo.multiaddrs.toArray())
|
||||||
|
|
||||||
const connection = await dialer.connectToPeer(peerInfo)
|
const connection = await dialer.connectToPeer(peerInfo)
|
||||||
expect(connection).to.exist()
|
expect(connection).to.exist()
|
||||||
@ -131,7 +134,10 @@ describe('Dialing (direct, TCP)', () => {
|
|||||||
const dialer = new Dialer({
|
const dialer = new Dialer({
|
||||||
transportManager: localTM,
|
transportManager: localTM,
|
||||||
peerStore: {
|
peerStore: {
|
||||||
multiaddrsForPeer: () => [unsupportedAddr]
|
addressBook: {
|
||||||
|
add: () => {},
|
||||||
|
getMultiaddrsForPeer: () => [unsupportedAddr]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const peerId = await PeerId.createFromJSON(Peers[0])
|
const peerId = await PeerId.createFromJSON(Peers[0])
|
||||||
@ -172,7 +178,10 @@ describe('Dialing (direct, TCP)', () => {
|
|||||||
transportManager: localTM,
|
transportManager: localTM,
|
||||||
concurrency: 2,
|
concurrency: 2,
|
||||||
peerStore: {
|
peerStore: {
|
||||||
multiaddrsForPeer: () => addrs
|
addressBook: {
|
||||||
|
add: () => {},
|
||||||
|
getMultiaddrsForPeer: () => addrs
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -87,7 +87,10 @@ describe('Dialing (direct, WebSockets)', () => {
|
|||||||
const dialer = new Dialer({
|
const dialer = new Dialer({
|
||||||
transportManager: localTM,
|
transportManager: localTM,
|
||||||
peerStore: {
|
peerStore: {
|
||||||
multiaddrsForPeer: () => [remoteAddr]
|
addressBook: {
|
||||||
|
add: () => {},
|
||||||
|
getMultiaddrsForPeer: () => [remoteAddr]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -100,7 +103,10 @@ describe('Dialing (direct, WebSockets)', () => {
|
|||||||
const dialer = new Dialer({
|
const dialer = new Dialer({
|
||||||
transportManager: localTM,
|
transportManager: localTM,
|
||||||
peerStore: {
|
peerStore: {
|
||||||
multiaddrsForPeer: () => [remoteAddr]
|
addressBook: {
|
||||||
|
add: () => {},
|
||||||
|
getMultiaddrsForPeer: () => [remoteAddr]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -121,7 +127,10 @@ describe('Dialing (direct, WebSockets)', () => {
|
|||||||
const dialer = new Dialer({
|
const dialer = new Dialer({
|
||||||
transportManager: localTM,
|
transportManager: localTM,
|
||||||
peerStore: {
|
peerStore: {
|
||||||
multiaddrsForPeer: () => [remoteAddr]
|
addressBook: {
|
||||||
|
add: () => {},
|
||||||
|
getMultiaddrsForPeer: () => [remoteAddr]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const peerId = await PeerId.createFromJSON(Peers[0])
|
const peerId = await PeerId.createFromJSON(Peers[0])
|
||||||
@ -135,7 +144,10 @@ describe('Dialing (direct, WebSockets)', () => {
|
|||||||
const dialer = new Dialer({
|
const dialer = new Dialer({
|
||||||
transportManager: localTM,
|
transportManager: localTM,
|
||||||
peerStore: {
|
peerStore: {
|
||||||
multiaddrsForPeer: () => [unsupportedAddr]
|
addressBook: {
|
||||||
|
set: () => {},
|
||||||
|
getMultiaddrsForPeer: () => [unsupportedAddr]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const peerId = await PeerId.createFromJSON(Peers[0])
|
const peerId = await PeerId.createFromJSON(Peers[0])
|
||||||
@ -150,7 +162,10 @@ describe('Dialing (direct, WebSockets)', () => {
|
|||||||
transportManager: localTM,
|
transportManager: localTM,
|
||||||
timeout: 50,
|
timeout: 50,
|
||||||
peerStore: {
|
peerStore: {
|
||||||
multiaddrsForPeer: () => [remoteAddr]
|
addressBook: {
|
||||||
|
add: () => {},
|
||||||
|
getMultiaddrsForPeer: () => [remoteAddr]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
sinon.stub(localTM, 'dial').callsFake(async (addr, options) => {
|
sinon.stub(localTM, 'dial').callsFake(async (addr, options) => {
|
||||||
@ -172,7 +187,10 @@ describe('Dialing (direct, WebSockets)', () => {
|
|||||||
transportManager: localTM,
|
transportManager: localTM,
|
||||||
concurrency: 2,
|
concurrency: 2,
|
||||||
peerStore: {
|
peerStore: {
|
||||||
multiaddrsForPeer: () => [remoteAddr, remoteAddr, remoteAddr]
|
addressBook: {
|
||||||
|
set: () => {},
|
||||||
|
getMultiaddrsForPeer: () => [remoteAddr, remoteAddr, remoteAddr]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -208,7 +226,10 @@ describe('Dialing (direct, WebSockets)', () => {
|
|||||||
transportManager: localTM,
|
transportManager: localTM,
|
||||||
concurrency: 2,
|
concurrency: 2,
|
||||||
peerStore: {
|
peerStore: {
|
||||||
multiaddrsForPeer: () => [remoteAddr, remoteAddr, remoteAddr]
|
addressBook: {
|
||||||
|
set: () => {},
|
||||||
|
getMultiaddrsForPeer: () => [remoteAddr, remoteAddr, remoteAddr]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -316,7 +337,7 @@ describe('Dialing (direct, WebSockets)', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
sinon.spy(libp2p.dialer, 'connectToPeer')
|
sinon.spy(libp2p.dialer, 'connectToPeer')
|
||||||
sinon.spy(libp2p.peerStore, 'put')
|
sinon.spy(libp2p.peerStore.addressBook, 'add')
|
||||||
|
|
||||||
const connection = await libp2p.dial(remoteAddr)
|
const connection = await libp2p.dial(remoteAddr)
|
||||||
expect(connection).to.exist()
|
expect(connection).to.exist()
|
||||||
@ -325,7 +346,7 @@ describe('Dialing (direct, WebSockets)', () => {
|
|||||||
expect(protocol).to.equal('/echo/1.0.0')
|
expect(protocol).to.equal('/echo/1.0.0')
|
||||||
await connection.close()
|
await connection.close()
|
||||||
expect(libp2p.dialer.connectToPeer.callCount).to.equal(1)
|
expect(libp2p.dialer.connectToPeer.callCount).to.equal(1)
|
||||||
expect(libp2p.peerStore.put.callCount).to.be.at.least(1)
|
expect(libp2p.peerStore.addressBook.add.callCount).to.be.at.least(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should run identify automatically after connecting', async () => {
|
it('should run identify automatically after connecting', async () => {
|
||||||
@ -339,19 +360,22 @@ describe('Dialing (direct, WebSockets)', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
sinon.spy(libp2p.identifyService, 'identify')
|
sinon.spy(libp2p.identifyService, 'identify')
|
||||||
sinon.spy(libp2p.peerStore, 'replace')
|
|
||||||
sinon.spy(libp2p.upgrader, 'onConnection')
|
sinon.spy(libp2p.upgrader, 'onConnection')
|
||||||
|
|
||||||
const connection = await libp2p.dial(remoteAddr)
|
const connection = await libp2p.dial(remoteAddr)
|
||||||
expect(connection).to.exist()
|
expect(connection).to.exist()
|
||||||
|
|
||||||
|
sinon.spy(libp2p.peerStore.addressBook, 'set')
|
||||||
|
sinon.spy(libp2p.peerStore.protoBook, 'set')
|
||||||
|
|
||||||
// Wait for onConnection to be called
|
// Wait for onConnection to be called
|
||||||
await pWaitFor(() => libp2p.upgrader.onConnection.callCount === 1)
|
await pWaitFor(() => libp2p.upgrader.onConnection.callCount === 1)
|
||||||
|
|
||||||
expect(libp2p.identifyService.identify.callCount).to.equal(1)
|
expect(libp2p.identifyService.identify.callCount).to.equal(1)
|
||||||
await libp2p.identifyService.identify.firstCall.returnValue
|
await libp2p.identifyService.identify.firstCall.returnValue
|
||||||
|
|
||||||
expect(libp2p.peerStore.replace.callCount).to.equal(1)
|
expect(libp2p.peerStore.addressBook.set.callCount).to.equal(1)
|
||||||
|
expect(libp2p.peerStore.protoBook.set.callCount).to.equal(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should be able to use hangup to close connections', async () => {
|
it('should be able to use hangup to close connections', async () => {
|
||||||
|
@ -11,6 +11,8 @@ const multiaddr = require('multiaddr')
|
|||||||
const { collect } = require('streaming-iterables')
|
const { collect } = require('streaming-iterables')
|
||||||
const pipe = require('it-pipe')
|
const pipe = require('it-pipe')
|
||||||
const AggregateError = require('aggregate-error')
|
const AggregateError = require('aggregate-error')
|
||||||
|
const PeerId = require('peer-id')
|
||||||
|
|
||||||
const { createPeerInfo } = require('../utils/creators/peer')
|
const { createPeerInfo } = require('../utils/creators/peer')
|
||||||
const baseOptions = require('../utils/base-options')
|
const baseOptions = require('../utils/base-options')
|
||||||
const Libp2p = require('../../src')
|
const Libp2p = require('../../src')
|
||||||
@ -51,8 +53,9 @@ describe('Dialing (via relay, TCP)', () => {
|
|||||||
return Promise.all([srcLibp2p, relayLibp2p, dstLibp2p].map(async libp2p => {
|
return Promise.all([srcLibp2p, relayLibp2p, dstLibp2p].map(async libp2p => {
|
||||||
await libp2p.stop()
|
await libp2p.stop()
|
||||||
// Clear the peer stores
|
// Clear the peer stores
|
||||||
for (const peerId of libp2p.peerStore.peers.keys()) {
|
for (const peerIdStr of libp2p.peerStore.peers.keys()) {
|
||||||
libp2p.peerStore.remove(peerId)
|
const peerId = PeerId.createFromCID(peerIdStr)
|
||||||
|
libp2p.peerStore.delete(peerId)
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
})
|
})
|
||||||
|
@ -48,7 +48,12 @@ describe('Identify', () => {
|
|||||||
protocols,
|
protocols,
|
||||||
registrar: {
|
registrar: {
|
||||||
peerStore: {
|
peerStore: {
|
||||||
replace: () => {}
|
addressBook: {
|
||||||
|
set: () => { }
|
||||||
|
},
|
||||||
|
protoBook: {
|
||||||
|
set: () => { }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -64,7 +69,8 @@ describe('Identify', () => {
|
|||||||
const [local, remote] = duplexPair()
|
const [local, remote] = duplexPair()
|
||||||
sinon.stub(localConnectionMock, 'newStream').returns({ stream: local, protocol: multicodecs.IDENTIFY })
|
sinon.stub(localConnectionMock, 'newStream').returns({ stream: local, protocol: multicodecs.IDENTIFY })
|
||||||
|
|
||||||
sinon.spy(localIdentify.registrar.peerStore, 'replace')
|
sinon.spy(localIdentify.registrar.peerStore.addressBook, 'set')
|
||||||
|
sinon.spy(localIdentify.registrar.peerStore.protoBook, 'set')
|
||||||
|
|
||||||
// Run identify
|
// Run identify
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
@ -76,9 +82,10 @@ describe('Identify', () => {
|
|||||||
})
|
})
|
||||||
])
|
])
|
||||||
|
|
||||||
expect(localIdentify.registrar.peerStore.replace.callCount).to.equal(1)
|
expect(localIdentify.registrar.peerStore.addressBook.set.callCount).to.equal(1)
|
||||||
|
expect(localIdentify.registrar.peerStore.protoBook.set.callCount).to.equal(1)
|
||||||
// Validate the remote peer gets updated in the peer store
|
// Validate the remote peer gets updated in the peer store
|
||||||
const call = localIdentify.registrar.peerStore.replace.firstCall
|
const call = localIdentify.registrar.peerStore.addressBook.set.firstCall
|
||||||
expect(call.args[0].id.bytes).to.equal(remotePeer.id.bytes)
|
expect(call.args[0].id.bytes).to.equal(remotePeer.id.bytes)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -88,7 +95,12 @@ describe('Identify', () => {
|
|||||||
protocols,
|
protocols,
|
||||||
registrar: {
|
registrar: {
|
||||||
peerStore: {
|
peerStore: {
|
||||||
replace: () => {}
|
addressBook: {
|
||||||
|
set: () => { }
|
||||||
|
},
|
||||||
|
protoBook: {
|
||||||
|
set: () => { }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -134,7 +146,12 @@ describe('Identify', () => {
|
|||||||
peerInfo: remotePeer,
|
peerInfo: remotePeer,
|
||||||
registrar: {
|
registrar: {
|
||||||
peerStore: {
|
peerStore: {
|
||||||
replace: () => {}
|
addressBook: {
|
||||||
|
set: () => {}
|
||||||
|
},
|
||||||
|
protoBook: {
|
||||||
|
set: () => { }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -152,9 +169,8 @@ describe('Identify', () => {
|
|||||||
const [local, remote] = duplexPair()
|
const [local, remote] = duplexPair()
|
||||||
sinon.stub(localConnectionMock, 'newStream').returns({ stream: local, protocol: multicodecs.IDENTIFY_PUSH })
|
sinon.stub(localConnectionMock, 'newStream').returns({ stream: local, protocol: multicodecs.IDENTIFY_PUSH })
|
||||||
|
|
||||||
sinon.spy(IdentifyService, 'updatePeerAddresses')
|
sinon.spy(remoteIdentify.registrar.peerStore.addressBook, 'set')
|
||||||
sinon.spy(IdentifyService, 'updatePeerProtocols')
|
sinon.spy(remoteIdentify.registrar.peerStore.protoBook, 'set')
|
||||||
sinon.spy(remoteIdentify.registrar.peerStore, 'replace')
|
|
||||||
|
|
||||||
// Run identify
|
// Run identify
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
@ -166,14 +182,14 @@ describe('Identify', () => {
|
|||||||
})
|
})
|
||||||
])
|
])
|
||||||
|
|
||||||
expect(IdentifyService.updatePeerAddresses.callCount).to.equal(1)
|
expect(remoteIdentify.registrar.peerStore.addressBook.set.callCount).to.equal(1)
|
||||||
expect(IdentifyService.updatePeerProtocols.callCount).to.equal(1)
|
expect(remoteIdentify.registrar.peerStore.protoBook.set.callCount).to.equal(1)
|
||||||
|
const [peerId, multiaddrs] = remoteIdentify.registrar.peerStore.addressBook.set.firstCall.args
|
||||||
expect(remoteIdentify.registrar.peerStore.replace.callCount).to.equal(1)
|
expect(peerId.bytes).to.eql(localPeer.id.bytes)
|
||||||
const [peerInfo] = remoteIdentify.registrar.peerStore.replace.firstCall.args
|
expect(multiaddrs).to.eql([listeningAddr])
|
||||||
expect(peerInfo.id.bytes).to.eql(localPeer.id.bytes)
|
const [peerId2, protocols] = remoteIdentify.registrar.peerStore.protoBook.set.firstCall.args
|
||||||
expect(peerInfo.multiaddrs.toArray()).to.eql([listeningAddr])
|
expect(peerId2.bytes).to.eql(localPeer.id.bytes)
|
||||||
expect(peerInfo.protocols).to.eql(localProtocols)
|
expect(protocols).to.eql(Array.from(localProtocols))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -204,13 +220,15 @@ describe('Identify', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
sinon.spy(libp2p.identifyService, 'identify')
|
sinon.spy(libp2p.identifyService, 'identify')
|
||||||
const peerStoreSpy = sinon.spy(libp2p.peerStore, 'replace')
|
const peerStoreSpySet = sinon.spy(libp2p.peerStore.addressBook, 'set')
|
||||||
|
const peerStoreSpyAdd = sinon.spy(libp2p.peerStore.addressBook, 'add')
|
||||||
|
|
||||||
const connection = await libp2p.dialer.connectToPeer(remoteAddr)
|
const connection = await libp2p.dialer.connectToPeer(remoteAddr)
|
||||||
expect(connection).to.exist()
|
expect(connection).to.exist()
|
||||||
|
|
||||||
// Wait for peer store to be updated
|
// Wait for peer store to be updated
|
||||||
await pWaitFor(() => peerStoreSpy.callCount === 1)
|
// Dialer._createDialTarget (add), Identify (replace)
|
||||||
|
await pWaitFor(() => peerStoreSpySet.callCount === 1 && peerStoreSpyAdd.callCount === 1)
|
||||||
expect(libp2p.identifyService.identify.callCount).to.equal(1)
|
expect(libp2p.identifyService.identify.callCount).to.equal(1)
|
||||||
|
|
||||||
// The connection should have no open streams
|
// The connection should have no open streams
|
||||||
@ -226,7 +244,6 @@ describe('Identify', () => {
|
|||||||
|
|
||||||
sinon.spy(libp2p.identifyService, 'identify')
|
sinon.spy(libp2p.identifyService, 'identify')
|
||||||
sinon.spy(libp2p.identifyService, 'push')
|
sinon.spy(libp2p.identifyService, 'push')
|
||||||
sinon.spy(libp2p.peerStore, 'update')
|
|
||||||
|
|
||||||
const connection = await libp2p.dialer.connectToPeer(remoteAddr)
|
const connection = await libp2p.dialer.connectToPeer(remoteAddr)
|
||||||
expect(connection).to.exist()
|
expect(connection).to.exist()
|
||||||
|
@ -36,7 +36,9 @@ describe('peer discovery', () => {
|
|||||||
...baseOptions,
|
...baseOptions,
|
||||||
peerInfo
|
peerInfo
|
||||||
})
|
})
|
||||||
libp2p.peerStore.add(remotePeerInfo)
|
libp2p.peerStore.addressBook.set(remotePeerInfo.id, remotePeerInfo.multiaddrs.toArray())
|
||||||
|
libp2p.peerStore.protoBook.set(remotePeerInfo.id, Array.from(remotePeerInfo.protocols))
|
||||||
|
|
||||||
const deferred = defer()
|
const deferred = defer()
|
||||||
sinon.stub(libp2p.dialer, 'connectToPeer').callsFake((remotePeerInfo) => {
|
sinon.stub(libp2p.dialer, 'connectToPeer').callsFake((remotePeerInfo) => {
|
||||||
expect(remotePeerInfo).to.equal(remotePeerInfo)
|
expect(remotePeerInfo).to.equal(remotePeerInfo)
|
||||||
@ -47,7 +49,9 @@ describe('peer discovery', () => {
|
|||||||
|
|
||||||
libp2p.start()
|
libp2p.start()
|
||||||
await deferred.promise
|
await deferred.promise
|
||||||
expect(spy.getCall(0).args).to.eql([remotePeerInfo])
|
|
||||||
|
expect(spy.calledOnce).to.eql(true)
|
||||||
|
expect(spy.getCall(0).args[0].id.toString()).to.eql(remotePeerInfo.id.toString())
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should ignore self on discovery', async () => {
|
it('should ignore self on discovery', async () => {
|
||||||
|
365
test/peer-store/address-book.spec.js
Normal file
365
test/peer-store/address-book.spec.js
Normal file
@ -0,0 +1,365 @@
|
|||||||
|
'use strict'
|
||||||
|
/* eslint-env mocha */
|
||||||
|
|
||||||
|
const chai = require('chai')
|
||||||
|
chai.use(require('dirty-chai'))
|
||||||
|
const { expect } = chai
|
||||||
|
|
||||||
|
const { EventEmitter } = require('events')
|
||||||
|
const pDefer = require('p-defer')
|
||||||
|
const multiaddr = require('multiaddr')
|
||||||
|
|
||||||
|
const AddressBook = require('../../src/peer-store/address-book')
|
||||||
|
|
||||||
|
const peerUtils = require('../utils/creators/peer')
|
||||||
|
const {
|
||||||
|
ERR_INVALID_PARAMETERS
|
||||||
|
} = require('../../src/errors')
|
||||||
|
|
||||||
|
const addr1 = multiaddr('/ip4/127.0.0.1/tcp/8000')
|
||||||
|
const addr2 = multiaddr('/ip4/127.0.0.1/tcp/8001')
|
||||||
|
const addr3 = multiaddr('/ip4/127.0.0.1/tcp/8002')
|
||||||
|
|
||||||
|
const arraysAreEqual = (a, b) => a.length === b.length && a.sort().every((item, index) => b[index] === item)
|
||||||
|
|
||||||
|
describe('addressBook', () => {
|
||||||
|
let peerId
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
[peerId] = await peerUtils.createPeerId()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('addressBook.set', () => {
|
||||||
|
let ee, ab
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
ee = new EventEmitter()
|
||||||
|
ab = new AddressBook(ee)
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
ee.removeAllListeners()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throwns invalid parameters error if invalid PeerId is provided', () => {
|
||||||
|
expect(() => {
|
||||||
|
ab.set('invalid peerId')
|
||||||
|
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throwns invalid parameters error if no addresses provided', () => {
|
||||||
|
expect(() => {
|
||||||
|
ab.set(peerId)
|
||||||
|
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throwns invalid parameters error if invalid multiaddrs are provided', () => {
|
||||||
|
expect(() => {
|
||||||
|
ab.set(peerId, 'invalid multiaddr')
|
||||||
|
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('replaces the stored content by default and emit change event', () => {
|
||||||
|
const defer = pDefer()
|
||||||
|
const supportedMultiaddrs = [addr1, addr2]
|
||||||
|
|
||||||
|
ee.once('change:multiaddrs', ({ peerId, multiaddrs }) => {
|
||||||
|
expect(peerId).to.exist()
|
||||||
|
expect(multiaddrs).to.eql(supportedMultiaddrs)
|
||||||
|
defer.resolve()
|
||||||
|
})
|
||||||
|
|
||||||
|
ab.set(peerId, supportedMultiaddrs)
|
||||||
|
const multiaddrInfos = ab.get(peerId)
|
||||||
|
const multiaddrs = multiaddrInfos.map((mi) => mi.multiaddr)
|
||||||
|
expect(multiaddrs).to.have.deep.members(supportedMultiaddrs)
|
||||||
|
|
||||||
|
return defer.promise
|
||||||
|
})
|
||||||
|
|
||||||
|
it('emits on set if not storing the exact same content', async () => {
|
||||||
|
const defer = pDefer()
|
||||||
|
|
||||||
|
const supportedMultiaddrsA = [addr1, addr2]
|
||||||
|
const supportedMultiaddrsB = [addr2]
|
||||||
|
|
||||||
|
let changeCounter = 0
|
||||||
|
ee.on('change:multiaddrs', () => {
|
||||||
|
changeCounter++
|
||||||
|
if (changeCounter > 1) {
|
||||||
|
defer.resolve()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// set 1
|
||||||
|
ab.set(peerId, supportedMultiaddrsA)
|
||||||
|
|
||||||
|
// set 2 (same content)
|
||||||
|
ab.set(peerId, supportedMultiaddrsB)
|
||||||
|
const multiaddrInfos = ab.get(peerId)
|
||||||
|
const multiaddrs = multiaddrInfos.map((mi) => mi.multiaddr)
|
||||||
|
expect(multiaddrs).to.have.deep.members(supportedMultiaddrsB)
|
||||||
|
|
||||||
|
await defer.promise
|
||||||
|
})
|
||||||
|
|
||||||
|
it('does not emit on set if it is storing the exact same content', async () => {
|
||||||
|
const defer = pDefer()
|
||||||
|
|
||||||
|
const supportedMultiaddrs = [addr1, addr2]
|
||||||
|
|
||||||
|
let changeCounter = 0
|
||||||
|
ee.on('change:multiaddrs', () => {
|
||||||
|
changeCounter++
|
||||||
|
if (changeCounter > 1) {
|
||||||
|
defer.reject()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// set 1
|
||||||
|
ab.set(peerId, supportedMultiaddrs)
|
||||||
|
|
||||||
|
// set 2 (same content)
|
||||||
|
ab.set(peerId, supportedMultiaddrs)
|
||||||
|
|
||||||
|
// Wait 50ms for incorrect second event
|
||||||
|
setTimeout(() => {
|
||||||
|
defer.resolve()
|
||||||
|
}, 50)
|
||||||
|
|
||||||
|
await defer.promise
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('addressBook.add', () => {
|
||||||
|
let ee, ab
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
ee = new EventEmitter()
|
||||||
|
ab = new AddressBook(ee)
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
ee.removeAllListeners()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throwns invalid parameters error if invalid PeerId is provided', () => {
|
||||||
|
expect(() => {
|
||||||
|
ab.add('invalid peerId')
|
||||||
|
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throwns invalid parameters error if no addresses provided', () => {
|
||||||
|
expect(() => {
|
||||||
|
ab.add(peerId)
|
||||||
|
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throwns invalid parameters error if invalid multiaddrs are provided', () => {
|
||||||
|
expect(() => {
|
||||||
|
ab.add(peerId, 'invalid multiaddr')
|
||||||
|
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('adds the new content and emits change event', () => {
|
||||||
|
const defer = pDefer()
|
||||||
|
|
||||||
|
const supportedMultiaddrsA = [addr1, addr2]
|
||||||
|
const supportedMultiaddrsB = [addr3]
|
||||||
|
const finalMultiaddrs = supportedMultiaddrsA.concat(supportedMultiaddrsB)
|
||||||
|
|
||||||
|
let changeTrigger = 2
|
||||||
|
ee.on('change:multiaddrs', ({ multiaddrs }) => {
|
||||||
|
changeTrigger--
|
||||||
|
if (changeTrigger === 0 && arraysAreEqual(multiaddrs, finalMultiaddrs)) {
|
||||||
|
defer.resolve()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Replace
|
||||||
|
ab.set(peerId, supportedMultiaddrsA)
|
||||||
|
let multiaddrInfos = ab.get(peerId)
|
||||||
|
let multiaddrs = multiaddrInfos.map((mi) => mi.multiaddr)
|
||||||
|
expect(multiaddrs).to.have.deep.members(supportedMultiaddrsA)
|
||||||
|
|
||||||
|
// Add
|
||||||
|
ab.add(peerId, supportedMultiaddrsB)
|
||||||
|
multiaddrInfos = ab.get(peerId)
|
||||||
|
multiaddrs = multiaddrInfos.map((mi) => mi.multiaddr)
|
||||||
|
expect(multiaddrs).to.have.deep.members(finalMultiaddrs)
|
||||||
|
|
||||||
|
return defer.promise
|
||||||
|
})
|
||||||
|
|
||||||
|
it('emits on add if the content to add not exists', async () => {
|
||||||
|
const defer = pDefer()
|
||||||
|
|
||||||
|
const supportedMultiaddrsA = [addr1]
|
||||||
|
const supportedMultiaddrsB = [addr2]
|
||||||
|
const finalMultiaddrs = supportedMultiaddrsA.concat(supportedMultiaddrsB)
|
||||||
|
|
||||||
|
let changeCounter = 0
|
||||||
|
ee.on('change:multiaddrs', () => {
|
||||||
|
changeCounter++
|
||||||
|
if (changeCounter > 1) {
|
||||||
|
defer.resolve()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// set 1
|
||||||
|
ab.set(peerId, supportedMultiaddrsA)
|
||||||
|
|
||||||
|
// set 2 (content already existing)
|
||||||
|
ab.add(peerId, supportedMultiaddrsB)
|
||||||
|
const multiaddrInfos = ab.get(peerId)
|
||||||
|
const multiaddrs = multiaddrInfos.map((mi) => mi.multiaddr)
|
||||||
|
expect(multiaddrs).to.have.deep.members(finalMultiaddrs)
|
||||||
|
|
||||||
|
await defer.promise
|
||||||
|
})
|
||||||
|
|
||||||
|
it('does not emit on add if the content to add already exists', async () => {
|
||||||
|
const defer = pDefer()
|
||||||
|
|
||||||
|
const supportedMultiaddrsA = [addr1, addr2]
|
||||||
|
const supportedMultiaddrsB = [addr2]
|
||||||
|
|
||||||
|
let changeCounter = 0
|
||||||
|
ee.on('change:multiaddrs', () => {
|
||||||
|
changeCounter++
|
||||||
|
if (changeCounter > 1) {
|
||||||
|
defer.reject()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// set 1
|
||||||
|
ab.set(peerId, supportedMultiaddrsA)
|
||||||
|
|
||||||
|
// set 2 (content already existing)
|
||||||
|
ab.add(peerId, supportedMultiaddrsB)
|
||||||
|
|
||||||
|
// Wait 50ms for incorrect second event
|
||||||
|
setTimeout(() => {
|
||||||
|
defer.resolve()
|
||||||
|
}, 50)
|
||||||
|
|
||||||
|
await defer.promise
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('addressBook.get', () => {
|
||||||
|
let ee, ab
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
ee = new EventEmitter()
|
||||||
|
ab = new AddressBook(ee)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throwns invalid parameters error if invalid PeerId is provided', () => {
|
||||||
|
expect(() => {
|
||||||
|
ab.get('invalid peerId')
|
||||||
|
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('returns undefined if no multiaddrs are known for the provided peer', () => {
|
||||||
|
const multiaddrInfos = ab.get(peerId)
|
||||||
|
|
||||||
|
expect(multiaddrInfos).to.not.exist()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('returns the multiaddrs stored', () => {
|
||||||
|
const supportedMultiaddrs = [addr1, addr2]
|
||||||
|
|
||||||
|
ab.set(peerId, supportedMultiaddrs)
|
||||||
|
|
||||||
|
const multiaddrInfos = ab.get(peerId)
|
||||||
|
const multiaddrs = multiaddrInfos.map((mi) => mi.multiaddr)
|
||||||
|
expect(multiaddrs).to.have.deep.members(supportedMultiaddrs)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('addressBook.getMultiaddrsForPeer', () => {
|
||||||
|
let ee, ab
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
ee = new EventEmitter()
|
||||||
|
ab = new AddressBook(ee)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throwns invalid parameters error if invalid PeerId is provided', () => {
|
||||||
|
expect(() => {
|
||||||
|
ab.getMultiaddrsForPeer('invalid peerId')
|
||||||
|
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('returns undefined if no multiaddrs are known for the provided peer', () => {
|
||||||
|
const multiaddrInfos = ab.getMultiaddrsForPeer(peerId)
|
||||||
|
|
||||||
|
expect(multiaddrInfos).to.not.exist()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('returns the multiaddrs stored', () => {
|
||||||
|
const supportedMultiaddrs = [addr1, addr2]
|
||||||
|
|
||||||
|
ab.set(peerId, supportedMultiaddrs)
|
||||||
|
|
||||||
|
const multiaddrs = ab.getMultiaddrsForPeer(peerId)
|
||||||
|
multiaddrs.forEach((m) => {
|
||||||
|
expect(m.getPeerId()).to.equal(peerId.toB58String())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('addressBook.delete', () => {
|
||||||
|
let ee, ab
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
ee = new EventEmitter()
|
||||||
|
ab = new AddressBook(ee)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throwns invalid parameters error if invalid PeerId is provided', () => {
|
||||||
|
expect(() => {
|
||||||
|
ab.delete('invalid peerId')
|
||||||
|
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('returns false if no records exist for the peer and no event is emitted', () => {
|
||||||
|
const defer = pDefer()
|
||||||
|
|
||||||
|
ee.on('change:multiaddrs', () => {
|
||||||
|
defer.reject()
|
||||||
|
})
|
||||||
|
|
||||||
|
const deleted = ab.delete(peerId)
|
||||||
|
|
||||||
|
expect(deleted).to.equal(false)
|
||||||
|
|
||||||
|
// Wait 50ms for incorrect invalid event
|
||||||
|
setTimeout(() => {
|
||||||
|
defer.resolve()
|
||||||
|
}, 50)
|
||||||
|
|
||||||
|
return defer.promise
|
||||||
|
})
|
||||||
|
|
||||||
|
it('returns true if the record exists and an event is emitted', () => {
|
||||||
|
const defer = pDefer()
|
||||||
|
|
||||||
|
const supportedMultiaddrs = [addr1, addr2]
|
||||||
|
ab.set(peerId, supportedMultiaddrs)
|
||||||
|
|
||||||
|
// Listen after set
|
||||||
|
ee.on('change:multiaddrs', ({ multiaddrs }) => {
|
||||||
|
expect(multiaddrs.length).to.eql(0)
|
||||||
|
defer.resolve()
|
||||||
|
})
|
||||||
|
|
||||||
|
const deleted = ab.delete(peerId)
|
||||||
|
|
||||||
|
expect(deleted).to.equal(true)
|
||||||
|
|
||||||
|
return defer.promise
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
@ -4,185 +4,147 @@
|
|||||||
const chai = require('chai')
|
const chai = require('chai')
|
||||||
chai.use(require('dirty-chai'))
|
chai.use(require('dirty-chai'))
|
||||||
const { expect } = chai
|
const { expect } = chai
|
||||||
const sinon = require('sinon')
|
|
||||||
|
|
||||||
const pDefer = require('p-defer')
|
|
||||||
|
|
||||||
const PeerStore = require('../../src/peer-store')
|
const PeerStore = require('../../src/peer-store')
|
||||||
const multiaddr = require('multiaddr')
|
const multiaddr = require('multiaddr')
|
||||||
|
|
||||||
const peerUtils = require('../utils/creators/peer')
|
const peerUtils = require('../utils/creators/peer')
|
||||||
|
|
||||||
const addr = multiaddr('/ip4/127.0.0.1/tcp/8000')
|
const addr1 = multiaddr('/ip4/127.0.0.1/tcp/8000')
|
||||||
|
const addr2 = multiaddr('/ip4/127.0.0.1/tcp/8001')
|
||||||
|
const addr3 = multiaddr('/ip4/127.0.0.1/tcp/8002')
|
||||||
|
const addr4 = multiaddr('/ip4/127.0.0.1/tcp/8003')
|
||||||
|
|
||||||
|
const proto1 = '/protocol1'
|
||||||
|
const proto2 = '/protocol2'
|
||||||
|
const proto3 = '/protocol3'
|
||||||
|
|
||||||
describe('peer-store', () => {
|
describe('peer-store', () => {
|
||||||
let peerStore
|
let peerIds
|
||||||
|
before(async () => {
|
||||||
beforeEach(() => {
|
peerIds = await peerUtils.createPeerId({
|
||||||
peerStore = new PeerStore()
|
number: 4
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should add a new peer and emit it when it does not exist', async () => {
|
describe('empty books', () => {
|
||||||
const defer = pDefer()
|
let peerStore
|
||||||
|
|
||||||
sinon.spy(peerStore, 'put')
|
beforeEach(() => {
|
||||||
sinon.spy(peerStore, 'add')
|
peerStore = new PeerStore()
|
||||||
sinon.spy(peerStore, 'update')
|
|
||||||
|
|
||||||
const [peerInfo] = await peerUtils.createPeerInfo()
|
|
||||||
|
|
||||||
peerStore.on('peer', (peer) => {
|
|
||||||
expect(peer).to.exist()
|
|
||||||
defer.resolve()
|
|
||||||
})
|
})
|
||||||
peerStore.put(peerInfo)
|
|
||||||
|
|
||||||
// Wait for peerStore to emit the peer
|
it('has an empty map of peers', () => {
|
||||||
await defer.promise
|
const peers = peerStore.peers
|
||||||
|
expect(peers.size).to.equal(0)
|
||||||
|
})
|
||||||
|
|
||||||
expect(peerStore.put.callCount).to.equal(1)
|
it('returns false on trying to delete a non existant peerId', () => {
|
||||||
expect(peerStore.add.callCount).to.equal(1)
|
const deleted = peerStore.delete(peerIds[0])
|
||||||
expect(peerStore.update.callCount).to.equal(0)
|
expect(deleted).to.equal(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('returns undefined on trying to find a non existant peerId', () => {
|
||||||
|
const peerInfo = peerStore.find(peerIds[0])
|
||||||
|
expect(peerInfo).to.not.exist()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should update peer when it is already in the store', async () => {
|
describe('previously populated books', () => {
|
||||||
const [peerInfo] = await peerUtils.createPeerInfo()
|
let peerStore
|
||||||
|
|
||||||
// Put the peer in the store
|
beforeEach(() => {
|
||||||
peerStore.put(peerInfo)
|
peerStore = new PeerStore()
|
||||||
|
|
||||||
sinon.spy(peerStore, 'add')
|
// Add peer0 with { addr1, addr2 } and { proto1 }
|
||||||
sinon.spy(peerStore, 'update')
|
peerStore.addressBook.set(peerIds[0], [addr1, addr2])
|
||||||
|
peerStore.protoBook.set(peerIds[0], [proto1])
|
||||||
|
|
||||||
// When updating, peer event must not be emitted
|
// Add peer1 with { addr3 } and { proto2, proto3 }
|
||||||
peerStore.on('peer', () => {
|
peerStore.addressBook.set(peerIds[1], [addr3])
|
||||||
throw new Error('should not emit twice')
|
peerStore.protoBook.set(peerIds[1], [proto2, proto3])
|
||||||
})
|
|
||||||
// If no multiaddrs change, the event should not be emitted
|
// Add peer2 with { addr4 }
|
||||||
peerStore.on('change:multiaddrs', () => {
|
peerStore.addressBook.set(peerIds[2], [addr4])
|
||||||
throw new Error('should not emit change:multiaddrs')
|
|
||||||
})
|
// Add peer3 with { addr4 } and { proto2 }
|
||||||
// If no protocols change, the event should not be emitted
|
peerStore.addressBook.set(peerIds[3], [addr4])
|
||||||
peerStore.on('change:protocols', () => {
|
peerStore.protoBook.set(peerIds[3], [proto2])
|
||||||
throw new Error('should not emit change:protocols')
|
|
||||||
})
|
})
|
||||||
|
|
||||||
peerStore.put(peerInfo)
|
it('has peers', () => {
|
||||||
|
const peers = peerStore.peers
|
||||||
|
|
||||||
expect(peerStore.add.callCount).to.equal(0)
|
expect(peers.size).to.equal(4)
|
||||||
expect(peerStore.update.callCount).to.equal(1)
|
expect(Array.from(peers.keys())).to.have.members([
|
||||||
})
|
peerIds[0].toB58String(),
|
||||||
|
peerIds[1].toB58String(),
|
||||||
|
peerIds[2].toB58String(),
|
||||||
|
peerIds[3].toB58String()
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
it('should emit the "change:multiaddrs" event when a peer has new multiaddrs', async () => {
|
it('returns true on deleting a stored peer', () => {
|
||||||
const defer = pDefer()
|
const deleted = peerStore.delete(peerIds[0])
|
||||||
const [createdPeerInfo] = await peerUtils.createPeerInfo()
|
expect(deleted).to.equal(true)
|
||||||
|
|
||||||
// Put the peer in the store
|
const peers = peerStore.peers
|
||||||
peerStore.put(createdPeerInfo)
|
expect(peers.size).to.equal(3)
|
||||||
|
expect(Array.from(peers.keys())).to.not.have.members([peerIds[0].toB58String()])
|
||||||
|
})
|
||||||
|
|
||||||
// When updating, "change:multiaddrs" event must not be emitted
|
it('returns true on deleting a stored peer which is only on one book', () => {
|
||||||
peerStore.on('change:multiaddrs', ({ peerInfo, multiaddrs }) => {
|
const deleted = peerStore.delete(peerIds[2])
|
||||||
|
expect(deleted).to.equal(true)
|
||||||
|
|
||||||
|
const peers = peerStore.peers
|
||||||
|
expect(peers.size).to.equal(3)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('finds the stored information of a peer in all its books', () => {
|
||||||
|
const peerInfo = peerStore.find(peerIds[0])
|
||||||
expect(peerInfo).to.exist()
|
expect(peerInfo).to.exist()
|
||||||
expect(peerInfo.id).to.eql(createdPeerInfo.id)
|
expect(peerInfo.protocols).to.have.members([proto1])
|
||||||
expect(peerInfo.protocols).to.eql(createdPeerInfo.protocols)
|
|
||||||
expect(multiaddrs).to.exist()
|
const peerMultiaddrs = peerInfo.multiaddrInfos.map((mi) => mi.multiaddr)
|
||||||
expect(multiaddrs).to.eql(createdPeerInfo.multiaddrs.toArray())
|
expect(peerMultiaddrs).to.have.members([addr1, addr2])
|
||||||
defer.resolve()
|
|
||||||
})
|
|
||||||
// If no protocols change, the event should not be emitted
|
|
||||||
peerStore.on('change:protocols', () => {
|
|
||||||
throw new Error('should not emit change:protocols')
|
|
||||||
})
|
})
|
||||||
|
|
||||||
createdPeerInfo.multiaddrs.add(addr)
|
it('finds the stored information of a peer that is not present in all its books', () => {
|
||||||
peerStore.put(createdPeerInfo)
|
const peerInfo = peerStore.find(peerIds[2])
|
||||||
|
|
||||||
// Wait for peerStore to emit the event
|
|
||||||
await defer.promise
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should emit the "change:protocols" event when a peer has new protocols', async () => {
|
|
||||||
const defer = pDefer()
|
|
||||||
const [createdPeerInfo] = await peerUtils.createPeerInfo()
|
|
||||||
|
|
||||||
// Put the peer in the store
|
|
||||||
peerStore.put(createdPeerInfo)
|
|
||||||
|
|
||||||
// If no multiaddrs change, the event should not be emitted
|
|
||||||
peerStore.on('change:multiaddrs', () => {
|
|
||||||
throw new Error('should not emit change:multiaddrs')
|
|
||||||
})
|
|
||||||
// When updating, "change:protocols" event must be emitted
|
|
||||||
peerStore.on('change:protocols', ({ peerInfo, protocols }) => {
|
|
||||||
expect(peerInfo).to.exist()
|
expect(peerInfo).to.exist()
|
||||||
expect(peerInfo.id).to.eql(createdPeerInfo.id)
|
expect(peerInfo.protocols.length).to.eql(0)
|
||||||
expect(peerInfo.multiaddrs).to.eql(createdPeerInfo.multiaddrs)
|
|
||||||
expect(protocols).to.exist()
|
const peerMultiaddrs = peerInfo.multiaddrInfos.map((mi) => mi.multiaddr)
|
||||||
expect(protocols).to.eql(Array.from(createdPeerInfo.protocols))
|
expect(peerMultiaddrs).to.have.members([addr4])
|
||||||
defer.resolve()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
createdPeerInfo.protocols.add('/new-protocol/1.0.0')
|
it('can find all the peers supporting a protocol', () => {
|
||||||
peerStore.put(createdPeerInfo)
|
const peerSupporting2 = []
|
||||||
|
|
||||||
// Wait for peerStore to emit the event
|
for (const [, peerInfo] of peerStore.peers.entries()) {
|
||||||
await defer.promise
|
if (peerInfo.protocols.has(proto2)) {
|
||||||
})
|
peerSupporting2.push(peerInfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
it('should be able to retrieve a peer from store through its b58str id', async () => {
|
expect(peerSupporting2.length).to.eql(2)
|
||||||
const [peerInfo] = await peerUtils.createPeerInfo()
|
expect(peerSupporting2[0].id.toB58String()).to.eql(peerIds[1].toB58String())
|
||||||
const id = peerInfo.id
|
expect(peerSupporting2[1].id.toB58String()).to.eql(peerIds[3].toB58String())
|
||||||
|
})
|
||||||
|
|
||||||
let retrievedPeer = peerStore.get(id)
|
it('can find all the peers listening on a given address', () => {
|
||||||
expect(retrievedPeer).to.not.exist()
|
const peerListenint4 = []
|
||||||
|
|
||||||
// Put the peer in the store
|
for (const [, peerInfo] of peerStore.peers.entries()) {
|
||||||
peerStore.put(peerInfo)
|
if (peerInfo.multiaddrs.has(addr4)) {
|
||||||
|
peerListenint4.push(peerInfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
retrievedPeer = peerStore.get(id)
|
expect(peerListenint4.length).to.eql(2)
|
||||||
expect(retrievedPeer).to.exist()
|
expect(peerListenint4[0].id.toB58String()).to.eql(peerIds[2].toB58String())
|
||||||
expect(retrievedPeer.id).to.equal(peerInfo.id)
|
expect(peerListenint4[1].id.toB58String()).to.eql(peerIds[3].toB58String())
|
||||||
expect(retrievedPeer.multiaddrs).to.eql(peerInfo.multiaddrs)
|
})
|
||||||
expect(retrievedPeer.protocols).to.eql(peerInfo.protocols)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should be able to remove a peer from store through its b58str id', async () => {
|
|
||||||
const [peerInfo] = await peerUtils.createPeerInfo()
|
|
||||||
const id = peerInfo.id
|
|
||||||
|
|
||||||
let removed = peerStore.remove(id)
|
|
||||||
expect(removed).to.eql(false)
|
|
||||||
|
|
||||||
// Put the peer in the store
|
|
||||||
peerStore.put(peerInfo)
|
|
||||||
expect(peerStore.peers.size).to.equal(1)
|
|
||||||
|
|
||||||
removed = peerStore.remove(id)
|
|
||||||
expect(removed).to.eql(true)
|
|
||||||
expect(peerStore.peers.size).to.equal(0)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should be able to get the multiaddrs for a peer', async () => {
|
|
||||||
const [peerInfo, relayInfo] = await peerUtils.createPeerInfo({ number: 2 })
|
|
||||||
const id = peerInfo.id
|
|
||||||
const ma1 = multiaddr('/ip4/127.0.0.1/tcp/4001')
|
|
||||||
const ma2 = multiaddr('/ip4/127.0.0.1/tcp/4002/ws')
|
|
||||||
const ma3 = multiaddr(`/ip4/127.0.0.1/tcp/4003/ws/p2p/${relayInfo.id.toB58String()}/p2p-circuit`)
|
|
||||||
|
|
||||||
peerInfo.multiaddrs.add(ma1)
|
|
||||||
peerInfo.multiaddrs.add(ma2)
|
|
||||||
peerInfo.multiaddrs.add(ma3)
|
|
||||||
|
|
||||||
const multiaddrs = peerStore.multiaddrsForPeer(peerInfo)
|
|
||||||
const expectedAddrs = [
|
|
||||||
ma1.encapsulate(`/p2p/${id.toB58String()}`),
|
|
||||||
ma2.encapsulate(`/p2p/${id.toB58String()}`),
|
|
||||||
ma3.encapsulate(`/p2p/${id.toB58String()}`)
|
|
||||||
]
|
|
||||||
|
|
||||||
expect(multiaddrs).to.eql(expectedAddrs)
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('peer-store on discovery', () => {
|
|
||||||
// TODO: implement with discovery
|
|
||||||
})
|
|
||||||
|
310
test/peer-store/proto-book.spec.js
Normal file
310
test/peer-store/proto-book.spec.js
Normal file
@ -0,0 +1,310 @@
|
|||||||
|
'use strict'
|
||||||
|
/* eslint-env mocha */
|
||||||
|
|
||||||
|
const chai = require('chai')
|
||||||
|
chai.use(require('dirty-chai'))
|
||||||
|
const { expect } = chai
|
||||||
|
|
||||||
|
const { EventEmitter } = require('events')
|
||||||
|
const pDefer = require('p-defer')
|
||||||
|
|
||||||
|
const ProtoBook = require('../../src/peer-store/proto-book')
|
||||||
|
|
||||||
|
const peerUtils = require('../utils/creators/peer')
|
||||||
|
const {
|
||||||
|
ERR_INVALID_PARAMETERS
|
||||||
|
} = require('../../src/errors')
|
||||||
|
|
||||||
|
const arraysAreEqual = (a, b) => a.length === b.length && a.sort().every((item, index) => b[index] === item)
|
||||||
|
|
||||||
|
describe('protoBook', () => {
|
||||||
|
let peerId
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
[peerId] = await peerUtils.createPeerId()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('protoBook.set', () => {
|
||||||
|
let ee, pb
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
ee = new EventEmitter()
|
||||||
|
pb = new ProtoBook(ee)
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
ee.removeAllListeners()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throwns invalid parameters error if invalid PeerId is provided', () => {
|
||||||
|
expect(() => {
|
||||||
|
pb.set('invalid peerId')
|
||||||
|
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throwns invalid parameters error if no protocols provided', () => {
|
||||||
|
expect(() => {
|
||||||
|
pb.set(peerId)
|
||||||
|
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('replaces the stored content by default and emit change event', () => {
|
||||||
|
const defer = pDefer()
|
||||||
|
const supportedProtocols = ['protocol1', 'protocol2']
|
||||||
|
|
||||||
|
ee.once('change:protocols', ({ peerId, protocols }) => {
|
||||||
|
expect(peerId).to.exist()
|
||||||
|
expect(protocols).to.have.deep.members(supportedProtocols)
|
||||||
|
defer.resolve()
|
||||||
|
})
|
||||||
|
|
||||||
|
pb.set(peerId, supportedProtocols)
|
||||||
|
const protocols = pb.get(peerId)
|
||||||
|
expect(protocols).to.have.deep.members(supportedProtocols)
|
||||||
|
|
||||||
|
return defer.promise
|
||||||
|
})
|
||||||
|
|
||||||
|
it('emits on set if not storing the exact same content', () => {
|
||||||
|
const defer = pDefer()
|
||||||
|
|
||||||
|
const supportedProtocolsA = ['protocol1', 'protocol2']
|
||||||
|
const supportedProtocolsB = ['protocol2']
|
||||||
|
|
||||||
|
let changeCounter = 0
|
||||||
|
ee.on('change:protocols', () => {
|
||||||
|
changeCounter++
|
||||||
|
if (changeCounter > 1) {
|
||||||
|
defer.resolve()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// set 1
|
||||||
|
pb.set(peerId, supportedProtocolsA)
|
||||||
|
|
||||||
|
// set 2 (same content)
|
||||||
|
pb.set(peerId, supportedProtocolsB)
|
||||||
|
const protocols = pb.get(peerId)
|
||||||
|
expect(protocols).to.have.deep.members(supportedProtocolsB)
|
||||||
|
|
||||||
|
return defer.promise
|
||||||
|
})
|
||||||
|
|
||||||
|
it('does not emit on set if it is storing the exact same content', () => {
|
||||||
|
const defer = pDefer()
|
||||||
|
|
||||||
|
const supportedProtocols = ['protocol1', 'protocol2']
|
||||||
|
|
||||||
|
let changeCounter = 0
|
||||||
|
ee.on('change:protocols', () => {
|
||||||
|
changeCounter++
|
||||||
|
if (changeCounter > 1) {
|
||||||
|
defer.reject()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// set 1
|
||||||
|
pb.set(peerId, supportedProtocols)
|
||||||
|
|
||||||
|
// set 2 (same content)
|
||||||
|
pb.set(peerId, supportedProtocols)
|
||||||
|
|
||||||
|
// Wait 50ms for incorrect second event
|
||||||
|
setTimeout(() => {
|
||||||
|
defer.resolve()
|
||||||
|
}, 50)
|
||||||
|
|
||||||
|
return defer.promise
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('protoBook.add', () => {
|
||||||
|
let ee, pb
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
ee = new EventEmitter()
|
||||||
|
pb = new ProtoBook(ee)
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
ee.removeAllListeners()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throwns invalid parameters error if invalid PeerId is provided', () => {
|
||||||
|
expect(() => {
|
||||||
|
pb.add('invalid peerId')
|
||||||
|
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throwns invalid parameters error if no protocols provided', () => {
|
||||||
|
expect(() => {
|
||||||
|
pb.add(peerId)
|
||||||
|
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('adds the new content and emits change event', () => {
|
||||||
|
const defer = pDefer()
|
||||||
|
|
||||||
|
const supportedProtocolsA = ['protocol1', 'protocol2']
|
||||||
|
const supportedProtocolsB = ['protocol3']
|
||||||
|
const finalProtocols = supportedProtocolsA.concat(supportedProtocolsB)
|
||||||
|
|
||||||
|
let changeTrigger = 2
|
||||||
|
ee.on('change:protocols', ({ protocols }) => {
|
||||||
|
changeTrigger--
|
||||||
|
if (changeTrigger === 0 && arraysAreEqual(protocols, finalProtocols)) {
|
||||||
|
defer.resolve()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Replace
|
||||||
|
pb.set(peerId, supportedProtocolsA)
|
||||||
|
let protocols = pb.get(peerId)
|
||||||
|
expect(protocols).to.have.deep.members(supportedProtocolsA)
|
||||||
|
|
||||||
|
// Add
|
||||||
|
pb.add(peerId, supportedProtocolsB)
|
||||||
|
protocols = pb.get(peerId)
|
||||||
|
expect(protocols).to.have.deep.members(finalProtocols)
|
||||||
|
|
||||||
|
return defer.promise
|
||||||
|
})
|
||||||
|
|
||||||
|
it('emits on add if the content to add not exists', () => {
|
||||||
|
const defer = pDefer()
|
||||||
|
|
||||||
|
const supportedProtocolsA = ['protocol1']
|
||||||
|
const supportedProtocolsB = ['protocol2']
|
||||||
|
const finalProtocols = supportedProtocolsA.concat(supportedProtocolsB)
|
||||||
|
|
||||||
|
let changeCounter = 0
|
||||||
|
ee.on('change:protocols', () => {
|
||||||
|
changeCounter++
|
||||||
|
if (changeCounter > 1) {
|
||||||
|
defer.resolve()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// set 1
|
||||||
|
pb.set(peerId, supportedProtocolsA)
|
||||||
|
|
||||||
|
// set 2 (content already existing)
|
||||||
|
pb.add(peerId, supportedProtocolsB)
|
||||||
|
const protocols = pb.get(peerId)
|
||||||
|
expect(protocols).to.have.deep.members(finalProtocols)
|
||||||
|
|
||||||
|
return defer.promise
|
||||||
|
})
|
||||||
|
|
||||||
|
it('does not emit on add if the content to add already exists', () => {
|
||||||
|
const defer = pDefer()
|
||||||
|
|
||||||
|
const supportedProtocolsA = ['protocol1', 'protocol2']
|
||||||
|
const supportedProtocolsB = ['protocol2']
|
||||||
|
|
||||||
|
let changeCounter = 0
|
||||||
|
ee.on('change:protocols', () => {
|
||||||
|
changeCounter++
|
||||||
|
if (changeCounter > 1) {
|
||||||
|
defer.reject()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// set 1
|
||||||
|
pb.set(peerId, supportedProtocolsA)
|
||||||
|
|
||||||
|
// set 2 (content already existing)
|
||||||
|
pb.add(peerId, supportedProtocolsB)
|
||||||
|
|
||||||
|
// Wait 50ms for incorrect second event
|
||||||
|
setTimeout(() => {
|
||||||
|
defer.resolve()
|
||||||
|
}, 50)
|
||||||
|
|
||||||
|
return defer.promise
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('protoBook.get', () => {
|
||||||
|
let ee, pb
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
ee = new EventEmitter()
|
||||||
|
pb = new ProtoBook(ee)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throwns invalid parameters error if invalid PeerId is provided', () => {
|
||||||
|
expect(() => {
|
||||||
|
pb.get('invalid peerId')
|
||||||
|
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('returns undefined if no protocols are known for the provided peer', () => {
|
||||||
|
const protocols = pb.get(peerId)
|
||||||
|
|
||||||
|
expect(protocols).to.not.exist()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('returns the protocols stored', () => {
|
||||||
|
const supportedProtocols = ['protocol1', 'protocol2']
|
||||||
|
|
||||||
|
pb.set(peerId, supportedProtocols)
|
||||||
|
|
||||||
|
const protocols = pb.get(peerId)
|
||||||
|
expect(protocols).to.have.deep.members(supportedProtocols)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('protoBook.delete', () => {
|
||||||
|
let ee, pb
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
ee = new EventEmitter()
|
||||||
|
pb = new ProtoBook(ee)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throwns invalid parameters error if invalid PeerId is provided', () => {
|
||||||
|
expect(() => {
|
||||||
|
pb.delete('invalid peerId')
|
||||||
|
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('returns false if no records exist for the peer and no event is emitted', () => {
|
||||||
|
const defer = pDefer()
|
||||||
|
|
||||||
|
ee.on('change:protocols', () => {
|
||||||
|
defer.reject()
|
||||||
|
})
|
||||||
|
|
||||||
|
const deleted = pb.delete(peerId)
|
||||||
|
|
||||||
|
expect(deleted).to.equal(false)
|
||||||
|
|
||||||
|
// Wait 50ms for incorrect invalid event
|
||||||
|
setTimeout(() => {
|
||||||
|
defer.resolve()
|
||||||
|
}, 50)
|
||||||
|
|
||||||
|
return defer.promise
|
||||||
|
})
|
||||||
|
|
||||||
|
it('returns true if the record exists and an event is emitted', () => {
|
||||||
|
const defer = pDefer()
|
||||||
|
|
||||||
|
const supportedProtocols = ['protocol1', 'protocol2']
|
||||||
|
pb.set(peerId, supportedProtocols)
|
||||||
|
|
||||||
|
// Listen after set
|
||||||
|
ee.on('change:protocols', ({ protocols }) => {
|
||||||
|
expect(protocols.length).to.eql(0)
|
||||||
|
defer.resolve()
|
||||||
|
})
|
||||||
|
|
||||||
|
const deleted = pb.delete(peerId)
|
||||||
|
|
||||||
|
expect(deleted).to.equal(true)
|
||||||
|
|
||||||
|
return defer.promise
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
@ -89,7 +89,9 @@ describe('registrar', () => {
|
|||||||
remotePeerInfo.protocols.add(multicodec)
|
remotePeerInfo.protocols.add(multicodec)
|
||||||
|
|
||||||
// Add connected peer to peerStore and registrar
|
// Add connected peer to peerStore and registrar
|
||||||
peerStore.put(remotePeerInfo)
|
peerStore.addressBook.set(remotePeerInfo.id, remotePeerInfo.multiaddrs.toArray())
|
||||||
|
peerStore.protoBook.set(remotePeerInfo.id, Array.from(remotePeerInfo.protocols))
|
||||||
|
|
||||||
registrar.onConnect(remotePeerInfo, conn)
|
registrar.onConnect(remotePeerInfo, conn)
|
||||||
expect(registrar.connections.size).to.eql(1)
|
expect(registrar.connections.size).to.eql(1)
|
||||||
|
|
||||||
@ -156,18 +158,23 @@ describe('registrar', () => {
|
|||||||
const peerInfo = await PeerInfo.create(conn.remotePeer)
|
const peerInfo = await PeerInfo.create(conn.remotePeer)
|
||||||
|
|
||||||
// Add connected peer to peerStore and registrar
|
// Add connected peer to peerStore and registrar
|
||||||
peerStore.put(peerInfo)
|
peerStore.addressBook.set(peerInfo.id, peerInfo.multiaddrs.toArray())
|
||||||
|
peerStore.protoBook.set(peerInfo.id, Array.from(peerInfo.protocols))
|
||||||
|
|
||||||
registrar.onConnect(peerInfo, conn)
|
registrar.onConnect(peerInfo, conn)
|
||||||
|
|
||||||
// Add protocol to peer and update it
|
// Add protocol to peer and update it
|
||||||
peerInfo.protocols.add(multicodec)
|
peerInfo.protocols.add(multicodec)
|
||||||
peerStore.put(peerInfo)
|
peerStore.addressBook.add(peerInfo.id, peerInfo.multiaddrs.toArray())
|
||||||
|
peerStore.protoBook.add(peerInfo.id, Array.from(peerInfo.protocols))
|
||||||
|
|
||||||
await onConnectDefer.promise
|
await onConnectDefer.promise
|
||||||
|
|
||||||
// Remove protocol to peer and update it
|
// Remove protocol to peer and update it
|
||||||
peerInfo.protocols.delete(multicodec)
|
peerInfo.protocols.delete(multicodec)
|
||||||
peerStore.replace(peerInfo)
|
|
||||||
|
peerStore.addressBook.set(peerInfo.id, peerInfo.multiaddrs.toArray())
|
||||||
|
peerStore.protoBook.set(peerInfo.id, Array.from(peerInfo.protocols))
|
||||||
|
|
||||||
await onDisconnectDefer.promise
|
await onDisconnectDefer.promise
|
||||||
})
|
})
|
||||||
@ -197,7 +204,8 @@ describe('registrar', () => {
|
|||||||
const id = peerInfo.id.toB58String()
|
const id = peerInfo.id.toB58String()
|
||||||
|
|
||||||
// Add connection to registrar
|
// Add connection to registrar
|
||||||
peerStore.put(peerInfo)
|
peerStore.addressBook.set(peerInfo.id, peerInfo.multiaddrs.toArray())
|
||||||
|
peerStore.protoBook.set(peerInfo.id, Array.from(peerInfo.protocols))
|
||||||
registrar.onConnect(peerInfo, conn1)
|
registrar.onConnect(peerInfo, conn1)
|
||||||
registrar.onConnect(peerInfo, conn2)
|
registrar.onConnect(peerInfo, conn2)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user