mirror of
https://github.com/fluencelabs/js-libp2p
synced 2025-07-13 15:51:34 +00:00
Compare commits
12 Commits
Author | SHA1 | Date | |
---|---|---|---|
48656712ea | |||
1a5ae74741 | |||
8691465a52 | |||
6350a187c7 | |||
8e3bb09279 | |||
73204958ee | |||
e9e4b731a5 | |||
d0a9fada32 | |||
824a444f56 | |||
fef54b2b2c | |||
8f29a667a1 | |||
093c0ea13f |
26
CHANGELOG.md
26
CHANGELOG.md
@ -1,3 +1,29 @@
|
||||
<a name="0.29.4"></a>
|
||||
## [0.29.4](https://github.com/libp2p/js-libp2p/compare/v0.29.3...v0.29.4) (2020-12-09)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* dial self ([#826](https://github.com/libp2p/js-libp2p/issues/826)) ([6350a18](https://github.com/libp2p/js-libp2p/commit/6350a18))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* custom and store self agent version + store self protocol version ([#800](https://github.com/libp2p/js-libp2p/issues/800)) ([d0a9fad](https://github.com/libp2p/js-libp2p/commit/d0a9fad))
|
||||
* support custom listener options ([#822](https://github.com/libp2p/js-libp2p/issues/822)) ([8691465](https://github.com/libp2p/js-libp2p/commit/8691465))
|
||||
|
||||
|
||||
|
||||
<a name="0.29.3"></a>
|
||||
## [0.29.3](https://github.com/libp2p/js-libp2p/compare/v0.29.2...v0.29.3) (2020-11-04)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* resolve multiaddrs before dial ([#782](https://github.com/libp2p/js-libp2p/issues/782)) ([093c0ea](https://github.com/libp2p/js-libp2p/commit/093c0ea))
|
||||
|
||||
|
||||
|
||||
<a name="0.29.2"></a>
|
||||
## [0.29.2](https://github.com/libp2p/js-libp2p/compare/v0.29.1...v0.29.2) (2020-10-23)
|
||||
|
||||
|
50
doc/API.md
50
doc/API.md
@ -92,6 +92,7 @@ Creates an instance of Libp2p.
|
||||
| options.modules | [`Array<object>`](./CONFIGURATION.md#modules) | libp2p [modules](./CONFIGURATION.md#modules) to use |
|
||||
| [options.addresses] | `{ listen: Array<string>, announce: Array<string>, noAnnounce: Array<string> }` | Addresses for transport listening and to advertise to the network |
|
||||
| [options.config] | `object` | libp2p modules configuration and core configuration |
|
||||
| [options.host] | `{ agentVersion: string }` | libp2p host options |
|
||||
| [options.connectionManager] | [`object`](./CONFIGURATION.md#configuring-connection-manager) | libp2p Connection Manager [configuration](./CONFIGURATION.md#configuring-connection-manager) |
|
||||
| [options.transportManager] | [`object`](./CONFIGURATION.md#configuring-transport-manager) | libp2p transport manager [configuration](./CONFIGURATION.md#configuring-transport-manager) |
|
||||
| [options.datastore] | `object` | must implement [ipfs/interface-datastore](https://github.com/ipfs/interface-datastore) (in memory datastore will be used if not provided) |
|
||||
@ -113,12 +114,25 @@ For Libp2p configurations and modules details read the [Configuration Document](
|
||||
|
||||
```js
|
||||
const Libp2p = require('libp2p')
|
||||
const TCP = require('libp2p-tcp')
|
||||
const MPLEX = require('libp2p-mplex')
|
||||
const { NOISE } = require('libp2p-noise')
|
||||
|
||||
// specify options
|
||||
const options = {}
|
||||
async function main () {
|
||||
// specify options
|
||||
const options = {
|
||||
modules: {
|
||||
transport: [TCP],
|
||||
streamMuxer: [MPLEX],
|
||||
connEncryption: [NOISE]
|
||||
}
|
||||
}
|
||||
|
||||
// create libp2p
|
||||
const libp2p = await Libp2p.create(options)
|
||||
// create libp2p
|
||||
const libp2p = await Libp2p.create(options)
|
||||
}
|
||||
|
||||
main()
|
||||
```
|
||||
|
||||
Note: The [`PeerId`][peer-id] option is not required and will be generated if it is not provided.
|
||||
@ -130,12 +144,30 @@ As an alternative, it is possible to create a Libp2p instance with the construct
|
||||
|
||||
```js
|
||||
const Libp2p = require('libp2p')
|
||||
const TCP = require('libp2p-tcp')
|
||||
const MPLEX = require('libp2p-mplex')
|
||||
const { NOISE } = require('libp2p-noise')
|
||||
const PeerId = require('peer-id')
|
||||
|
||||
// specify options
|
||||
const options = {}
|
||||
async function main () {
|
||||
const peerId = await PeerId.create();
|
||||
|
||||
// create libp2p
|
||||
const libp2p = new Libp2p(options)
|
||||
// specify options
|
||||
// peerId is required when Libp2p is instantiated via the constructor
|
||||
const options = {
|
||||
peerId,
|
||||
modules: {
|
||||
transport: [TCP],
|
||||
streamMuxer: [MPLEX],
|
||||
connEncryption: [NOISE]
|
||||
}
|
||||
}
|
||||
|
||||
// create libp2p
|
||||
const libp2p = new Libp2p(options)
|
||||
}
|
||||
|
||||
main()
|
||||
```
|
||||
|
||||
Required keys in the `options` object:
|
||||
@ -665,7 +697,7 @@ Queries the DHT for the n values stored for the given key (without sorting).
|
||||
// ...
|
||||
|
||||
const key = '/key'
|
||||
const { from, val } = await libp2p.contentRouting.get(key)
|
||||
const records = await libp2p.contentRouting.getMany(key, 2)
|
||||
```
|
||||
|
||||
### peerRouting.findPeer
|
||||
|
@ -465,6 +465,7 @@ Dialing in libp2p can be configured to limit the rate of dialing, and how long d
|
||||
| maxParallelDials | `number` | How many multiaddrs we can dial in parallel. |
|
||||
| maxDialsPerPeer | `number` | How many multiaddrs we can dial per peer, in parallel. |
|
||||
| dialTimeout | `number` | Second dial timeout per peer in ms. |
|
||||
| resolvers | `object` | Dial [Resolvers](https://github.com/multiformats/js-multiaddr/blob/master/src/resolvers/index.js) for resolving multiaddrs |
|
||||
|
||||
The below configuration example shows how the dialer should be configured, with the current defaults:
|
||||
|
||||
@ -474,6 +475,8 @@ const TCP = require('libp2p-tcp')
|
||||
const MPLEX = require('libp2p-mplex')
|
||||
const { NOISE } = require('libp2p-noise')
|
||||
|
||||
const { dnsaddrResolver } = require('multiaddr/src/resolvers')
|
||||
|
||||
const node = await Libp2p.create({
|
||||
modules: {
|
||||
transport: [TCP],
|
||||
@ -483,7 +486,10 @@ const node = await Libp2p.create({
|
||||
dialer: {
|
||||
maxParallelDials: 100,
|
||||
maxDialsPerPeer: 4,
|
||||
dialTimeout: 30e3
|
||||
dialTimeout: 30e3,
|
||||
resolvers: {
|
||||
dnsaddr: dnsaddrResolver
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@ -645,6 +651,35 @@ const node = await Libp2p.create({
|
||||
})
|
||||
```
|
||||
|
||||
During Libp2p startup, transport listeners will be created for the configured listen multiaddrs. Some transports support custom listener options and you can set them using the `listenerOptions` in the transport configuration. For example, [libp2p-webrtc-star](https://github.com/libp2p/js-libp2p-webrtc-star) transport listener supports the configuration of its underlying [simple-peer](https://github.com/feross/simple-peer) ice server(STUN/TURN) config as follows:
|
||||
|
||||
```js
|
||||
const transportKey = WebRTCStar.prototype[Symbol.toStringTag]
|
||||
const node = await Libp2p.create({
|
||||
modules: {
|
||||
transport: [WebRTCStar],
|
||||
streamMuxer: [MPLEX],
|
||||
connEncryption: [NOISE]
|
||||
},
|
||||
addresses: {
|
||||
listen: ['/dns4/your-wrtc-star.pub/tcp/443/wss/p2p-webrtc-star'] // your webrtc dns multiaddr
|
||||
},
|
||||
config: {
|
||||
transport: {
|
||||
[transportKey]: {
|
||||
listenerOptions: {
|
||||
config: {
|
||||
iceServers: [
|
||||
{"urls": ["turn:YOUR.TURN.SERVER:3478"], "username": "YOUR.USER", "credential": "YOUR.PASSWORD"},
|
||||
{"urls": ["stun:YOUR.STUN.SERVER:3478"], "username": "", "credential": ""}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## Configuration examples
|
||||
|
||||
As libp2p is designed to be a modular networking library, its usage will vary based on individual project needs. We've included links to some existing project configurations for your reference, in case you wish to replicate their configuration:
|
||||
|
@ -204,8 +204,8 @@ const Bootstrap = require('libp2p-bootstrap')
|
||||
|
||||
// Known peers addresses
|
||||
const bootstrapMultiaddrs = [
|
||||
'/dns4/ams-1.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd',
|
||||
'/dns4/lon-1.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3'
|
||||
'/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb',
|
||||
'/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN'
|
||||
]
|
||||
|
||||
const node = await Libp2p.create({
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
const PeerId = require('peer-id')
|
||||
const multiaddr = require('multiaddr')
|
||||
const Node = require('./libp2p-bundle')
|
||||
const createLibp2p = require('./libp2p-bundle')
|
||||
const { stdinToStream, streamToConsole } = require('./stream')
|
||||
|
||||
async function run() {
|
||||
@ -13,7 +13,7 @@ async function run() {
|
||||
])
|
||||
|
||||
// Create a new libp2p node on localhost with a randomly chosen port
|
||||
const nodeDialer = new Node({
|
||||
const nodeDialer = await createLibp2p({
|
||||
peerId: idDialer,
|
||||
addresses: {
|
||||
listen: ['/ip4/0.0.0.0/tcp/0']
|
||||
|
@ -7,21 +7,16 @@ const { NOISE } = require('libp2p-noise')
|
||||
const defaultsDeep = require('@nodeutils/defaults-deep')
|
||||
const libp2p = require('../../..')
|
||||
|
||||
class Node extends libp2p {
|
||||
constructor (_options) {
|
||||
const defaults = {
|
||||
modules: {
|
||||
transport: [
|
||||
TCP,
|
||||
WS
|
||||
],
|
||||
streamMuxer: [ mplex ],
|
||||
connEncryption: [ NOISE ]
|
||||
}
|
||||
}
|
||||
|
||||
super(defaultsDeep(_options, defaults))
|
||||
async function createLibp2p(_options) {
|
||||
const defaults = {
|
||||
modules: {
|
||||
transport: [TCP, WS],
|
||||
streamMuxer: [mplex],
|
||||
connEncryption: [NOISE],
|
||||
},
|
||||
}
|
||||
|
||||
return libp2p.create(defaultsDeep(_options, defaults))
|
||||
}
|
||||
|
||||
module.exports = Node
|
||||
module.exports = createLibp2p
|
||||
|
@ -2,13 +2,13 @@
|
||||
/* eslint-disable no-console */
|
||||
|
||||
const PeerId = require('peer-id')
|
||||
const Node = require('./libp2p-bundle.js')
|
||||
const createLibp2p = require('./libp2p-bundle.js')
|
||||
const { stdinToStream, streamToConsole } = require('./stream')
|
||||
|
||||
async function run() {
|
||||
// Create a new libp2p node with the given multi-address
|
||||
const idListener = await PeerId.createFromJSON(require('./peer-id-listener'))
|
||||
const nodeListener = new Node({
|
||||
const nodeListener = await createLibp2p({
|
||||
peerId: idListener,
|
||||
addresses: {
|
||||
listen: ['/ip4/0.0.0.0/tcp/10333']
|
||||
|
@ -10,14 +10,11 @@ const Bootstrap = require('libp2p-bootstrap')
|
||||
// Find this list at: https://github.com/ipfs/js-ipfs/blob/master/src/core/runtime/config-nodejs.json
|
||||
const bootstrapers = [
|
||||
'/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ',
|
||||
'/ip4/104.236.176.52/tcp/4001/p2p/QmSoLnSGccFuZQJzRadHn95W2CrSFmZuTdDWP8HXaHca9z',
|
||||
'/ip4/104.236.179.241/tcp/4001/p2p/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM',
|
||||
'/ip4/162.243.248.213/tcp/4001/p2p/QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm',
|
||||
'/ip4/128.199.219.111/tcp/4001/p2p/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu',
|
||||
'/ip4/104.236.76.40/tcp/4001/p2p/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64',
|
||||
'/ip4/178.62.158.247/tcp/4001/p2p/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd',
|
||||
'/ip4/178.62.61.185/tcp/4001/p2p/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3',
|
||||
'/ip4/104.236.151.122/tcp/4001/p2p/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx'
|
||||
'/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN',
|
||||
'/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb',
|
||||
'/dnsaddr/bootstrap.libp2p.io/p2p/QmZa1sAxajnQjVM8WjWXoMbmPd7NsWhfKsPkErzpm9wGkp',
|
||||
'/dnsaddr/bootstrap.libp2p.io/p2p/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa',
|
||||
'/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt'
|
||||
]
|
||||
|
||||
;(async () => {
|
||||
|
@ -40,14 +40,11 @@ In this configuration, we use a `bootstrappers` array listing peers to connect _
|
||||
```JavaScript
|
||||
const bootstrapers = [
|
||||
'/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ',
|
||||
'/ip4/104.236.176.52/tcp/4001/p2p/QmSoLnSGccFuZQJzRadHn95W2CrSFmZuTdDWP8HXaHca9z',
|
||||
'/ip4/104.236.179.241/tcp/4001/p2p/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM',
|
||||
'/ip4/162.243.248.213/tcp/4001/p2p/QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm',
|
||||
'/ip4/128.199.219.111/tcp/4001/p2p/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu',
|
||||
'/ip4/104.236.76.40/tcp/4001/p2p/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64',
|
||||
'/ip4/178.62.158.247/tcp/4001/p2p/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd',
|
||||
'/ip4/178.62.61.185/tcp/4001/p2p/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3',
|
||||
'/ip4/104.236.151.122/tcp/4001/p2p/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx'
|
||||
'/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN',
|
||||
'/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb',
|
||||
'/dnsaddr/bootstrap.libp2p.io/p2p/QmZa1sAxajnQjVM8WjWXoMbmPd7NsWhfKsPkErzpm9wGkp',
|
||||
'/dnsaddr/bootstrap.libp2p.io/p2p/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa',
|
||||
'/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt'
|
||||
]
|
||||
```
|
||||
|
||||
@ -93,23 +90,17 @@ From running [1.js](./1.js), you should see the following:
|
||||
```bash
|
||||
> node 1.js
|
||||
Discovered: QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ
|
||||
Discovered: QmSoLnSGccFuZQJzRadHn95W2CrSFmZuTdDWP8HXaHca9z
|
||||
Discovered: QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM
|
||||
Discovered: QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm
|
||||
Discovered: QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu
|
||||
Discovered: QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64
|
||||
Discovered: QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd
|
||||
Discovered: QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3
|
||||
Discovered: QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx
|
||||
Discovered: QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN
|
||||
Discovered: QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb
|
||||
Discovered: QmZa1sAxajnQjVM8WjWXoMbmPd7NsWhfKsPkErzpm9wGkp
|
||||
Discovered: QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa
|
||||
Discovered: QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt
|
||||
Connection established to: QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ
|
||||
Connection established to: QmSoLnSGccFuZQJzRadHn95W2CrSFmZuTdDWP8HXaHca9z
|
||||
Connection established to: QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM
|
||||
Connection established to: QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm
|
||||
Connection established to: QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu
|
||||
Connection established to: QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64
|
||||
Connection established to: QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd
|
||||
Connection established to: QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3
|
||||
Connection established to: QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx
|
||||
Connection established to: QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN
|
||||
Connection established to: QmZa1sAxajnQjVM8WjWXoMbmPd7NsWhfKsPkErzpm9wGkp
|
||||
Connection established to: QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa
|
||||
Connection established to: QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt
|
||||
Connection established to: QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb
|
||||
```
|
||||
|
||||
## 2. MulticastDNS to find other peers in the network
|
||||
|
@ -5,9 +5,8 @@
|
||||
* Dialer Node
|
||||
*/
|
||||
|
||||
const multiaddr = require('multiaddr')
|
||||
const PeerId = require('peer-id')
|
||||
const Node = require('./libp2p-bundle')
|
||||
const createLibp2p = require('./libp2p-bundle')
|
||||
const pipe = require('it-pipe')
|
||||
|
||||
async function run() {
|
||||
@ -17,7 +16,7 @@ async function run() {
|
||||
])
|
||||
|
||||
// Dialer
|
||||
const dialerNode = new Node({
|
||||
const dialerNode = await createLibp2p({
|
||||
addresses: {
|
||||
listen: ['/ip4/0.0.0.0/tcp/0']
|
||||
},
|
||||
|
@ -8,21 +8,16 @@ const { NOISE } = require('libp2p-noise')
|
||||
const defaultsDeep = require('@nodeutils/defaults-deep')
|
||||
const libp2p = require('../../..')
|
||||
|
||||
class Node extends libp2p {
|
||||
constructor (_options) {
|
||||
const defaults = {
|
||||
modules: {
|
||||
transport: [
|
||||
TCP,
|
||||
WS
|
||||
],
|
||||
streamMuxer: [ mplex ],
|
||||
connEncryption: [ NOISE ]
|
||||
}
|
||||
}
|
||||
|
||||
super(defaultsDeep(_options, defaults))
|
||||
async function createLibp2p(_options) {
|
||||
const defaults = {
|
||||
modules: {
|
||||
transport: [TCP, WS],
|
||||
streamMuxer: [mplex],
|
||||
connEncryption: [NOISE],
|
||||
},
|
||||
}
|
||||
|
||||
return libp2p.create(defaultsDeep(_options, defaults))
|
||||
}
|
||||
|
||||
module.exports = Node
|
||||
module.exports = createLibp2p
|
||||
|
@ -6,14 +6,14 @@
|
||||
*/
|
||||
|
||||
const PeerId = require('peer-id')
|
||||
const Node = require('./libp2p-bundle')
|
||||
const createLibp2p = require('./libp2p-bundle')
|
||||
const pipe = require('it-pipe')
|
||||
|
||||
async function run() {
|
||||
const listenerId = await PeerId.createFromJSON(require('./id-l'))
|
||||
|
||||
// Listener libp2p node
|
||||
const listenerNode = new Node({
|
||||
const listenerNode = await createLibp2p({
|
||||
addresses: {
|
||||
listen: ['/ip4/0.0.0.0/tcp/10333']
|
||||
},
|
||||
|
@ -31,12 +31,11 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
[Bootstrap.tag]: {
|
||||
enabled: true,
|
||||
list: [
|
||||
'/dns4/ams-1.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd',
|
||||
'/dns4/lon-1.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3',
|
||||
'/dns4/sfo-3.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM',
|
||||
'/dns4/sgp-1.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu',
|
||||
'/dns4/nyc-1.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm',
|
||||
'/dns4/nyc-2.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64'
|
||||
'/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN',
|
||||
'/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb',
|
||||
'/dnsaddr/bootstrap.libp2p.io/p2p/QmZa1sAxajnQjVM8WjWXoMbmPd7NsWhfKsPkErzpm9wGkp',
|
||||
'/dnsaddr/bootstrap.libp2p.io/p2p/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa',
|
||||
'/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt'
|
||||
]
|
||||
}
|
||||
}
|
||||
|
17
package.json
17
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "libp2p",
|
||||
"version": "0.29.2",
|
||||
"version": "0.29.4",
|
||||
"description": "JavaScript implementation of libp2p, a modular peer to peer network stack",
|
||||
"leadMaintainer": "Jacob Heun <jacobheun@gmail.com>",
|
||||
"main": "src/index.js",
|
||||
@ -64,7 +64,7 @@
|
||||
"mafmt": "^8.0.0",
|
||||
"merge-options": "^2.0.0",
|
||||
"moving-average": "^1.0.0",
|
||||
"multiaddr": "^8.0.0",
|
||||
"multiaddr": "^8.1.0",
|
||||
"multicodec": "^2.0.0",
|
||||
"multistream-select": "^1.0.0",
|
||||
"mutable-proxy": "^1.0.0",
|
||||
@ -135,6 +135,7 @@
|
||||
"dirkmc <dirkmdev@gmail.com>",
|
||||
"Volker Mische <volker.mische@gmail.com>",
|
||||
"Richard Littauer <richard.littauer@gmail.com>",
|
||||
"a1300 <matthias-knopp@gmx.net>",
|
||||
"Elven <mon.samuel@qq.com>",
|
||||
"Andrew Nesbitt <andrewnez@gmail.com>",
|
||||
"Giovanni T. Parra <fiatjaf@gmail.com>",
|
||||
@ -142,8 +143,6 @@
|
||||
"Thomas Eizinger <thomas@eizinger.io>",
|
||||
"ᴠɪᴄᴛᴏʀ ʙᴊᴇʟᴋʜᴏʟᴍ <victorbjelkholm@gmail.com>",
|
||||
"Didrik Nordström <didrik@betamos.se>",
|
||||
"Henrique Dias <hacdias@gmail.com>",
|
||||
"Fei Liu <liu.feiwood@gmail.com>",
|
||||
"Irakli Gozalishvili <rfobic@gmail.com>",
|
||||
"Ethan Lam <elmemphis2000@gmail.com>",
|
||||
"Joel Gustafson <joelg@mit.edu>",
|
||||
@ -153,9 +152,11 @@
|
||||
"Dmitriy Ryajov <dryajov@gmail.com>",
|
||||
"RasmusErik Voel Jensen <github@solsort.com>",
|
||||
"Diogo Silva <fsdiogo@gmail.com>",
|
||||
"robertkiel <robert.kiel@validitylabs.org>",
|
||||
"Samlior <samlior@foxmail.com>",
|
||||
"Smite Chow <xiaopengyou@live.com>",
|
||||
"Soeren <nikorpoulsen@gmail.com>",
|
||||
"Sönke Hahn <soenkehahn@gmail.com>",
|
||||
"robertkiel <robert.kiel@validitylabs.org>",
|
||||
"Tiago Alves <alvesjtiago@gmail.com>",
|
||||
"Daijiro Wachi <daijiro.wachi@gmail.com>",
|
||||
"Yusef Napora <yusef@napora.org>",
|
||||
@ -164,9 +165,11 @@
|
||||
"Chris Bratlien <chrisbratlien@gmail.com>",
|
||||
"ebinks <elizabethjbinks@gmail.com>",
|
||||
"Bernd Strehl <bernd.strehl@gmail.com>",
|
||||
"isan_rivkin <isanrivkin@gmail.com>",
|
||||
"Florian-Merle <florian.david.merle@gmail.com>",
|
||||
"Francis Gulotta <wizard@roborooter.com>",
|
||||
"Felipe Martins <felipebrasil93@gmail.com>"
|
||||
"Felipe Martins <felipebrasil93@gmail.com>",
|
||||
"isan_rivkin <isanrivkin@gmail.com>",
|
||||
"Henrique Dias <hacdias@gmail.com>",
|
||||
"Fei Liu <liu.feiwood@gmail.com>"
|
||||
]
|
||||
}
|
||||
|
@ -1,7 +1,10 @@
|
||||
'use strict'
|
||||
|
||||
const mergeOptions = require('merge-options')
|
||||
const { dnsaddrResolver } = require('multiaddr/src/resolvers')
|
||||
|
||||
const Constants = require('./constants')
|
||||
const { AGENT_VERSION } = require('./identify/consts')
|
||||
|
||||
const { FaultTolerance } = require('./transport-manager')
|
||||
|
||||
@ -20,7 +23,13 @@ const DefaultConfig = {
|
||||
dialer: {
|
||||
maxParallelDials: Constants.MAX_PARALLEL_DIALS,
|
||||
maxDialsPerPeer: Constants.MAX_PER_PEER_DIALS,
|
||||
dialTimeout: Constants.DIAL_TIMEOUT
|
||||
dialTimeout: Constants.DIAL_TIMEOUT,
|
||||
resolvers: {
|
||||
dnsaddr: dnsaddrResolver
|
||||
}
|
||||
},
|
||||
host: {
|
||||
agentVersion: AGENT_VERSION
|
||||
},
|
||||
metrics: {
|
||||
enabled: false
|
||||
|
@ -27,13 +27,15 @@ class Dialer {
|
||||
* @param {number} [options.concurrency = MAX_PARALLEL_DIALS] - Number of max concurrent dials.
|
||||
* @param {number} [options.perPeerLimit = MAX_PER_PEER_DIALS] - Number of max concurrent dials per peer.
|
||||
* @param {number} [options.timeout = DIAL_TIMEOUT] - How long a dial attempt is allowed to take.
|
||||
* @param {object} [options.resolvers = {}] - multiaddr resolvers to use when dialing
|
||||
*/
|
||||
constructor ({
|
||||
transportManager,
|
||||
peerStore,
|
||||
concurrency = MAX_PARALLEL_DIALS,
|
||||
timeout = DIAL_TIMEOUT,
|
||||
perPeerLimit = MAX_PER_PEER_DIALS
|
||||
perPeerLimit = MAX_PER_PEER_DIALS,
|
||||
resolvers = {}
|
||||
}) {
|
||||
this.transportManager = transportManager
|
||||
this.peerStore = peerStore
|
||||
@ -42,6 +44,10 @@ class Dialer {
|
||||
this.perPeerLimit = perPeerLimit
|
||||
this.tokens = [...new Array(concurrency)].map((_, index) => index)
|
||||
this._pendingDials = new Map()
|
||||
|
||||
for (const [key, value] of Object.entries(resolvers)) {
|
||||
multiaddr.resolvers.set(key, value)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -69,7 +75,7 @@ class Dialer {
|
||||
* @returns {Promise<Connection>}
|
||||
*/
|
||||
async connectToPeer (peer, options = {}) {
|
||||
const dialTarget = this._createDialTarget(peer)
|
||||
const dialTarget = await this._createDialTarget(peer)
|
||||
|
||||
if (!dialTarget.addrs.length) {
|
||||
throw errCode(new Error('The dial request has no addresses'), codes.ERR_NO_VALID_ADDRESSES)
|
||||
@ -105,22 +111,28 @@ class Dialer {
|
||||
*
|
||||
* @private
|
||||
* @param {PeerId|Multiaddr|string} peer - A PeerId or Multiaddr
|
||||
* @returns {DialTarget}
|
||||
* @returns {Promise<DialTarget>}
|
||||
*/
|
||||
_createDialTarget (peer) {
|
||||
async _createDialTarget (peer) {
|
||||
const { id, multiaddrs } = getPeer(peer)
|
||||
|
||||
if (multiaddrs) {
|
||||
this.peerStore.addressBook.add(id, multiaddrs)
|
||||
}
|
||||
|
||||
let addrs = this.peerStore.addressBook.getMultiaddrsForPeer(id) || []
|
||||
let knownAddrs = this.peerStore.addressBook.getMultiaddrsForPeer(id) || []
|
||||
|
||||
// If received a multiaddr to dial, it should be the first to use
|
||||
// But, if we know other multiaddrs for the peer, we should try them too.
|
||||
if (multiaddr.isMultiaddr(peer)) {
|
||||
addrs = addrs.filter((addr) => !peer.equals(addr))
|
||||
addrs.unshift(peer)
|
||||
knownAddrs = knownAddrs.filter((addr) => !peer.equals(addr))
|
||||
knownAddrs.unshift(peer)
|
||||
}
|
||||
|
||||
const addrs = []
|
||||
for (const a of knownAddrs) {
|
||||
const resolvedAddrs = await this._resolve(a)
|
||||
resolvedAddrs.forEach(ra => addrs.push(ra))
|
||||
}
|
||||
|
||||
return {
|
||||
@ -190,6 +202,52 @@ class Dialer {
|
||||
log('token %d released', token)
|
||||
this.tokens.push(token)
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve multiaddr recursively.
|
||||
*
|
||||
* @param {Multiaddr} ma
|
||||
* @returns {Promise<Array<Multiaddr>>}
|
||||
*/
|
||||
async _resolve (ma) {
|
||||
// TODO: recursive logic should live in multiaddr once dns4/dns6 support is in place
|
||||
// Now only supporting resolve for dnsaddr
|
||||
const resolvableProto = ma.protoNames().includes('dnsaddr')
|
||||
|
||||
// Multiaddr is not resolvable? End recursion!
|
||||
if (!resolvableProto) {
|
||||
return [ma]
|
||||
}
|
||||
|
||||
const resolvedMultiaddrs = await this._resolveRecord(ma)
|
||||
const recursiveMultiaddrs = await Promise.all(resolvedMultiaddrs.map((nm) => {
|
||||
return this._resolve(nm)
|
||||
}))
|
||||
|
||||
return recursiveMultiaddrs.flat().reduce((array, newM) => {
|
||||
if (!array.find(m => m.equals(newM))) {
|
||||
array.push(newM)
|
||||
}
|
||||
return array
|
||||
}, []) // Unique addresses
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a given multiaddr. If this fails, an empty array will be returned
|
||||
*
|
||||
* @param {Multiaddr} ma
|
||||
* @returns {Promise<Array<Multiaddr>>}
|
||||
*/
|
||||
async _resolveRecord (ma) {
|
||||
try {
|
||||
ma = multiaddr(ma.toString()) // Use current multiaddr module
|
||||
const multiaddrs = await ma.resolve()
|
||||
return multiaddrs
|
||||
} catch (_) {
|
||||
log.error(`multiaddr ${ma} could not be resolved`)
|
||||
return []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Dialer
|
||||
|
@ -16,6 +16,7 @@ exports.codes = {
|
||||
ERR_NODE_NOT_STARTED: 'ERR_NODE_NOT_STARTED',
|
||||
ERR_ALREADY_ABORTED: 'ERR_ALREADY_ABORTED',
|
||||
ERR_NO_VALID_ADDRESSES: 'ERR_NO_VALID_ADDRESSES',
|
||||
ERR_DIALED_SELF: 'ERR_DIALED_SELF',
|
||||
ERR_DISCOVERED_SELF: 'ERR_DISCOVERED_SELF',
|
||||
ERR_DUPLICATE_TRANSPORT: 'ERR_DUPLICATE_TRANSPORT',
|
||||
ERR_ENCRYPTION_FAILED: 'ERR_ENCRYPTION_FAILED',
|
||||
|
@ -83,6 +83,16 @@ class IdentifyService {
|
||||
this._protocols = protocols
|
||||
|
||||
this.handleMessage = this.handleMessage.bind(this)
|
||||
|
||||
// Store self host metadata
|
||||
this._host = {
|
||||
agentVersion: AGENT_VERSION,
|
||||
protocolVersion: PROTOCOL_VERSION,
|
||||
...libp2p._options.host
|
||||
}
|
||||
|
||||
this.peerStore.metadataBook.set(this.peerId, 'AgentVersion', uint8ArrayFromString(this._host.agentVersion))
|
||||
this.peerStore.metadataBook.set(this.peerId, 'ProtocolVersion', uint8ArrayFromString(this._host.protocolVersion))
|
||||
}
|
||||
|
||||
/**
|
||||
@ -246,8 +256,8 @@ class IdentifyService {
|
||||
const signedPeerRecord = await this._getSelfPeerRecord()
|
||||
|
||||
const message = Message.encode({
|
||||
protocolVersion: PROTOCOL_VERSION,
|
||||
agentVersion: AGENT_VERSION,
|
||||
protocolVersion: this._host.protocolVersion,
|
||||
agentVersion: this._host.agentVersion,
|
||||
publicKey,
|
||||
listenAddrs: this._libp2p.multiaddrs.map((ma) => ma.bytes),
|
||||
signedPeerRecord,
|
||||
|
12
src/index.js
12
src/index.js
@ -134,7 +134,8 @@ class Libp2p extends EventEmitter {
|
||||
peerStore: this.peerStore,
|
||||
concurrency: this._options.dialer.maxParallelDials,
|
||||
perPeerLimit: this._options.dialer.maxDialsPerPeer,
|
||||
timeout: this._options.dialer.dialTimeout
|
||||
timeout: this._options.dialer.dialTimeout,
|
||||
resolvers: this._options.dialer.resolvers
|
||||
})
|
||||
|
||||
this._modules.transport.forEach((Transport) => {
|
||||
@ -241,7 +242,7 @@ class Libp2p extends EventEmitter {
|
||||
* Stop the libp2p node by closing its listeners and open connections
|
||||
*
|
||||
* @async
|
||||
* @returns {void}
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async stop () {
|
||||
log('libp2p is stopping')
|
||||
@ -334,6 +335,11 @@ class Libp2p extends EventEmitter {
|
||||
*/
|
||||
async dialProtocol (peer, protocols, options) {
|
||||
const { id, multiaddrs } = getPeer(peer)
|
||||
|
||||
if (id.equals(this.peerId)) {
|
||||
throw errCode(new Error('Cannot dial self'), codes.ERR_DIALED_SELF)
|
||||
}
|
||||
|
||||
let connection = this.connectionManager.get(id)
|
||||
|
||||
if (!connection) {
|
||||
@ -600,7 +606,7 @@ class Libp2p extends EventEmitter {
|
||||
* instance if one is not provided in options.
|
||||
*
|
||||
* @param {object} options - Libp2p configuration options
|
||||
* @returns {Libp2p}
|
||||
* @returns {Promise<Libp2p>}
|
||||
*/
|
||||
Libp2p.create = async function create (options = {}) {
|
||||
if (options.peerId) {
|
||||
|
@ -20,6 +20,7 @@ class TransportManager {
|
||||
this.upgrader = upgrader
|
||||
this._transports = new Map()
|
||||
this._listeners = new Map()
|
||||
this._listenerOptions = new Map()
|
||||
this.faultTolerance = faultTolerance
|
||||
}
|
||||
|
||||
@ -47,6 +48,7 @@ class TransportManager {
|
||||
})
|
||||
|
||||
this._transports.set(key, transport)
|
||||
this._listenerOptions.set(key, transportOptions.listenerOptions || {})
|
||||
if (!this._listeners.has(key)) {
|
||||
this._listeners.set(key, [])
|
||||
}
|
||||
@ -154,7 +156,7 @@ class TransportManager {
|
||||
// For each supported multiaddr, create a listener
|
||||
for (const addr of supportedAddrs) {
|
||||
log('creating listener for %s on %s', key, addr)
|
||||
const listener = transport.createListener({}, this.onConnection)
|
||||
const listener = transport.createListener(this._listenerOptions.get(key), this.onConnection)
|
||||
this._listeners.get(key).push(listener)
|
||||
|
||||
// We need to attempt to listen on everything
|
||||
|
@ -18,10 +18,16 @@ const listenMultiaddr = '/ip4/127.0.0.1/tcp/15002/ws'
|
||||
|
||||
describe('Connection Manager', () => {
|
||||
let libp2p
|
||||
let peerIds
|
||||
|
||||
before(async () => {
|
||||
peerIds = await peerUtils.createPeerId({ number: 2 })
|
||||
})
|
||||
|
||||
beforeEach(async () => {
|
||||
[libp2p] = await peerUtils.createPeer({
|
||||
config: {
|
||||
peerId: peerIds[0],
|
||||
addresses: {
|
||||
listen: [listenMultiaddr]
|
||||
},
|
||||
@ -33,12 +39,10 @@ describe('Connection Manager', () => {
|
||||
afterEach(() => libp2p.stop())
|
||||
|
||||
it('should filter connections on disconnect, removing the closed one', async () => {
|
||||
const [localPeer, remotePeer] = await peerUtils.createPeerId({ number: 2 })
|
||||
const conn1 = await mockConnection({ localPeer: peerIds[0], remotePeer: peerIds[1] })
|
||||
const conn2 = await mockConnection({ localPeer: peerIds[0], remotePeer: peerIds[1] })
|
||||
|
||||
const conn1 = await mockConnection({ localPeer, remotePeer })
|
||||
const conn2 = await mockConnection({ localPeer, remotePeer })
|
||||
|
||||
const id = remotePeer.toB58String()
|
||||
const id = peerIds[1].toB58String()
|
||||
|
||||
// Add connection to the connectionManager
|
||||
libp2p.connectionManager.onConnect(conn1)
|
||||
@ -57,6 +61,7 @@ describe('Connection Manager', () => {
|
||||
it('should add connection on dial and remove on node stop', async () => {
|
||||
const [remoteLibp2p] = await peerUtils.createPeer({
|
||||
config: {
|
||||
peerId: peerIds[1],
|
||||
addresses: {
|
||||
listen: ['/ip4/127.0.0.1/tcp/15003/ws']
|
||||
},
|
||||
@ -89,9 +94,16 @@ describe('Connection Manager', () => {
|
||||
})
|
||||
|
||||
describe('libp2p.connections', () => {
|
||||
let peerIds
|
||||
|
||||
before(async () => {
|
||||
peerIds = await peerUtils.createPeerId({ number: 2 })
|
||||
})
|
||||
|
||||
it('libp2p.connections gets the connectionManager conns', async () => {
|
||||
const [libp2p] = await peerUtils.createPeer({
|
||||
config: {
|
||||
peerId: peerIds[0],
|
||||
addresses: {
|
||||
listen: ['/ip4/127.0.0.1/tcp/15003/ws']
|
||||
},
|
||||
@ -100,6 +112,7 @@ describe('libp2p.connections', () => {
|
||||
})
|
||||
const [remoteLibp2p] = await peerUtils.createPeer({
|
||||
config: {
|
||||
peerId: peerIds[1],
|
||||
addresses: {
|
||||
listen: ['/ip4/127.0.0.1/tcp/15004/ws']
|
||||
},
|
||||
|
@ -158,9 +158,9 @@ describe('Dialing (direct, TCP)', () => {
|
||||
|
||||
it('should dial to the max concurrency', async () => {
|
||||
const addrs = [
|
||||
'/ip4/0.0.0.0/tcp/8000',
|
||||
'/ip4/0.0.0.0/tcp/8001',
|
||||
'/ip4/0.0.0.0/tcp/8002'
|
||||
multiaddr('/ip4/0.0.0.0/tcp/8000'),
|
||||
multiaddr('/ip4/0.0.0.0/tcp/8001'),
|
||||
multiaddr('/ip4/0.0.0.0/tcp/8002')
|
||||
]
|
||||
const dialer = new Dialer({
|
||||
transportManager: localTM,
|
||||
|
@ -263,7 +263,6 @@ describe('Dialing (direct, WebSockets)', () => {
|
||||
|
||||
describe('libp2p.dialer', () => {
|
||||
let libp2p
|
||||
let remoteLibp2p
|
||||
|
||||
afterEach(async () => {
|
||||
sinon.restore()
|
||||
@ -271,10 +270,6 @@ describe('Dialing (direct, WebSockets)', () => {
|
||||
libp2p = null
|
||||
})
|
||||
|
||||
after(async () => {
|
||||
remoteLibp2p && await remoteLibp2p.stop()
|
||||
})
|
||||
|
||||
it('should create a dialer', () => {
|
||||
libp2p = new Libp2p({
|
||||
peerId,
|
||||
@ -414,5 +409,20 @@ describe('Dialing (direct, WebSockets)', () => {
|
||||
|
||||
expect(libp2p.dialer.destroy).to.have.property('callCount', 1)
|
||||
})
|
||||
|
||||
it('should fail to dial self', async () => {
|
||||
libp2p = new Libp2p({
|
||||
peerId,
|
||||
modules: {
|
||||
transport: [Transport],
|
||||
streamMuxer: [Muxer],
|
||||
connEncryption: [Crypto]
|
||||
}
|
||||
})
|
||||
|
||||
await expect(libp2p.dial(peerId))
|
||||
.to.eventually.be.rejected()
|
||||
.and.to.have.property('code', ErrorCodes.ERR_DIALED_SELF)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
176
test/dialing/resolver.spec.js
Normal file
176
test/dialing/resolver.spec.js
Normal file
@ -0,0 +1,176 @@
|
||||
'use strict'
|
||||
/* eslint-env mocha */
|
||||
|
||||
const { expect } = require('aegir/utils/chai')
|
||||
const sinon = require('sinon')
|
||||
|
||||
const multiaddr = require('multiaddr')
|
||||
const { Resolver } = require('multiaddr/src/resolvers/dns')
|
||||
|
||||
const { codes: ErrorCodes } = require('../../src/errors')
|
||||
|
||||
const peerUtils = require('../utils/creators/peer')
|
||||
const baseOptions = require('../utils/base-options.browser')
|
||||
|
||||
const { MULTIADDRS_WEBSOCKETS } = require('../fixtures/browser')
|
||||
const relayAddr = MULTIADDRS_WEBSOCKETS[0]
|
||||
|
||||
const getDnsaddrStub = (peerId) => [
|
||||
[`dnsaddr=/dnsaddr/ams-1.bootstrap.libp2p.io/p2p/${peerId}`],
|
||||
[`dnsaddr=/dnsaddr/ams-2.bootstrap.libp2p.io/p2p/${peerId}`],
|
||||
[`dnsaddr=/dnsaddr/lon-1.bootstrap.libp2p.io/p2p/${peerId}`],
|
||||
[`dnsaddr=/dnsaddr/nrt-1.bootstrap.libp2p.io/p2p/${peerId}`],
|
||||
[`dnsaddr=/dnsaddr/nyc-1.bootstrap.libp2p.io/p2p/${peerId}`],
|
||||
[`dnsaddr=/dnsaddr/sfo-2.bootstrap.libp2p.io/p2p/${peerId}`]
|
||||
]
|
||||
|
||||
const relayedAddr = (peerId) => `${relayAddr}/p2p-circuit/p2p/${peerId}`
|
||||
|
||||
const getDnsRelayedAddrStub = (peerId) => [
|
||||
[`dnsaddr=${relayedAddr(peerId)}`]
|
||||
]
|
||||
|
||||
describe('Dialing (resolvable addresses)', () => {
|
||||
let libp2p, remoteLibp2p
|
||||
|
||||
beforeEach(async () => {
|
||||
[libp2p, remoteLibp2p] = await peerUtils.createPeer({
|
||||
number: 2,
|
||||
config: {
|
||||
modules: baseOptions.modules,
|
||||
addresses: {
|
||||
listen: [multiaddr(`${relayAddr}/p2p-circuit`)]
|
||||
},
|
||||
config: {
|
||||
peerDiscovery: {
|
||||
autoDial: false
|
||||
}
|
||||
}
|
||||
},
|
||||
started: true,
|
||||
populateAddressBooks: false
|
||||
})
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
sinon.restore()
|
||||
await Promise.all([libp2p, remoteLibp2p].map(n => n.stop()))
|
||||
})
|
||||
|
||||
it('resolves dnsaddr to ws local address', async () => {
|
||||
const remoteId = remoteLibp2p.peerId.toB58String()
|
||||
const dialAddr = multiaddr(`/dnsaddr/remote.libp2p.io/p2p/${remoteId}`)
|
||||
const relayedAddrFetched = multiaddr(relayedAddr(remoteId))
|
||||
|
||||
// Transport spy
|
||||
const transport = libp2p.transportManager._transports.get('Circuit')
|
||||
sinon.spy(transport, 'dial')
|
||||
|
||||
// Resolver stub
|
||||
const stub = sinon.stub(Resolver.prototype, 'resolveTxt')
|
||||
stub.onCall(0).returns(Promise.resolve(getDnsRelayedAddrStub(remoteId)))
|
||||
|
||||
// Dial with address resolve
|
||||
const connection = await libp2p.dial(dialAddr)
|
||||
expect(connection).to.exist()
|
||||
expect(connection.remoteAddr.equals(relayedAddrFetched))
|
||||
|
||||
const dialArgs = transport.dial.firstCall.args
|
||||
expect(dialArgs[0].equals(relayedAddrFetched)).to.eql(true)
|
||||
})
|
||||
|
||||
it('resolves a dnsaddr recursively', async () => {
|
||||
const remoteId = remoteLibp2p.peerId.toB58String()
|
||||
const dialAddr = multiaddr(`/dnsaddr/remote.libp2p.io/p2p/${remoteId}`)
|
||||
const relayedAddrFetched = multiaddr(relayedAddr(remoteId))
|
||||
|
||||
// Transport spy
|
||||
const transport = libp2p.transportManager._transports.get('Circuit')
|
||||
sinon.spy(transport, 'dial')
|
||||
|
||||
// Resolver stub
|
||||
const stub = sinon.stub(Resolver.prototype, 'resolveTxt')
|
||||
let firstCall = false
|
||||
stub.callsFake(() => {
|
||||
if (!firstCall) {
|
||||
firstCall = true
|
||||
// Return an array of dnsaddr
|
||||
return Promise.resolve(getDnsaddrStub(remoteId))
|
||||
}
|
||||
return Promise.resolve(getDnsRelayedAddrStub(remoteId))
|
||||
})
|
||||
|
||||
// Dial with address resolve
|
||||
const connection = await libp2p.dial(dialAddr)
|
||||
expect(connection).to.exist()
|
||||
expect(connection.remoteAddr.equals(relayedAddrFetched))
|
||||
|
||||
const dialArgs = transport.dial.firstCall.args
|
||||
expect(dialArgs[0].equals(relayedAddrFetched)).to.eql(true)
|
||||
})
|
||||
|
||||
// TODO: Temporary solution does not resolve dns4/dns6
|
||||
// Resolver just returns the received multiaddrs
|
||||
it('stops recursive resolve if finds dns4/dns6 and dials it', async () => {
|
||||
const remoteId = remoteLibp2p.peerId.toB58String()
|
||||
const dialAddr = multiaddr(`/dnsaddr/remote.libp2p.io/p2p/${remoteId}`)
|
||||
|
||||
// Stub resolver
|
||||
const dnsMa = multiaddr(`/dns4/ams-1.remote.libp2p.io/tcp/443/wss/p2p/${remoteId}`)
|
||||
const stubResolve = sinon.stub(Resolver.prototype, 'resolveTxt')
|
||||
stubResolve.returns(Promise.resolve([
|
||||
[`dnsaddr=${dnsMa}`]
|
||||
]))
|
||||
|
||||
// Stub transport
|
||||
const transport = libp2p.transportManager._transports.get('WebSockets')
|
||||
const stubTransport = sinon.stub(transport, 'dial')
|
||||
stubTransport.callsFake((multiaddr) => {
|
||||
expect(multiaddr.equals(dnsMa)).to.eql(true)
|
||||
})
|
||||
|
||||
await libp2p.dial(dialAddr)
|
||||
})
|
||||
|
||||
it('resolves a dnsaddr recursively not failing if one address fails to resolve', async () => {
|
||||
const remoteId = remoteLibp2p.peerId.toB58String()
|
||||
const dialAddr = multiaddr(`/dnsaddr/remote.libp2p.io/p2p/${remoteId}`)
|
||||
const relayedAddrFetched = multiaddr(relayedAddr(remoteId))
|
||||
|
||||
// Transport spy
|
||||
const transport = libp2p.transportManager._transports.get('Circuit')
|
||||
sinon.spy(transport, 'dial')
|
||||
|
||||
// Resolver stub
|
||||
const stub = sinon.stub(Resolver.prototype, 'resolveTxt')
|
||||
stub.onCall(0).callsFake(() => Promise.resolve(getDnsaddrStub(remoteId)))
|
||||
stub.onCall(1).callsFake(() => Promise.reject(new Error()))
|
||||
stub.callsFake(() => Promise.resolve(getDnsRelayedAddrStub(remoteId)))
|
||||
|
||||
// Dial with address resolve
|
||||
const connection = await libp2p.dial(dialAddr)
|
||||
expect(connection).to.exist()
|
||||
expect(connection.remoteAddr.equals(relayedAddrFetched))
|
||||
|
||||
const dialArgs = transport.dial.firstCall.args
|
||||
expect(dialArgs[0].equals(relayedAddrFetched)).to.eql(true)
|
||||
})
|
||||
|
||||
it('fails to dial if resolve fails and there are no addresses to dial', async () => {
|
||||
const remoteId = remoteLibp2p.peerId.toB58String()
|
||||
const dialAddr = multiaddr(`/dnsaddr/remote.libp2p.io/p2p/${remoteId}`)
|
||||
|
||||
// Stub resolver
|
||||
const stubResolve = sinon.stub(Resolver.prototype, 'resolveTxt')
|
||||
stubResolve.returns(Promise.reject(new Error()))
|
||||
|
||||
// Stub transport
|
||||
const transport = libp2p.transportManager._transports.get('WebSockets')
|
||||
const spy = sinon.spy(transport, 'dial')
|
||||
|
||||
await expect(libp2p.dial(dialAddr))
|
||||
.to.eventually.be.rejectedWith(Error)
|
||||
.and.to.have.nested.property('.code', ErrorCodes.ERR_NO_VALID_ADDRESSES)
|
||||
expect(spy.callCount).to.eql(0)
|
||||
})
|
||||
})
|
@ -53,7 +53,8 @@ describe('Identify', () => {
|
||||
peerId: localPeer,
|
||||
connectionManager: new EventEmitter(),
|
||||
peerStore: new PeerStore({ peerId: localPeer }),
|
||||
multiaddrs: listenMaddrs
|
||||
multiaddrs: listenMaddrs,
|
||||
_options: { host: {} }
|
||||
},
|
||||
protocols
|
||||
})
|
||||
@ -63,7 +64,8 @@ describe('Identify', () => {
|
||||
peerId: remotePeer,
|
||||
connectionManager: new EventEmitter(),
|
||||
peerStore: new PeerStore({ peerId: remotePeer }),
|
||||
multiaddrs: listenMaddrs
|
||||
multiaddrs: listenMaddrs,
|
||||
_options: { host: {} }
|
||||
},
|
||||
protocols
|
||||
})
|
||||
@ -106,7 +108,8 @@ describe('Identify', () => {
|
||||
peerId: localPeer,
|
||||
connectionManager: new EventEmitter(),
|
||||
peerStore: new PeerStore({ peerId: localPeer }),
|
||||
multiaddrs: listenMaddrs
|
||||
multiaddrs: listenMaddrs,
|
||||
_options: { host: {} }
|
||||
},
|
||||
protocols
|
||||
})
|
||||
@ -116,7 +119,8 @@ describe('Identify', () => {
|
||||
peerId: remotePeer,
|
||||
connectionManager: new EventEmitter(),
|
||||
peerStore: new PeerStore({ peerId: remotePeer }),
|
||||
multiaddrs: listenMaddrs
|
||||
multiaddrs: listenMaddrs,
|
||||
_options: { host: {} }
|
||||
},
|
||||
protocols
|
||||
})
|
||||
@ -165,7 +169,8 @@ describe('Identify', () => {
|
||||
peerId: localPeer,
|
||||
connectionManager: new EventEmitter(),
|
||||
peerStore: new PeerStore({ peerId: localPeer }),
|
||||
multiaddrs: []
|
||||
multiaddrs: [],
|
||||
_options: { host: {} }
|
||||
},
|
||||
protocols
|
||||
})
|
||||
@ -174,7 +179,8 @@ describe('Identify', () => {
|
||||
peerId: remotePeer,
|
||||
connectionManager: new EventEmitter(),
|
||||
peerStore: new PeerStore({ peerId: remotePeer }),
|
||||
multiaddrs: []
|
||||
multiaddrs: [],
|
||||
_options: { host: {} }
|
||||
},
|
||||
protocols
|
||||
})
|
||||
@ -201,6 +207,36 @@ describe('Identify', () => {
|
||||
.and.to.have.property('code', Errors.ERR_INVALID_PEER)
|
||||
})
|
||||
|
||||
it('should store host data and protocol version into metadataBook', () => {
|
||||
const agentVersion = 'js-project/1.0.0'
|
||||
const peerStore = new PeerStore({ peerId: localPeer })
|
||||
|
||||
sinon.spy(peerStore.metadataBook, 'set')
|
||||
|
||||
new IdentifyService({ // eslint-disable-line no-new
|
||||
libp2p: {
|
||||
peerId: localPeer,
|
||||
connectionManager: new EventEmitter(),
|
||||
peerStore,
|
||||
multiaddrs: listenMaddrs,
|
||||
_options: {
|
||||
host: {
|
||||
agentVersion
|
||||
}
|
||||
}
|
||||
},
|
||||
protocols
|
||||
})
|
||||
|
||||
expect(peerStore.metadataBook.set.callCount).to.eql(2)
|
||||
|
||||
const storedAgentVersion = peerStore.metadataBook.getValue(localPeer, 'AgentVersion')
|
||||
const storedProtocolVersion = peerStore.metadataBook.getValue(localPeer, 'ProtocolVersion')
|
||||
|
||||
expect(agentVersion).to.eql(unit8ArrayToString(storedAgentVersion))
|
||||
expect(storedProtocolVersion).to.exist()
|
||||
})
|
||||
|
||||
describe('push', () => {
|
||||
it('should be able to push identify updates to another peer', async () => {
|
||||
const connectionManager = new EventEmitter()
|
||||
@ -211,7 +247,8 @@ describe('Identify', () => {
|
||||
peerId: localPeer,
|
||||
connectionManager: new EventEmitter(),
|
||||
peerStore: new PeerStore({ peerId: localPeer }),
|
||||
multiaddrs: listenMaddrs
|
||||
multiaddrs: listenMaddrs,
|
||||
_options: { host: {} }
|
||||
},
|
||||
protocols: new Map([
|
||||
[multicodecs.IDENTIFY],
|
||||
@ -224,7 +261,8 @@ describe('Identify', () => {
|
||||
peerId: remotePeer,
|
||||
connectionManager,
|
||||
peerStore: new PeerStore({ peerId: remotePeer }),
|
||||
multiaddrs: []
|
||||
multiaddrs: [],
|
||||
_options: { host: {} }
|
||||
}
|
||||
})
|
||||
|
||||
@ -272,7 +310,8 @@ describe('Identify', () => {
|
||||
peerId: localPeer,
|
||||
connectionManager: new EventEmitter(),
|
||||
peerStore: new PeerStore({ peerId: localPeer }),
|
||||
multiaddrs: listenMaddrs
|
||||
multiaddrs: listenMaddrs,
|
||||
_options: { host: {} }
|
||||
},
|
||||
protocols: new Map([
|
||||
[multicodecs.IDENTIFY],
|
||||
@ -285,7 +324,8 @@ describe('Identify', () => {
|
||||
peerId: remotePeer,
|
||||
connectionManager,
|
||||
peerStore: new PeerStore({ peerId: remotePeer }),
|
||||
multiaddrs: []
|
||||
multiaddrs: [],
|
||||
_options: { host: {} }
|
||||
}
|
||||
})
|
||||
|
||||
@ -404,5 +444,23 @@ describe('Identify', () => {
|
||||
// Verify the streams close
|
||||
await pWaitFor(() => connection.streams.length === 0)
|
||||
})
|
||||
|
||||
it('should store host data and protocol version into metadataBook', () => {
|
||||
const agentVersion = 'js-project/1.0.0'
|
||||
|
||||
libp2p = new Libp2p({
|
||||
...baseOptions,
|
||||
peerId,
|
||||
host: {
|
||||
agentVersion
|
||||
}
|
||||
})
|
||||
|
||||
const storedAgentVersion = libp2p.peerStore.metadataBook.getValue(localPeer, 'AgentVersion')
|
||||
const storedProtocolVersion = libp2p.peerStore.metadataBook.getValue(localPeer, 'ProtocolVersion')
|
||||
|
||||
expect(agentVersion).to.eql(unit8ArrayToString(storedAgentVersion))
|
||||
expect(storedProtocolVersion).to.exist()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -10,6 +10,7 @@ const TransportManager = require('../../src/transport-manager')
|
||||
const Transport = require('libp2p-tcp')
|
||||
const multiaddr = require('multiaddr')
|
||||
const mockUpgrader = require('../utils/mockUpgrader')
|
||||
const sinon = require('sinon')
|
||||
const addrs = [
|
||||
multiaddr('/ip4/127.0.0.1/tcp/0'),
|
||||
multiaddr('/ip4/127.0.0.1/tcp/0')
|
||||
@ -40,7 +41,9 @@ describe('Transport Manager (TCP)', () => {
|
||||
})
|
||||
|
||||
it('should be able to listen', async () => {
|
||||
tm.add(Transport.prototype[Symbol.toStringTag], Transport)
|
||||
tm.add(Transport.prototype[Symbol.toStringTag], Transport, { listenerOptions: { listen: 'carefully' } })
|
||||
const transport = tm._transports.get(Transport.prototype[Symbol.toStringTag])
|
||||
const spyListener = sinon.spy(transport, 'createListener')
|
||||
await tm.listen()
|
||||
expect(tm._listeners).to.have.key(Transport.prototype[Symbol.toStringTag])
|
||||
expect(tm._listeners.get(Transport.prototype[Symbol.toStringTag])).to.have.length(addrs.length)
|
||||
@ -48,6 +51,7 @@ describe('Transport Manager (TCP)', () => {
|
||||
expect(tm.getAddrs().length).to.equal(addrs.length)
|
||||
await tm.close()
|
||||
expect(tm._listeners.get(Transport.prototype[Symbol.toStringTag])).to.have.length(0)
|
||||
expect(spyListener.firstCall.firstArg).to.deep.equal({ listen: 'carefully' })
|
||||
})
|
||||
|
||||
it('should be able to dial', async () => {
|
||||
|
@ -125,7 +125,10 @@ describe('libp2p.transportManager', () => {
|
||||
const spy = sinon.spy()
|
||||
const key = spy.prototype[Symbol.toStringTag] = 'TransportSpy'
|
||||
const customOptions = {
|
||||
another: 'value'
|
||||
another: 'value',
|
||||
listenerOptions: {
|
||||
listen: 'carefully'
|
||||
}
|
||||
}
|
||||
libp2p = new Libp2p({
|
||||
peerId,
|
||||
@ -143,6 +146,7 @@ describe('libp2p.transportManager', () => {
|
||||
expect(libp2p.transportManager).to.exist()
|
||||
// Our transport and circuit relay
|
||||
expect(libp2p.transportManager._transports.size).to.equal(2)
|
||||
expect(libp2p.transportManager._listenerOptions.size).to.equal(2)
|
||||
expect(spy).to.have.property('callCount', 1)
|
||||
expect(spy.getCall(0)).to.have.deep.property('args', [{
|
||||
...customOptions,
|
||||
|
Reference in New Issue
Block a user