mirror of
https://github.com/fluencelabs/js-libp2p
synced 2025-04-25 02:22:14 +00:00
fix: not dial all known peers in parallel on startup (#698)
* fix: not dial all known peers on startup * feat: connection manager should proactively connect to peers from peerStore * chore: increase bundle size * fix: do connMgr proactive dial on an interval * chore: address review * chore: use retimer reschedule * chore: address review * fix: use minConnections in default config * chore: minPeers to minConnections everywhere
This commit is contained in:
parent
619e5dd73c
commit
9ccab40fc8
@ -45,7 +45,7 @@ const after = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
bundlesize: { maxSize: '200kB' },
|
bundlesize: { maxSize: '202kB' },
|
||||||
hooks: {
|
hooks: {
|
||||||
pre: before,
|
pre: before,
|
||||||
post: after
|
post: after
|
||||||
|
@ -270,7 +270,7 @@ const node = await Libp2p.create({
|
|||||||
},
|
},
|
||||||
config: {
|
config: {
|
||||||
peerDiscovery: {
|
peerDiscovery: {
|
||||||
autoDial: true, // Auto connect to discovered peers (limited by ConnectionManager minPeers)
|
autoDial: true, // Auto connect to discovered peers (limited by ConnectionManager minConnections)
|
||||||
// The `tag` property will be searched when creating the instance of your Peer Discovery service.
|
// The `tag` property will be searched when creating the instance of your Peer Discovery service.
|
||||||
// The associated object, will be passed to the service when it is instantiated.
|
// The associated object, will be passed to the service when it is instantiated.
|
||||||
[MulticastDNS.tag]: {
|
[MulticastDNS.tag]: {
|
||||||
|
@ -217,7 +217,7 @@ const node = await Libp2p.create({
|
|||||||
},
|
},
|
||||||
config: {
|
config: {
|
||||||
peerDiscovery: {
|
peerDiscovery: {
|
||||||
autoDial: true, // Auto connect to discovered peers (limited by ConnectionManager minPeers)
|
autoDial: true, // Auto connect to discovered peers (limited by ConnectionManager minConnections)
|
||||||
// The `tag` property will be searched when creating the instance of your Peer Discovery service.
|
// The `tag` property will be searched when creating the instance of your Peer Discovery service.
|
||||||
// The associated object, will be passed to the service when it is instantiated.
|
// The associated object, will be passed to the service when it is instantiated.
|
||||||
[Bootstrap.tag]: {
|
[Bootstrap.tag]: {
|
||||||
|
@ -12,7 +12,7 @@ const DefaultConfig = {
|
|||||||
noAnnounce: []
|
noAnnounce: []
|
||||||
},
|
},
|
||||||
connectionManager: {
|
connectionManager: {
|
||||||
minPeers: 25
|
minConnections: 25
|
||||||
},
|
},
|
||||||
transportManager: {
|
transportManager: {
|
||||||
faultTolerance: FaultTolerance.FATAL_ALL
|
faultTolerance: FaultTolerance.FATAL_ALL
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
|
const debug = require('debug')
|
||||||
|
const log = debug('libp2p:connection-manager')
|
||||||
|
log.error = debug('libp2p:connection-manager:error')
|
||||||
|
|
||||||
const errcode = require('err-code')
|
const errcode = require('err-code')
|
||||||
const mergeOptions = require('merge-options')
|
const mergeOptions = require('merge-options')
|
||||||
const LatencyMonitor = require('./latency-monitor')
|
const LatencyMonitor = require('./latency-monitor')
|
||||||
const debug = require('debug')('libp2p:connection-manager')
|
|
||||||
const retimer = require('retimer')
|
const retimer = require('retimer')
|
||||||
|
|
||||||
const { EventEmitter } = require('events')
|
const { EventEmitter } = require('events')
|
||||||
@ -22,6 +25,7 @@ const defaultOptions = {
|
|||||||
maxReceivedData: Infinity,
|
maxReceivedData: Infinity,
|
||||||
maxEventLoopDelay: Infinity,
|
maxEventLoopDelay: Infinity,
|
||||||
pollInterval: 2000,
|
pollInterval: 2000,
|
||||||
|
autoDialInterval: 10000,
|
||||||
movingAverageInterval: 60000,
|
movingAverageInterval: 60000,
|
||||||
defaultPeerValue: 1
|
defaultPeerValue: 1
|
||||||
}
|
}
|
||||||
@ -45,6 +49,8 @@ class ConnectionManager extends EventEmitter {
|
|||||||
* @param {Number} options.pollInterval How often, in milliseconds, metrics and latency should be checked. Default=2000
|
* @param {Number} options.pollInterval How often, in milliseconds, metrics and latency should be checked. Default=2000
|
||||||
* @param {Number} options.movingAverageInterval How often, in milliseconds, to compute averages. Default=60000
|
* @param {Number} options.movingAverageInterval How often, in milliseconds, to compute averages. Default=60000
|
||||||
* @param {Number} options.defaultPeerValue The value of the peer. Default=1
|
* @param {Number} options.defaultPeerValue The value of the peer. Default=1
|
||||||
|
* @param {boolean} options.autoDial Should preemptively guarantee connections are above the low watermark. Default=true
|
||||||
|
* @param {Number} options.autoDialInterval How often, in milliseconds, it should preemptively guarantee connections are above the low watermark. Default=10000
|
||||||
*/
|
*/
|
||||||
constructor (libp2p, options) {
|
constructor (libp2p, options) {
|
||||||
super()
|
super()
|
||||||
@ -57,7 +63,7 @@ class ConnectionManager extends EventEmitter {
|
|||||||
throw errcode(new Error('Connection Manager maxConnections must be greater than minConnections'), ERR_INVALID_PARAMETERS)
|
throw errcode(new Error('Connection Manager maxConnections must be greater than minConnections'), ERR_INVALID_PARAMETERS)
|
||||||
}
|
}
|
||||||
|
|
||||||
debug('options: %j', this._options)
|
log('options: %j', this._options)
|
||||||
|
|
||||||
this._libp2p = libp2p
|
this._libp2p = libp2p
|
||||||
|
|
||||||
@ -73,8 +79,11 @@ class ConnectionManager extends EventEmitter {
|
|||||||
*/
|
*/
|
||||||
this.connections = new Map()
|
this.connections = new Map()
|
||||||
|
|
||||||
|
this._started = false
|
||||||
this._timer = null
|
this._timer = null
|
||||||
|
this._autoDialTimeout = null
|
||||||
this._checkMetrics = this._checkMetrics.bind(this)
|
this._checkMetrics = this._checkMetrics.bind(this)
|
||||||
|
this._autoDial = this._autoDial.bind(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -101,7 +110,11 @@ class ConnectionManager extends EventEmitter {
|
|||||||
})
|
})
|
||||||
this._onLatencyMeasure = this._onLatencyMeasure.bind(this)
|
this._onLatencyMeasure = this._onLatencyMeasure.bind(this)
|
||||||
this._latencyMonitor.on('data', this._onLatencyMeasure)
|
this._latencyMonitor.on('data', this._onLatencyMeasure)
|
||||||
debug('started')
|
|
||||||
|
this._started = true
|
||||||
|
log('started')
|
||||||
|
|
||||||
|
this._options.autoDial && this._autoDial()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -109,11 +122,13 @@ class ConnectionManager extends EventEmitter {
|
|||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
async stop () {
|
async stop () {
|
||||||
|
this._autoDialTimeout && this._autoDialTimeout.clear()
|
||||||
this._timer && this._timer.clear()
|
this._timer && this._timer.clear()
|
||||||
this._latencyMonitor && this._latencyMonitor.removeListener('data', this._onLatencyMeasure)
|
this._latencyMonitor && this._latencyMonitor.removeListener('data', this._onLatencyMeasure)
|
||||||
|
|
||||||
|
this._started = false
|
||||||
await this._close()
|
await this._close()
|
||||||
debug('stopped')
|
log('stopped')
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -157,12 +172,12 @@ class ConnectionManager extends EventEmitter {
|
|||||||
_checkMetrics () {
|
_checkMetrics () {
|
||||||
const movingAverages = this._libp2p.metrics.global.movingAverages
|
const movingAverages = this._libp2p.metrics.global.movingAverages
|
||||||
const received = movingAverages.dataReceived[this._options.movingAverageInterval].movingAverage()
|
const received = movingAverages.dataReceived[this._options.movingAverageInterval].movingAverage()
|
||||||
this._checkLimit('maxReceivedData', received)
|
this._checkMaxLimit('maxReceivedData', received)
|
||||||
const sent = movingAverages.dataSent[this._options.movingAverageInterval].movingAverage()
|
const sent = movingAverages.dataSent[this._options.movingAverageInterval].movingAverage()
|
||||||
this._checkLimit('maxSentData', sent)
|
this._checkMaxLimit('maxSentData', sent)
|
||||||
const total = received + sent
|
const total = received + sent
|
||||||
this._checkLimit('maxData', total)
|
this._checkMaxLimit('maxData', total)
|
||||||
debug('metrics update', total)
|
log('metrics update', total)
|
||||||
this._timer.reschedule(this._options.pollInterval)
|
this._timer.reschedule(this._options.pollInterval)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,7 +203,7 @@ class ConnectionManager extends EventEmitter {
|
|||||||
this._peerValues.set(peerIdStr, this._options.defaultPeerValue)
|
this._peerValues.set(peerIdStr, this._options.defaultPeerValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
this._checkLimit('maxConnections', this.size)
|
this._checkMaxLimit('maxConnections', this.size)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -248,7 +263,7 @@ class ConnectionManager extends EventEmitter {
|
|||||||
* @param {*} summary The LatencyMonitor summary
|
* @param {*} summary The LatencyMonitor summary
|
||||||
*/
|
*/
|
||||||
_onLatencyMeasure (summary) {
|
_onLatencyMeasure (summary) {
|
||||||
this._checkLimit('maxEventLoopDelay', summary.avgMs)
|
this._checkMaxLimit('maxEventLoopDelay', summary.avgMs)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -257,15 +272,69 @@ class ConnectionManager extends EventEmitter {
|
|||||||
* @param {string} name The name of the field to check limits for
|
* @param {string} name The name of the field to check limits for
|
||||||
* @param {number} value The current value of the field
|
* @param {number} value The current value of the field
|
||||||
*/
|
*/
|
||||||
_checkLimit (name, value) {
|
_checkMaxLimit (name, value) {
|
||||||
const limit = this._options[name]
|
const limit = this._options[name]
|
||||||
debug('checking limit of %s. current value: %d of %d', name, value, limit)
|
log('checking limit of %s. current value: %d of %d', name, value, limit)
|
||||||
if (value > limit) {
|
if (value > limit) {
|
||||||
debug('%s: limit exceeded: %s, %d', this._peerId, name, value)
|
log('%s: limit exceeded: %s, %d', this._peerId, name, value)
|
||||||
this._maybeDisconnectOne()
|
this._maybeDisconnectOne()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Proactively tries to connect to known peers stored in the PeerStore.
|
||||||
|
* It will keep the number of connections below the upper limit and sort
|
||||||
|
* the peers to connect based on wether we know their keys and protocols.
|
||||||
|
* @async
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
async _autoDial () {
|
||||||
|
const minConnections = this._options.minConnections
|
||||||
|
|
||||||
|
const recursiveTimeoutTrigger = () => {
|
||||||
|
if (this._autoDialTimeout) {
|
||||||
|
this._autoDialTimeout.reschedule(this._options.autoDialInterval)
|
||||||
|
} else {
|
||||||
|
this._autoDialTimeout = retimer(this._autoDial, this._options.autoDialInterval)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Already has enough connections
|
||||||
|
if (this.size >= minConnections) {
|
||||||
|
recursiveTimeoutTrigger()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort peers on wether we know protocols of public keys for them
|
||||||
|
const peers = Array.from(this._libp2p.peerStore.peers.values())
|
||||||
|
.sort((a, b) => {
|
||||||
|
if (b.protocols && b.protocols.length && (!a.protocols || !a.protocols.length)) {
|
||||||
|
return 1
|
||||||
|
} else if (b.id.pubKey && !a.id.pubKey) {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
})
|
||||||
|
|
||||||
|
for (let i = 0; i < peers.length && this.size < minConnections; i++) {
|
||||||
|
if (!this.get(peers[i].id)) {
|
||||||
|
log('connecting to a peerStore stored peer %s', peers[i].id.toB58String())
|
||||||
|
try {
|
||||||
|
await this._libp2p.dialer.connectToPeer(peers[i].id)
|
||||||
|
|
||||||
|
// Connection Manager was stopped
|
||||||
|
if (!this._started) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
log.error('could not connect to peerStore stored peer', err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
recursiveTimeoutTrigger()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If we have more connections than our maximum, close a connection
|
* If we have more connections than our maximum, close a connection
|
||||||
* to the lowest valued peer.
|
* to the lowest valued peer.
|
||||||
@ -274,12 +343,12 @@ class ConnectionManager extends EventEmitter {
|
|||||||
_maybeDisconnectOne () {
|
_maybeDisconnectOne () {
|
||||||
if (this._options.minConnections < this.connections.size) {
|
if (this._options.minConnections < this.connections.size) {
|
||||||
const peerValues = Array.from(this._peerValues).sort(byPeerValue)
|
const peerValues = Array.from(this._peerValues).sort(byPeerValue)
|
||||||
debug('%s: sorted peer values: %j', this._peerId, peerValues)
|
log('%s: sorted peer values: %j', this._peerId, peerValues)
|
||||||
const disconnectPeer = peerValues[0]
|
const disconnectPeer = peerValues[0]
|
||||||
if (disconnectPeer) {
|
if (disconnectPeer) {
|
||||||
const peerId = disconnectPeer[0]
|
const peerId = disconnectPeer[0]
|
||||||
debug('%s: lowest value peer is %s', this._peerId, peerId)
|
log('%s: lowest value peer is %s', this._peerId, peerId)
|
||||||
debug('%s: closing a connection to %j', this._peerId, peerId)
|
log('%s: closing a connection to %j', this._peerId, peerId)
|
||||||
for (const connections of this.connections.values()) {
|
for (const connections of this.connections.values()) {
|
||||||
if (connections[0].remotePeer.toB58String() === peerId) {
|
if (connections[0].remotePeer.toB58String() === peerId) {
|
||||||
connections[0].close()
|
connections[0].close()
|
||||||
|
22
src/index.js
22
src/index.js
@ -65,7 +65,13 @@ class Libp2p extends EventEmitter {
|
|||||||
this._discovery = new Map() // Discovery service instances/references
|
this._discovery = new Map() // Discovery service instances/references
|
||||||
|
|
||||||
// Create the Connection Manager
|
// Create the Connection Manager
|
||||||
this.connectionManager = new ConnectionManager(this, this._options.connectionManager)
|
if (this._options.connectionManager.minPeers) { // Remove in 0.29
|
||||||
|
this._options.connectionManager.minConnections = this._options.connectionManager.minPeers
|
||||||
|
}
|
||||||
|
this.connectionManager = new ConnectionManager(this, {
|
||||||
|
autoDial: this._config.peerDiscovery.autoDial,
|
||||||
|
...this._options.connectionManager
|
||||||
|
})
|
||||||
|
|
||||||
// Create Metrics
|
// Create Metrics
|
||||||
if (this._options.metrics.enabled) {
|
if (this._options.metrics.enabled) {
|
||||||
@ -460,19 +466,19 @@ class Libp2p extends EventEmitter {
|
|||||||
async _onDidStart () {
|
async _onDidStart () {
|
||||||
this._isStarted = true
|
this._isStarted = true
|
||||||
|
|
||||||
this.connectionManager.start()
|
|
||||||
|
|
||||||
this.peerStore.on('peer', peerId => {
|
this.peerStore.on('peer', peerId => {
|
||||||
this.emit('peer:discovery', peerId)
|
this.emit('peer:discovery', peerId)
|
||||||
this._maybeConnect(peerId)
|
this._maybeConnect(peerId)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Once we start, emit and dial any peers we may have already discovered
|
// Once we start, emit any peers we may have already discovered
|
||||||
|
// TODO: this should be removed, as we already discovered these peers in the past
|
||||||
for (const peer of this.peerStore.peers.values()) {
|
for (const peer of this.peerStore.peers.values()) {
|
||||||
this.emit('peer:discovery', peer.id)
|
this.emit('peer:discovery', peer.id)
|
||||||
this._maybeConnect(peer.id)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.connectionManager.start()
|
||||||
|
|
||||||
// Peer discovery
|
// Peer discovery
|
||||||
await this._setupPeerDiscovery()
|
await this._setupPeerDiscovery()
|
||||||
}
|
}
|
||||||
@ -496,15 +502,15 @@ class Libp2p extends EventEmitter {
|
|||||||
/**
|
/**
|
||||||
* Will dial to the given `peerId` if the current number of
|
* Will dial to the given `peerId` if the current number of
|
||||||
* connected peers is less than the configured `ConnectionManager`
|
* connected peers is less than the configured `ConnectionManager`
|
||||||
* minPeers.
|
* minConnections.
|
||||||
* @private
|
* @private
|
||||||
* @param {PeerId} peerId
|
* @param {PeerId} peerId
|
||||||
*/
|
*/
|
||||||
async _maybeConnect (peerId) {
|
async _maybeConnect (peerId) {
|
||||||
// If auto dialing is on and we have no connection to the peer, check if we should dial
|
// If auto dialing is on and we have no connection to the peer, check if we should dial
|
||||||
if (this._config.peerDiscovery.autoDial === true && !this.connectionManager.get(peerId)) {
|
if (this._config.peerDiscovery.autoDial === true && !this.connectionManager.get(peerId)) {
|
||||||
const minPeers = this._options.connectionManager.minPeers || 0
|
const minConnections = this._options.connectionManager.minConnections || 0
|
||||||
if (minPeers > this.connectionManager.size) {
|
if (minConnections > this.connectionManager.size) {
|
||||||
log('connecting to discovered peer %s', peerId.toB58String())
|
log('connecting to discovered peer %s', peerId.toB58String())
|
||||||
try {
|
try {
|
||||||
await this.dialer.connectToPeer(peerId)
|
await this.dialer.connectToPeer(peerId)
|
||||||
|
@ -7,6 +7,9 @@ chai.use(require('chai-as-promised'))
|
|||||||
const { expect } = chai
|
const { expect } = chai
|
||||||
const sinon = require('sinon')
|
const sinon = require('sinon')
|
||||||
|
|
||||||
|
const delay = require('delay')
|
||||||
|
const pWaitFor = require('p-wait-for')
|
||||||
|
|
||||||
const peerUtils = require('../utils/creators/peer')
|
const peerUtils = require('../utils/creators/peer')
|
||||||
const mockConnection = require('../utils/mockConnection')
|
const mockConnection = require('../utils/mockConnection')
|
||||||
const baseOptions = require('../utils/base-options.browser')
|
const baseOptions = require('../utils/base-options.browser')
|
||||||
@ -112,4 +115,148 @@ describe('libp2p.connections', () => {
|
|||||||
await libp2p.stop()
|
await libp2p.stop()
|
||||||
await remoteLibp2p.stop()
|
await remoteLibp2p.stop()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('proactive connections', () => {
|
||||||
|
let nodes = []
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
nodes = await peerUtils.createPeer({
|
||||||
|
number: 2,
|
||||||
|
config: {
|
||||||
|
addresses: {
|
||||||
|
listen: ['/ip4/127.0.0.1/tcp/0/ws']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
await Promise.all(nodes.map((node) => node.stop()))
|
||||||
|
sinon.reset()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should connect to all the peers stored in the PeerStore, if their number is below minConnections', async () => {
|
||||||
|
const [libp2p] = await peerUtils.createPeer({
|
||||||
|
fixture: false,
|
||||||
|
started: false,
|
||||||
|
config: {
|
||||||
|
addresses: {
|
||||||
|
listen: ['/ip4/127.0.0.1/tcp/0/ws']
|
||||||
|
},
|
||||||
|
connectionManager: {
|
||||||
|
minConnections: 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Populate PeerStore before starting
|
||||||
|
libp2p.peerStore.addressBook.set(nodes[0].peerId, nodes[0].multiaddrs)
|
||||||
|
libp2p.peerStore.addressBook.set(nodes[1].peerId, nodes[1].multiaddrs)
|
||||||
|
|
||||||
|
await libp2p.start()
|
||||||
|
|
||||||
|
// Wait for peers to connect
|
||||||
|
await pWaitFor(() => libp2p.connectionManager.size === 2)
|
||||||
|
|
||||||
|
await libp2p.stop()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should connect to all the peers stored in the PeerStore until reaching the minConnections', async () => {
|
||||||
|
const minConnections = 1
|
||||||
|
const [libp2p] = await peerUtils.createPeer({
|
||||||
|
fixture: false,
|
||||||
|
started: false,
|
||||||
|
config: {
|
||||||
|
addresses: {
|
||||||
|
listen: ['/ip4/127.0.0.1/tcp/0/ws']
|
||||||
|
},
|
||||||
|
connectionManager: {
|
||||||
|
minConnections
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Populate PeerStore before starting
|
||||||
|
libp2p.peerStore.addressBook.set(nodes[0].peerId, nodes[0].multiaddrs)
|
||||||
|
libp2p.peerStore.addressBook.set(nodes[1].peerId, nodes[1].multiaddrs)
|
||||||
|
|
||||||
|
await libp2p.start()
|
||||||
|
|
||||||
|
// Wait for peer to connect
|
||||||
|
await pWaitFor(() => libp2p.connectionManager.size === minConnections)
|
||||||
|
|
||||||
|
// Wait more time to guarantee no other connection happened
|
||||||
|
await delay(200)
|
||||||
|
expect(libp2p.connectionManager.size).to.eql(minConnections)
|
||||||
|
|
||||||
|
await libp2p.stop()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should connect to all the peers stored in the PeerStore until reaching the minConnections sorted', async () => {
|
||||||
|
const minConnections = 1
|
||||||
|
const [libp2p] = await peerUtils.createPeer({
|
||||||
|
fixture: false,
|
||||||
|
started: false,
|
||||||
|
config: {
|
||||||
|
addresses: {
|
||||||
|
listen: ['/ip4/127.0.0.1/tcp/0/ws']
|
||||||
|
},
|
||||||
|
connectionManager: {
|
||||||
|
minConnections
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Populate PeerStore before starting
|
||||||
|
libp2p.peerStore.addressBook.set(nodes[0].peerId, nodes[0].multiaddrs)
|
||||||
|
libp2p.peerStore.addressBook.set(nodes[1].peerId, nodes[1].multiaddrs)
|
||||||
|
libp2p.peerStore.protoBook.set(nodes[1].peerId, ['/protocol-min-conns'])
|
||||||
|
|
||||||
|
await libp2p.start()
|
||||||
|
|
||||||
|
// Wait for peer to connect
|
||||||
|
await pWaitFor(() => libp2p.connectionManager.size === minConnections)
|
||||||
|
|
||||||
|
// Should have connected to the peer with protocols
|
||||||
|
expect(libp2p.connectionManager.get(nodes[0].peerId)).to.not.exist()
|
||||||
|
expect(libp2p.connectionManager.get(nodes[1].peerId)).to.exist()
|
||||||
|
|
||||||
|
await libp2p.stop()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should connect to peers in the PeerStore when a peer disconnected', async () => {
|
||||||
|
const minConnections = 1
|
||||||
|
const autoDialInterval = 1000
|
||||||
|
|
||||||
|
const [libp2p] = await peerUtils.createPeer({
|
||||||
|
fixture: false,
|
||||||
|
config: {
|
||||||
|
addresses: {
|
||||||
|
listen: ['/ip4/127.0.0.1/tcp/0/ws']
|
||||||
|
},
|
||||||
|
connectionManager: {
|
||||||
|
minConnections,
|
||||||
|
autoDialInterval
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Populate PeerStore after starting (discovery)
|
||||||
|
libp2p.peerStore.addressBook.set(nodes[0].peerId, nodes[0].multiaddrs)
|
||||||
|
|
||||||
|
// Wait for peer to connect
|
||||||
|
const conn = await libp2p.dial(nodes[0].peerId)
|
||||||
|
expect(libp2p.connectionManager.get(nodes[0].peerId)).to.exist()
|
||||||
|
|
||||||
|
await conn.close()
|
||||||
|
// Closed
|
||||||
|
await pWaitFor(() => libp2p.connectionManager.size === 0)
|
||||||
|
// Connected
|
||||||
|
await pWaitFor(() => libp2p.connectionManager.size === 1)
|
||||||
|
|
||||||
|
expect(libp2p.connectionManager.get(nodes[0].peerId)).to.exist()
|
||||||
|
|
||||||
|
await libp2p.stop()
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
@ -58,7 +58,8 @@ describe('Connection Manager', () => {
|
|||||||
config: {
|
config: {
|
||||||
modules: baseOptions.modules,
|
modules: baseOptions.modules,
|
||||||
connectionManager: {
|
connectionManager: {
|
||||||
maxConnections: max
|
maxConnections: max,
|
||||||
|
minConnections: 2
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
started: false
|
started: false
|
||||||
@ -96,7 +97,8 @@ describe('Connection Manager', () => {
|
|||||||
config: {
|
config: {
|
||||||
modules: baseOptions.modules,
|
modules: baseOptions.modules,
|
||||||
connectionManager: {
|
connectionManager: {
|
||||||
maxConnections: max
|
maxConnections: max,
|
||||||
|
minConnections: 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
started: false
|
started: false
|
||||||
|
@ -31,10 +31,13 @@ describe('peer discovery', () => {
|
|||||||
sinon.reset()
|
sinon.reset()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should dial know peers on startup', async () => {
|
it('should dial know peers on startup below the minConnections watermark', async () => {
|
||||||
libp2p = new Libp2p({
|
libp2p = new Libp2p({
|
||||||
...baseOptions,
|
...baseOptions,
|
||||||
peerId
|
peerId,
|
||||||
|
connectionManager: {
|
||||||
|
minConnections: 2
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
libp2p.peerStore.addressBook.set(remotePeerId, [multiaddr('/ip4/165.1.1.1/tcp/80')])
|
libp2p.peerStore.addressBook.set(remotePeerId, [multiaddr('/ip4/165.1.1.1/tcp/80')])
|
||||||
|
Loading…
x
Reference in New Issue
Block a user