feat: address manager

This commit is contained in:
Vasco Santos 2020-04-18 23:26:46 +02:00 committed by Jacob Heun
parent 9e9ec0b575
commit 2a7967c1cc
24 changed files with 598 additions and 126 deletions

View File

@ -11,6 +11,9 @@
* [`handle`](#handle)
* [`unhandle`](#unhandle)
* [`ping`](#ping)
* [`addressManager.listen`](#addressManagerlisten)
* [`addressManager.announce`](#addressManagerannounce)
* [`addressManager.noAnnounce`](#addressManagernoannounce)
* [`contentRouting.findProviders`](#contentroutingfindproviders)
* [`contentRouting.provide`](#contentroutingprovide)
* [`contentRouting.put`](#contentroutingput)
@ -360,31 +363,42 @@ Pings a given peer and get the operation's latency.
const latency = await libp2p.ping(otherPeerId)
```
### peerRouting.findPeer
### addressManager.listen
Iterates over all peer routers in series to find the given peer. If the DHT is enabled, it will be tried first.
Getter for getting the addresses that the peer is using for listening on libp2p transports.
`libp2p.peerRouting.findPeer(peerId, options)`
#### Parameters
| Name | Type | Description |
|------|------|-------------|
| peerId | [`PeerId`][peer-id] | ID of the peer to find |
| options | `object` | operation options |
| options.timeout | `number` | maximum time the query should run |
#### Returns
| Type | Description |
|------|-------------|
| `Promise<{ id: PeerId, multiaddrs: Multiaddr[] }>` | Peer data of a known peer |
`libp2p.addressManager.listen`
#### Example
```js
// ...
const peer = await libp2p.peerRouting.findPeer(peerId, options)
const listenAddresses = libp2p.addressManager.listen
// [ <Multiaddr 047f00000106f9ba - /ip4/127.0.0.1/tcp/63930> ]
```
### addressManager.announce
Getter for getting the addresses that the peer is announcing to other peers in the network.
`libp2p.addressManager.announce`
```js
// ...
const announceAddresses = libp2p.addressManager.announce
// [ <Multiaddr 047f00000106f9ba - /dns4/peer.io/...> ]
```
### addressManager.noAnnounce
Getter for getting the addresses that the peer is not announcing in the network.
`libp2p.addressManager.noAnnounce`
```js
// ...
const noAnnounceAddresses = libp2p.addressManager.noAnnounce
// [ <Multiaddr 047f00000106f9ba - /ip4/127.0.0.1/tcp/63930> ]
```
### contentRouting.findProviders
@ -533,6 +547,33 @@ const key = '/key'
const { from, val } = await libp2p.contentRouting.get(key)
```
### peerRouting.findPeer
Iterates over all peer routers in series to find the given peer. If the DHT is enabled, it will be tried first.
`libp2p.peerRouting.findPeer(peerId, options)`
#### Parameters
| Name | Type | Description |
|------|------|-------------|
| peerId | [`PeerId`][peer-id] | ID of the peer to find |
| options | `object` | operation options |
| options.timeout | `number` | maximum time the query should run |
#### Returns
| Type | Description |
|------|-------------|
| `Promise<{ id: PeerId, multiaddrs: Multiaddr[] }>` | Peer data of a known peer |
#### Example
```js
// ...
const peer = await libp2p.peerRouting.findPeer(peerId, options)
```
### peerStore.addressBook.add
Adds known `multiaddrs` of a given peer. If the peer is not known, it will be set with the provided multiaddrs.

View File

@ -207,6 +207,8 @@ Besides the `modules` and `config`, libp2p allows other internal options and con
- `peerInfo`: a previously created instance of [libp2p/js-peer-info](https://github.com/libp2p/js-peer-info).
- This is particularly useful if you want to reuse the same `peer-id`, as well as for modules like `libp2p-delegated-content-routing`, which need a `peer-id` in their instantiation.
TODO: Add listen/announce addresses and remove peerInfo!!
### Examples
#### Basic setup

View File

@ -0,0 +1,49 @@
# Address Manager
The Address manager is responsible for keeping an updated register of the peer's addresses. It includes 3 different types of Addresses: `Listen Addresses`, `Announce Addresses` and `No Announce Addresses`.
These Addresses should be specified in your libp2p [configuration](../../doc/CONFIGURATION.md) when you create your node.
## Listen Addresses
A libp2p node should have a set of listen addresses, which will be used by libp2p underlying transports to listen for dials from other nodes in the network.
Before a libp2p node starts, a set of listen addresses should be provided to the AddressManager, so that when the node is started, the libp2p transports can use them to listen for connections. Accordingly, listen addresses should be specified through the libp2p configuration, in order to have the `AddressManager` created with them.
It is important pointing out that libp2p accepts to listen on addresses that intend to rely on any available local port. In this context, the provided listen addresses might not be exactly the same as the ones used by the transports. For example tcp may replace `/ip4/0.0.0.0/tcp/0` with something like `/ip4/0.0.0.0/tcp/8989`. As a consequence, libp2p should take into account this when advertising its addresses.
## Announce Addresses
In some scenarios, a libp2p node will need to announce addresses that it is not listening on. In other words, Announce Addresses are an amendment to the Listen Addresses that aim to enable other nodes to achieve connectivity to this node.
Scenarios for Announce Addresses include:
- when you setup a libp2p node in your private network at home, but you need to announce your public IP Address to the outside world;
- when you want to announce a DNS address, which maps to your public IP Address.
## No Announce Addresses
While we need to add Announce Addresses to enable peers' connectivity, we can also not announce addresses that will not be reachable. This way, No Announce Addresses should be specified so that they are not announced by the peer as addresses that other peers can use to dial it.
As stated into the Listen Addresses section, Listen Addresses might get modified after libp2p transports get in action and use them to listen for new connections. This way, libp2p should also take into account these changes so that they can be matched when No Announce Addresses are being filtered out for advertising addresses.
## Implementation
When a libp2p node is created, the Address Manager will be populated from the provided addresses through the libp2p configuration. Once the node is started, the Transport Manager component will gather the listen addresses from the Address Manager, so that the libp2p transports use them to listen on.
Libp2p will use the the Address Manager as the source of truth when advertising the peers addresses. After all transports are ready, other libp2p components/subsystems will kickoff, namely the Identify Service and the DHT. Both of them will announce the node addresses to the other peers in the network. The announce and noAnnounce addresses will have an important role here and will be gathered by libp2p to compute its current addresses to advertise everytime it is needed.
## Future Considerations
### Dynamic address modifications
In a future iteration, we can enable these addresses to be modified in runtime. For this, the Address Manager should be responsible for notifying interested subsystems of these changes, through an Event Emitter.
#### Modify Listen Addresses
While adding new addresses to listen on runtime is a feasible operation, removing one listen address might have bad implications for the node, since all the connections using that listen address will be closed. With this in mind and taking also into consideration the lack of good use cases for removing listen addresses, the Address Manager API only allows libp2p users to add new Listen Addresses on runtime.
Every time a new listen address is added, the Address Manager should emit an event with the new multiaddrs to listen. The Transport Manager should listen to this events and act accordingly.
#### Modify Announce Addresses
When the announce addresses are modified, the Address Manager should emit an event so that other subsystems can act accordingly. For example, libp2p identify service should use the libp2p push protocol to inform other peers about these changes.

View File

@ -0,0 +1,55 @@
'use strict'
const debug = require('debug')
const log = debug('libp2p:addresses')
log.error = debug('libp2p:addresses:error')
const multiaddr = require('multiaddr')
/**
* Responsible for managing the peer addresses.
* Peers can specify their listen, announce and noAnnounce addresses.
* The listen addresses will be used by the libp2p transports to listen for new connections,
* while the announce an noAnnounce addresses will be combined with the listen addresses for
* address adverstising to other peers in the network.
*/
class AddressManager {
/**
* @constructor
* @param {object} [options]
* @param {Array<string>} [options.listen = []] list of multiaddrs string representation to listen.
* @param {Array<string>} [options.announce = []] list of multiaddrs string representation to announce.
* @param {Array<string>} [options.noAnnounce = []] list of multiaddrs string representation to not announce.
*/
constructor ({ listen = [], announce = [], noAnnounce = [] } = {}) {
this.listen = new Set(listen)
this.announce = new Set(announce)
this.noAnnounce = new Set(noAnnounce)
}
/**
* Get peer listen multiaddrs.
* @return {Array<Multiaddr>}
*/
getListenMultiaddrs () {
return Array.from(this.listen).map((a) => multiaddr(a))
}
/**
* Get peer announcing multiaddrs.
* @return {Array<Multiaddr>}
*/
getAnnounceMultiaddrs () {
return Array.from(this.announce).map((a) => multiaddr(a))
}
/**
* Get peer noAnnouncing multiaddrs.
* @return {Array<Multiaddr>}
*/
getNoAnnounceMultiaddrs () {
return Array.from(this.noAnnounce).map((a) => multiaddr(a))
}
}
module.exports = AddressManager

View File

@ -32,7 +32,7 @@ class Circuit {
this._connectionManager = libp2p.connectionManager
this._upgrader = upgrader
this._options = libp2p._config.relay
this.addresses = libp2p.addresses
this.addressManager = libp2p.addressManager
this.peerId = libp2p.peerId
this._registrar.handle(multicodec, this._onProtocol.bind(this))
}
@ -122,7 +122,7 @@ class Circuit {
type: CircuitPB.Type.HOP,
srcPeer: {
id: this.peerId.toBytes(),
addrs: this.addresses.listen.map(addr => addr.buffer)
addrs: this.addressManager.getListenMultiaddrs().map(addr => addr.buffer)
},
dstPeer: {
id: destinationPeer.toBytes(),

View File

@ -5,7 +5,9 @@ const Constants = require('./constants')
const DefaultConfig = {
addresses: {
listen: []
listen: [],
announce: [],
noAnnounce: []
},
connectionManager: {
minPeers: 25

View File

@ -46,22 +46,20 @@ class IdentifyService {
/**
* @constructor
* @param {object} options
* @param {PeerStore} options.peerStore
* @param {ConnectionManager} options.connectionManager
* @param {Libp2p} options.libp2p
* @param {Map<string, handler>} options.protocols A reference to the protocols we support
* @param {PeerId} options.peerId The peer running the identify service
* @param {{ listen: Array<Multiaddr>}} options.addresses The peer addresses
*/
constructor (options) {
/**
* @property {PeerStore}
*/
this.peerStore = options.peerStore
this.peerStore = options.libp2p.peerStore
/**
* @property {ConnectionManager}
*/
this.connectionManager = options.connectionManager
this.connectionManager = options.libp2p.connectionManager
this.connectionManager.on('peer:connect', (connection) => {
const peerId = connection.remotePeer
@ -71,9 +69,12 @@ class IdentifyService {
/**
* @property {PeerId}
*/
this.peerId = options.peerId
this.peerId = options.libp2p.peerId
this.addresses = options.addresses || {}
/**
* @property {AddressManager}
*/
this._libp2p = options.libp2p
this._protocols = options.protocols
@ -92,7 +93,7 @@ class IdentifyService {
await pipe(
[{
listenAddrs: this.addresses.listen.map((ma) => ma.buffer),
listenAddrs: this._libp2p.getAdvertisingMultiaddrs().map((ma) => ma.buffer),
protocols: Array.from(this._protocols.keys())
}],
pb.encode(Message),
@ -217,7 +218,7 @@ class IdentifyService {
protocolVersion: PROTOCOL_VERSION,
agentVersion: AGENT_VERSION,
publicKey,
listenAddrs: this.addresses.listen.map((ma) => ma.buffer),
listenAddrs: this._libp2p.getAdvertisingMultiaddrs().map((ma) => ma.buffer),
observedAddr: connection.remoteAddr.buffer,
protocols: Array.from(this._protocols.keys())
})

View File

@ -15,6 +15,7 @@ const getPeer = require('./get-peer')
const { validate: validateConfig } = require('./config')
const { codes } = require('./errors')
const AddressManager = require('./address-manager')
const ConnectionManager = require('./connection-manager')
const Circuit = require('./circuit')
const Dialer = require('./dialer')
@ -48,6 +49,7 @@ class Libp2p extends EventEmitter {
// Addresses {listen, announce, noAnnounce}
this.addresses = this._options.addresses
this.addressManager = new AddressManager(this._options.addresses)
this._modules = this._options.modules
this._config = this._options.config
@ -123,10 +125,7 @@ class Libp2p extends EventEmitter {
// Add the identify service since we can multiplex
this.identifyService = new IdentifyService({
peerStore: this.peerStore,
connectionManager: this.connectionManager,
peerId: this.peerId,
addresses: this.addresses,
libp2p: this,
protocols: this.upgrader.protocols
})
this.handle(Object.values(IDENTIFY_PROTOCOLS), this.identifyService.handleMessage)
@ -190,6 +189,8 @@ class Libp2p extends EventEmitter {
*/
async start () {
log('libp2p is starting')
// TODO: consider validate listen addresses on start?
// depend on transports?
try {
await this._onStarting()
await this._onDidStart()
@ -295,6 +296,54 @@ class Libp2p extends EventEmitter {
return connection
}
/**
* Get peer advertising multiaddrs by concating the addresses used
* by transports to listen with the announce addresses.
* Duplicated addresses and noAnnounce addresses are filtered out.
* This takes into account random ports on matching noAnnounce addresses.
* @return {Array<Multiaddr>}
*/
getAdvertisingMultiaddrs () {
// Filter noAnnounce multiaddrs
const filterMa = this.addressManager.getNoAnnounceMultiaddrs()
// Special filter for noAnnounce addresses using a random port
// eg /ip4/0.0.0.0/tcp/0 => /ip4/192.168.1.0/tcp/58751
const filterSpecial = filterMa
.map((ma) => ({
protos: ma.protos(),
...ma.toOptions()
}))
.filter((op) => op.port === 0)
// Create advertising list
return this.transportManager.getAddrs()
.concat(this.addressManager.getAnnounceMultiaddrs())
.filter((ma, index, array) => {
// Filter out if repeated
if (array.findIndex((otherMa) => otherMa.equals(ma)) !== index) {
return false
}
// Filter out if in noAnnounceMultiaddrs
if (filterMa.find((fm) => fm.equals(ma))) {
return false
}
// Filter out if in the special filter
const options = ma.toOptions()
if (filterSpecial.find((op) =>
op.family === options.family &&
op.host === options.host &&
op.transport === options.transport &&
op.protos.length === ma.protos().length
)) {
return false
}
return true
})
}
/**
* Disconnects all connections to the given `peer`
* @param {PeerId|multiaddr|string} peer the peer to close connections to
@ -362,14 +411,8 @@ class Libp2p extends EventEmitter {
}
async _onStarting () {
// Listen on the addresses provided
const multiaddrs = this.addresses.listen
await this.transportManager.listen(multiaddrs)
// The addresses may change once the listener starts
// eg /ip4/0.0.0.0/tcp/0 => /ip4/192.168.1.0/tcp/58751
this.addresses.listen = this.transportManager.getAddrs()
// Listen on the provided transports
await this.transportManager.listen()
if (this._config.pubsub.enabled) {
this.pubsub && this.pubsub.start()
@ -475,7 +518,6 @@ class Libp2p extends EventEmitter {
if (typeof DiscoveryService === 'function') {
discoveryService = new DiscoveryService(Object.assign({}, config, {
peerId: this.peerId,
multiaddrs: this.addresses.listen,
libp2p: this
}))
} else {

View File

@ -127,11 +127,13 @@ class TransportManager {
}
/**
* Starts listeners for each given Multiaddr.
* Starts listeners for each listen Multiaddr.
* Update listen multiaddrs of the Address Manager after the operation.
* @async
* @param {Multiaddr[]} addrs
*/
async listen (addrs) {
async listen () {
const addrs = this.libp2p.addressManager.getListenMultiaddrs()
if (addrs.length === 0) {
log('no addresses were provided for listening, this node is dial only')
return

View File

@ -0,0 +1,93 @@
'use strict'
/* eslint-env mocha */
const chai = require('chai')
chai.use(require('dirty-chai'))
chai.use(require('chai-as-promised'))
const { expect } = chai
const multiaddr = require('multiaddr')
const AddressManager = require('../../src/address-manager')
const peerUtils = require('../utils/creators/peer')
const listenAddresses = ['/ip4/127.0.0.1/tcp/15006/ws', '/ip4/127.0.0.1/tcp/15008/ws']
const announceAddreses = ['/dns4/peer.io']
describe('Address Manager', () => {
it('should not need any addresses', () => {
const am = new AddressManager()
expect(am.listen.size).to.equal(0)
expect(am.announce.size).to.equal(0)
expect(am.noAnnounce.size).to.equal(0)
})
it('should return listen multiaddrs on get', () => {
const am = new AddressManager({
listen: listenAddresses
})
expect(am.listen.size).to.equal(listenAddresses.length)
expect(am.announce.size).to.equal(0)
expect(am.noAnnounce.size).to.equal(0)
const listenMultiaddrs = am.getListenMultiaddrs()
expect(listenMultiaddrs.length).to.equal(2)
expect(listenMultiaddrs[0].equals(multiaddr(listenAddresses[0]))).to.equal(true)
expect(listenMultiaddrs[1].equals(multiaddr(listenAddresses[1]))).to.equal(true)
})
it('should return announce multiaddrs on get', () => {
const am = new AddressManager({
listen: listenAddresses,
announce: announceAddreses
})
expect(am.listen.size).to.equal(listenAddresses.length)
expect(am.announce.size).to.equal(announceAddreses.length)
expect(am.noAnnounce.size).to.equal(0)
const announceMultiaddrs = am.getAnnounceMultiaddrs()
expect(announceMultiaddrs.length).to.equal(1)
expect(announceMultiaddrs[0].equals(multiaddr(announceAddreses[0]))).to.equal(true)
})
it('should return noAnnounce multiaddrs on get', () => {
const am = new AddressManager({
listen: listenAddresses,
noAnnounce: listenAddresses
})
expect(am.listen.size).to.equal(listenAddresses.length)
expect(am.announce.size).to.equal(0)
expect(am.noAnnounce.size).to.equal(listenAddresses.length)
const noAnnounceMultiaddrs = am.getNoAnnounceMultiaddrs()
expect(noAnnounceMultiaddrs.length).to.equal(2)
expect(noAnnounceMultiaddrs[0].equals(multiaddr(listenAddresses[0]))).to.equal(true)
expect(noAnnounceMultiaddrs[1].equals(multiaddr(listenAddresses[1]))).to.equal(true)
})
})
describe('libp2p.addressManager', () => {
let libp2p
afterEach(() => libp2p && libp2p.stop())
it('should populate the AddressManager from the config', async () => {
[libp2p] = await peerUtils.createPeer({
started: false,
config: {
addresses: {
listen: listenAddresses,
announce: announceAddreses,
noAnnounce: listenAddresses
}
}
})
expect(libp2p.addressManager.listen.size).to.equal(listenAddresses.length)
expect(libp2p.addressManager.announce.size).to.equal(announceAddreses.length)
expect(libp2p.addressManager.noAnnounce.size).to.equal(listenAddresses.length)
})
})

View File

@ -0,0 +1,152 @@
'use strict'
/* eslint-env mocha */
const chai = require('chai')
chai.use(require('dirty-chai'))
chai.use(require('chai-as-promised'))
const { expect } = chai
const sinon = require('sinon')
const { AddressesOptions } = require('./utils')
const peerUtils = require('../utils/creators/peer')
const listenAddresses = ['/ip4/127.0.0.1/tcp/0', '/ip4/127.0.0.1/tcp/8000/ws']
const announceAddreses = ['/dns4/peer.io']
describe('libp2p.getAdvertisingMultiaddrs', () => {
let libp2p
afterEach(() => libp2p && libp2p.stop())
it('should keep listen addresses after start, even if changed', async () => {
[libp2p] = await peerUtils.createPeer({
started: false,
config: {
...AddressesOptions,
addresses: {
listen: listenAddresses,
announce: announceAddreses
}
}
})
let listenAddrs = libp2p.addressManager.listen
expect(listenAddrs.size).to.equal(listenAddresses.length)
expect(listenAddrs.has(listenAddresses[0])).to.equal(true)
expect(listenAddrs.has(listenAddresses[1])).to.equal(true)
// Should not replace listen addresses after transport listen
// Only transportManager has visibility of the port used
await libp2p.start()
listenAddrs = libp2p.addressManager.listen
expect(listenAddrs.size).to.equal(listenAddresses.length)
expect(listenAddrs.has(listenAddresses[0])).to.equal(true)
expect(listenAddrs.has(listenAddresses[1])).to.equal(true)
})
it('should advertise all addresses if noAnnounce addresses are not provided, but with correct ports', async () => {
[libp2p] = await peerUtils.createPeer({
config: {
...AddressesOptions,
addresses: {
listen: listenAddresses,
announce: announceAddreses
}
}
})
const tmListen = libp2p.transportManager.getAddrs().map((ma) => ma.toString())
const spyAnnounce = sinon.spy(libp2p.addressManager, 'getAnnounceMultiaddrs')
const spyNoAnnounce = sinon.spy(libp2p.addressManager, 'getNoAnnounceMultiaddrs')
const spyListen = sinon.spy(libp2p.addressManager, 'getListenMultiaddrs')
const spyTranspMgr = sinon.spy(libp2p.transportManager, 'getAddrs')
const advertiseMultiaddrs = libp2p.getAdvertisingMultiaddrs().map((ma) => ma.toString())
expect(spyAnnounce).to.have.property('callCount', 1)
expect(spyNoAnnounce).to.have.property('callCount', 1)
expect(spyListen).to.have.property('callCount', 0) // Listen addr should not be used
expect(spyTranspMgr).to.have.property('callCount', 1)
// Announce 2 listen (transport) + 1 announce
expect(advertiseMultiaddrs.length).to.equal(3)
tmListen.forEach((m) => {
expect(advertiseMultiaddrs).to.include(m)
})
announceAddreses.forEach((m) => {
expect(advertiseMultiaddrs).to.include(m)
})
expect(advertiseMultiaddrs).to.not.include(listenAddresses[0]) // Random Port switch
})
it('should remove replicated addresses', async () => {
[libp2p] = await peerUtils.createPeer({
config: {
...AddressesOptions,
addresses: {
listen: listenAddresses,
announce: [listenAddresses[1]]
}
}
})
const advertiseMultiaddrs = libp2p.getAdvertisingMultiaddrs().map((ma) => ma.toString())
// Announce 2 listen (transport), ignoring duplicated in announce
expect(advertiseMultiaddrs.length).to.equal(2)
})
it('should not advertise noAnnounce addresses', async () => {
const noAnnounce = [listenAddresses[1]]
;[libp2p] = await peerUtils.createPeer({
config: {
...AddressesOptions,
addresses: {
listen: listenAddresses,
announce: announceAddreses,
noAnnounce
}
}
})
const advertiseMultiaddrs = libp2p.getAdvertisingMultiaddrs().map((ma) => ma.toString())
// Announce 1 listen (transport) not in the noAnnounce and the announce
expect(advertiseMultiaddrs.length).to.equal(2)
announceAddreses.forEach((m) => {
expect(advertiseMultiaddrs).to.include(m)
})
noAnnounce.forEach((m) => {
expect(advertiseMultiaddrs).to.not.include(m)
})
})
it('should not advertise noAnnounce addresses with random port switch', async () => {
const noAnnounce = [listenAddresses[0]]
;[libp2p] = await peerUtils.createPeer({
config: {
...AddressesOptions,
addresses: {
listen: listenAddresses,
announce: announceAddreses,
noAnnounce
}
}
})
const advertiseMultiaddrs = libp2p.getAdvertisingMultiaddrs().map((ma) => ma.toString())
// Announce 1 listen (transport) not in the noAnnounce and the announce
expect(advertiseMultiaddrs.length).to.equal(2)
announceAddreses.forEach((m) => {
expect(advertiseMultiaddrs).to.include(m)
})
noAnnounce.forEach((m) => {
expect(advertiseMultiaddrs).to.not.include(m)
})
})
})

16
test/addresses/utils.js Normal file
View File

@ -0,0 +1,16 @@
'use strict'
const Transport1 = require('libp2p-tcp')
const Transport2 = require('libp2p-websockets')
const mergeOptions = require('merge-options')
const baseOptions = require('../utils/base-options')
module.exports.baseOptions = baseOptions
const AddressesOptions = mergeOptions(baseOptions, {
modules: {
transport: [Transport1, Transport2]
}
})
module.exports.AddressesOptions = AddressesOptions

View File

@ -38,7 +38,7 @@ describe('Listening', () => {
await libp2p.start()
const addrs = libp2p.addresses.listen
const addrs = libp2p.transportManager.getAddrs()
// Should get something like:
// /ip4/127.0.0.1/tcp/50866

View File

@ -21,8 +21,8 @@ describe('ping', () => {
config: baseOptions
})
nodes[0].peerStore.addressBook.set(nodes[1].peerId, nodes[1].addresses.listen)
nodes[1].peerStore.addressBook.set(nodes[0].peerId, nodes[0].addresses.listen)
nodes[0].peerStore.addressBook.set(nodes[1].peerId, nodes[1].getAdvertisingMultiaddrs())
nodes[1].peerStore.addressBook.set(nodes[0].peerId, nodes[0].getAdvertisingMultiaddrs())
})
it('ping once from peer0 to peer1', async () => {

View File

@ -22,6 +22,7 @@ const { AbortError } = require('libp2p-interfaces/src/transport/errors')
const Libp2p = require('../../src')
const Dialer = require('../../src/dialer')
const AddressManager = require('../../src/address-manager')
const PeerStore = require('../../src/peer-store')
const TransportManager = require('../../src/transport-manager')
const { codes: ErrorCodes } = require('../../src/errors')
@ -47,7 +48,9 @@ describe('Dialing (direct, TCP)', () => {
PeerId.createFromJSON(Peers[0])
])
remoteTM = new TransportManager({
libp2p: {},
libp2p: {
addressManager: new AddressManager({ listen: [listenAddr] })
},
upgrader: mockUpgrader
})
remoteTM.add(Transport.prototype[Symbol.toStringTag], Transport)
@ -279,7 +282,7 @@ describe('Dialing (direct, TCP)', () => {
})
sinon.spy(libp2p.dialer, 'connectToPeer')
libp2p.peerStore.addressBook.set(remotePeerId, remoteLibp2p.addresses.listen)
libp2p.peerStore.addressBook.set(remotePeerId, remoteLibp2p.getAdvertisingMultiaddrs())
const connection = await libp2p.dial(remotePeerId)
expect(connection).to.exist()
@ -361,7 +364,7 @@ describe('Dialing (direct, TCP)', () => {
const fullAddress = remoteAddr.encapsulate(`/p2p/${remoteLibp2p.peerId.toB58String()}`)
libp2p.peerStore.addressBook.set(remotePeerId, remoteLibp2p.addresses.listen)
libp2p.peerStore.addressBook.set(remotePeerId, remoteLibp2p.getAdvertisingMultiaddrs())
const dialResults = await Promise.all([...new Array(dials)].map((_, index) => {
if (index % 2 === 0) return libp2p.dial(remoteLibp2p.peerId)
return libp2p.dial(fullAddress)
@ -391,7 +394,7 @@ describe('Dialing (direct, TCP)', () => {
const error = new Error('Boom')
sinon.stub(libp2p.transportManager, 'dial').callsFake(() => Promise.reject(error))
libp2p.peerStore.addressBook.set(remotePeerId, remoteLibp2p.addresses.listen)
libp2p.peerStore.addressBook.set(remotePeerId, remoteLibp2p.getAdvertisingMultiaddrs())
const dialResults = await pSettle([...new Array(dials)].map((_, index) => {
if (index % 2 === 0) return libp2p.dial(remoteLibp2p.peerId)
return libp2p.dial(remoteAddr)

View File

@ -395,7 +395,7 @@ describe('Dialing (direct, WebSockets)', () => {
it('should be able to use hangup when no connection exists', async () => {
libp2p = new Libp2p({
peerInfo,
peerId,
modules: {
transport: [Transport],
streamMuxer: [Muxer],

View File

@ -6,6 +6,7 @@ const chai = require('chai')
chai.use(require('dirty-chai'))
chai.use(require('chai-as-promised'))
const { expect } = chai
const sinon = require('sinon')
const multiaddr = require('multiaddr')
const { collect } = require('streaming-iterables')
@ -25,7 +26,7 @@ describe('Dialing (via relay, TCP)', () => {
let relayLibp2p
let dstLibp2p
before(async () => {
beforeEach(async () => {
const peerIds = await createPeerId({ number: 3 })
// Create 3 nodes, and turn HOP on for the relay
;[srcLibp2p, relayLibp2p, dstLibp2p] = peerIds.map((peerId, index) => {
@ -69,7 +70,9 @@ describe('Dialing (via relay, TCP)', () => {
.encapsulate(`/p2p-circuit/p2p/${dstLibp2p.peerId.toB58String()}`)
const tcpAddrs = dstLibp2p.transportManager.getAddrs()
await dstLibp2p.transportManager.listen([multiaddr(`/p2p-circuit${relayAddr}/p2p/${relayIdString}`)])
sinon.stub(dstLibp2p.addressManager, 'listen').value([multiaddr(`/p2p-circuit${relayAddr}/p2p/${relayIdString}`)])
await dstLibp2p.transportManager.listen()
expect(dstLibp2p.transportManager.getAddrs()).to.have.deep.members([...tcpAddrs, dialAddr.decapsulate('p2p')])
const connection = await srcLibp2p.dial(dialAddr)
@ -152,13 +155,15 @@ describe('Dialing (via relay, TCP)', () => {
// Connect the destination peer and the relay
const tcpAddrs = dstLibp2p.transportManager.getAddrs()
await dstLibp2p.transportManager.listen([multiaddr(`${relayAddr}/p2p-circuit`)])
sinon.stub(dstLibp2p.addressManager, 'getListenMultiaddrs').returns([multiaddr(`${relayAddr}/p2p-circuit`)])
await dstLibp2p.transportManager.listen()
expect(dstLibp2p.transportManager.getAddrs()).to.have.deep.members([...tcpAddrs, dialAddr.decapsulate('p2p')])
// Tamper with the our multiaddrs for the circuit message
srcLibp2p.addresses.listen = [{
sinon.stub(srcLibp2p.addressManager, 'getListenMultiaddrs').returns([{
buffer: Buffer.from('an invalid multiaddr')
}]
}])
await expect(srcLibp2p.dial(dialAddr))
.to.eventually.be.rejectedWith(AggregateError)

View File

@ -44,28 +44,28 @@ describe('Identify', () => {
it('should be able to identify another peer', async () => {
const localIdentify = new IdentifyService({
peerId: localPeer,
addresses: {
listen: []
},
protocols,
connectionManager: new EventEmitter(),
peerStore: {
addressBook: {
set: () => { }
libp2p: {
peerId: localPeer,
connectionManager: new EventEmitter(),
peerStore: {
addressBook: {
set: () => { }
},
protoBook: {
set: () => { }
}
},
protoBook: {
set: () => { }
}
}
getAdvertisingMultiaddrs: () => []
},
protocols
})
const remoteIdentify = new IdentifyService({
peerId: remotePeer,
addresses: {
listen: []
libp2p: {
peerId: remotePeer,
connectionManager: new EventEmitter(),
getAdvertisingMultiaddrs: () => []
},
protocols,
connectionManager: new EventEmitter()
protocols
})
const observedAddr = multiaddr('/ip4/127.0.0.1/tcp/1234')
@ -97,28 +97,28 @@ describe('Identify', () => {
it('should throw if identified peer is the wrong peer', async () => {
const localIdentify = new IdentifyService({
peerId: localPeer,
addresses: {
listen: []
},
protocols,
connectionManager: new EventEmitter(),
peerStore: {
addressBook: {
set: () => { }
libp2p: {
peerId: localPeer,
connectionManager: new EventEmitter(),
peerStore: {
addressBook: {
set: () => { }
},
protoBook: {
set: () => { }
}
},
protoBook: {
set: () => { }
}
}
getAdvertisingMultiaddrs: () => []
},
protocols
})
const remoteIdentify = new IdentifyService({
peerId: remotePeer,
addresses: {
listen: []
libp2p: {
peerId: remotePeer,
connectionManager: new EventEmitter(),
getAdvertisingMultiaddrs: () => []
},
protocols,
connectionManager: new EventEmitter()
protocols
})
const observedAddr = multiaddr('/ip4/127.0.0.1/tcp/1234')
@ -150,11 +150,11 @@ describe('Identify', () => {
connectionManager.getConnection = () => {}
const localIdentify = new IdentifyService({
peerId: localPeer,
addresses: {
listen: [listeningAddr]
libp2p: {
peerId: localPeer,
connectionManager: new EventEmitter(),
getAdvertisingMultiaddrs: () => [listeningAddr]
},
connectionManager,
protocols: new Map([
[multicodecs.IDENTIFY],
[multicodecs.IDENTIFY_PUSH],
@ -162,18 +162,18 @@ describe('Identify', () => {
])
})
const remoteIdentify = new IdentifyService({
peerId: remotePeer,
addresses: {
listen: []
},
connectionManager,
peerStore: {
addressBook: {
set: () => { }
libp2p: {
peerId: remotePeer,
connectionManager,
peerStore: {
addressBook: {
set: () => { }
},
protoBook: {
set: () => { }
}
},
protoBook: {
set: () => { }
}
getAdvertisingMultiaddrs: () => []
}
})

View File

@ -33,7 +33,7 @@ describe('peer discovery scenarios', () => {
})
it('should ignore self on discovery', async () => {
libp2p = new Libp2p(mergeOptions(baseOptions, {
peerInfo,
peerId,
modules: {
peerDiscovery: [MulticastDNS]
}
@ -42,7 +42,7 @@ describe('peer discovery scenarios', () => {
await libp2p.start()
const discoverySpy = sinon.spy()
libp2p.on('peer:discovery', discoverySpy)
libp2p._discovery.get('mdns').emit('peer', libp2p.peerInfo)
libp2p._discovery.get('mdns').emit('peer', { id: libp2p.peerId })
expect(discoverySpy.called).to.eql(false)
})
@ -193,8 +193,8 @@ describe('peer discovery scenarios', () => {
remoteLibp2p2.start()
])
libp2p.peerStore.addressBook.set(remotePeerId1, remoteLibp2p1.addresses.listen)
remoteLibp2p2.peerStore.addressBook.set(remotePeerId1, remoteLibp2p1.addresses.listen)
libp2p.peerStore.addressBook.set(remotePeerId1, remoteLibp2p1.getAdvertisingMultiaddrs())
remoteLibp2p2.peerStore.addressBook.set(remotePeerId1, remoteLibp2p1.getAdvertisingMultiaddrs())
// Topology:
// A -> B

View File

@ -75,7 +75,7 @@ describe('Pubsub subsystem is able to use different implementations', () => {
])
const libp2pId = libp2p.peerId.toB58String()
libp2p.peerStore.addressBook.set(remotePeerId, remoteLibp2p.addresses.listen)
libp2p.peerStore.addressBook.set(remotePeerId, remoteLibp2p.getAdvertisingMultiaddrs())
const connection = await libp2p.dialProtocol(remotePeerId, multicodec)
expect(connection).to.exist()

View File

@ -47,7 +47,7 @@ describe('Pubsub subsystem operates correctly', () => {
remoteLibp2p.start()
])
libp2p.peerStore.addressBook.set(remotePeerId, remoteLibp2p.addresses.listen)
libp2p.peerStore.addressBook.set(remotePeerId, remoteLibp2p.getAdvertisingMultiaddrs())
})
afterEach(() => Promise.all([
@ -124,7 +124,7 @@ describe('Pubsub subsystem operates correctly', () => {
await libp2p.start()
await remoteLibp2p.start()
libp2p.peerStore.addressBook.set(remotePeerId, remoteLibp2p.addresses.listen)
libp2p.peerStore.addressBook.set(remotePeerId, remoteLibp2p.getAdvertisingMultiaddrs())
})
afterEach(() => Promise.all([

View File

@ -4,6 +4,8 @@
const chai = require('chai')
chai.use(require('dirty-chai'))
const { expect } = chai
const AddressManager = require('../../src/address-manager')
const TransportManager = require('../../src/transport-manager')
const Transport = require('libp2p-tcp')
const multiaddr = require('multiaddr')
@ -18,7 +20,9 @@ describe('Transport Manager (TCP)', () => {
before(() => {
tm = new TransportManager({
libp2p: {},
libp2p: {
addressManager: new AddressManager({ listen: addrs })
},
upgrader: mockUpgrader,
onConnection: () => {}
})
@ -37,7 +41,7 @@ describe('Transport Manager (TCP)', () => {
it('should be able to listen', async () => {
tm.add(Transport.prototype[Symbol.toStringTag], Transport)
await tm.listen(addrs)
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)
// Ephemeral ip addresses may result in multiple listeners
@ -48,7 +52,7 @@ describe('Transport Manager (TCP)', () => {
it('should be able to dial', async () => {
tm.add(Transport.prototype[Symbol.toStringTag], Transport)
await tm.listen(addrs)
await tm.listen()
const addr = tm.getAddrs().shift()
const connection = await tm.dial(addr)
expect(connection).to.exist()

View File

@ -9,6 +9,7 @@ const sinon = require('sinon')
const multiaddr = require('multiaddr')
const Transport = require('libp2p-websockets')
const AddressManager = require('../../src/address-manager')
const TransportManager = require('../../src/transport-manager')
const mockUpgrader = require('../utils/mockUpgrader')
const { MULTIADDRS_WEBSOCKETS } = require('../fixtures/browser')
@ -17,12 +18,16 @@ const Libp2p = require('../../src')
const Peers = require('../fixtures/peers')
const PeerId = require('peer-id')
const listenAddr = multiaddr('/ip4/127.0.0.1/tcp/0')
describe('Transport Manager (WebSockets)', () => {
let tm
before(() => {
tm = new TransportManager({
libp2p: {},
libp2p: {
addressManager: new AddressManager({ listen: [listenAddr] })
},
upgrader: mockUpgrader,
onConnection: () => {}
})
@ -78,9 +83,8 @@ describe('Transport Manager (WebSockets)', () => {
it('should fail to listen with no valid address', async () => {
tm.add(Transport.prototype[Symbol.toStringTag], Transport)
const addrs = [multiaddr('/ip4/127.0.0.1/tcp/0')]
await expect(tm.listen(addrs))
await expect(tm.listen())
.to.eventually.be.rejected()
.and.to.have.property('code', ErrorCodes.ERR_NO_VALID_ADDRESSES)
})

View File

@ -21,13 +21,14 @@ const listenAddr = multiaddr('/ip4/127.0.0.1/tcp/0')
* @param {boolean} [properties.populateAddressBooks] nodes addressBooks should be populated with other peers (default: true)
* @return {Promise<Array<Libp2p>>}
*/
async function createPeer ({ number = 1, fixture = true, started = true, populateAddressBooks = true, config = defaultOptions } = {}) {
async function createPeer ({ number = 1, fixture = true, started = true, populateAddressBooks = true, config = {} } = {}) {
const peerIds = await createPeerId({ number, fixture })
const addresses = started ? { listen: [listenAddr] } : {}
const peers = await pTimes(number, (i) => Libp2p.create({
peerId: peerIds[i],
addresses,
...defaultOptions,
...config
}))
@ -44,7 +45,7 @@ function _populateAddressBooks (peers) {
for (let i = 0; i < peers.length; i++) {
for (let j = 0; j < peers.length; j++) {
if (i !== j) {
peers[i].peerStore.addressBook.set(peers[j].peerId, peers[j].addresses.listen)
peers[i].peerStore.addressBook.set(peers[j].peerId, peers[j].getAdvertisingMultiaddrs())
}
}
}