mirror of
https://github.com/fluencelabs/js-libp2p
synced 2025-07-30 16:01:59 +00:00
Compare commits
7 Commits
fix/unref-
...
feat/obser
Author | SHA1 | Date | |
---|---|---|---|
|
459d3f24af | ||
|
b1f4e5be4a | ||
|
da4fb5a074 | ||
|
8d3b61710a | ||
|
5dbbeef311 | ||
|
3e7594f697 | ||
|
ce2a624a09 |
@@ -48,7 +48,7 @@ const after = async () => {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
bundlesize: { maxSize: '215kB' },
|
||||
bundlesize: { maxSize: '216kB' },
|
||||
hooks: {
|
||||
pre: before,
|
||||
post: after
|
||||
|
10
CHANGELOG.md
10
CHANGELOG.md
@@ -1,3 +1,13 @@
|
||||
## [0.30.6](https://github.com/libp2p/js-libp2p/compare/v0.30.5...v0.30.6) (2021-01-29)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* peer discovery type in config ([#878](https://github.com/libp2p/js-libp2p/issues/878)) ([3e7594f](https://github.com/libp2p/js-libp2p/commit/3e7594f69733bf374b374a6065458fa6cae81c5f))
|
||||
* unref nat manager retries ([#877](https://github.com/libp2p/js-libp2p/issues/877)) ([ce2a624](https://github.com/libp2p/js-libp2p/commit/ce2a624a09b3107c0b2b4752e666804ecea54fb5))
|
||||
|
||||
|
||||
|
||||
## [0.30.5](https://github.com/libp2p/js-libp2p/compare/v0.30.4...v0.30.5) (2021-01-28)
|
||||
|
||||
|
||||
|
@@ -23,6 +23,7 @@
|
||||
- [Setup with Auto Relay](#setup-with-auto-relay)
|
||||
- [Setup with Keychain](#setup-with-keychain)
|
||||
- [Configuring Dialing](#configuring-dialing)
|
||||
- [Configuring Address Manager](#configuring-address-manager)
|
||||
- [Configuring Connection Manager](#configuring-connection-manager)
|
||||
- [Configuring Transport Manager](#configuring-transport-manager)
|
||||
- [Configuring Metrics](#configuring-metrics)
|
||||
@@ -549,6 +550,26 @@ const node = await Libp2p.create({
|
||||
}
|
||||
```
|
||||
|
||||
#### Configuring Address Manager
|
||||
|
||||
The address manager receives observed addresses from network peers. We accept observed addresses once a certain number of peers have reported the same observed address within a certain window of time.
|
||||
|
||||
```js
|
||||
const node = await Libp2p.create({
|
||||
addressManager: {
|
||||
observedAddresses: {
|
||||
// we must receive the same observed address from this many
|
||||
// peers before we start believe it
|
||||
minConfidence: 4,
|
||||
// an address must reach the minimum level of confidence within
|
||||
// this timeout otherwise it will be ignored
|
||||
maxLifetimeBeforeEviction: (60 * 10) * 1000 // ten minutes in ms
|
||||
}
|
||||
},
|
||||
// ...other options
|
||||
})
|
||||
```
|
||||
|
||||
#### Configuring Connection Manager
|
||||
|
||||
The Connection Manager prunes Connections in libp2p whenever certain limits are exceeded. If Metrics are enabled, you can also configure the Connection Manager to monitor the bandwidth of libp2p and prune connections as needed. You can read more about what Connection Manager does at [./CONNECTION_MANAGER.md](./CONNECTION_MANAGER.md). The configuration values below show the defaults for Connection Manager. See [./CONNECTION_MANAGER.md](./CONNECTION_MANAGER.md#options) for a full description of the parameters.
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "libp2p",
|
||||
"version": "0.30.5",
|
||||
"version": "0.30.6",
|
||||
"description": "JavaScript implementation of libp2p, a modular peer to peer network stack",
|
||||
"leadMaintainer": "Jacob Heun <jacobheun@gmail.com>",
|
||||
"main": "src/index.js",
|
||||
|
@@ -31,14 +31,18 @@ class AddressManager extends EventEmitter {
|
||||
* @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 {object} [options.observedAddresses = { minConfidence: 4, maxLifetimeBeforeEviction: 600000 }] - configuration options for observed addresses
|
||||
*/
|
||||
constructor (peerId, { listen = [], announce = [] } = {}) {
|
||||
constructor (peerId, { listen = [], announce = [], observedAddresses = { minConfidence: 4, maxLifetimeBeforeEviction: (60 * 10) * 1000 } } = {}) {
|
||||
super()
|
||||
|
||||
this.peerId = peerId
|
||||
this.listen = new Set(listen.map(ma => ma.toString()))
|
||||
this.announce = new Set(announce.map(ma => ma.toString()))
|
||||
this.observed = new Set()
|
||||
this.observed = new Map()
|
||||
this.config = {
|
||||
observedAddresses
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,15 +69,25 @@ class AddressManager extends EventEmitter {
|
||||
* @returns {Array<Multiaddr>}
|
||||
*/
|
||||
getObservedAddrs () {
|
||||
return Array.from(this.observed).map((a) => multiaddr(a))
|
||||
const output = []
|
||||
|
||||
this.observed.forEach(({ confidence }, addr) => {
|
||||
if (confidence >= this.config.observedAddresses.minConfidence) {
|
||||
output.push(multiaddr(addr))
|
||||
}
|
||||
})
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
/**
|
||||
* Add peer observed addresses
|
||||
*
|
||||
* @param {string | Multiaddr} addr
|
||||
* @param {PeerId} reporter
|
||||
* @param {number} [confidence=1]
|
||||
*/
|
||||
addObservedAddr (addr) {
|
||||
addObservedAddr (addr, reporter, confidence = 1) {
|
||||
let ma = multiaddr(addr)
|
||||
const remotePeer = ma.getPeerId()
|
||||
|
||||
@@ -87,15 +101,41 @@ class AddressManager extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
const now = Date.now()
|
||||
const addrString = ma.toString()
|
||||
|
||||
// do not trigger the change:addresses event if we already know about this address
|
||||
if (this.observed.has(addrString)) {
|
||||
return
|
||||
const wasNewAddr = !this.observed.has(addrString)
|
||||
let addrRecord = {
|
||||
confidence,
|
||||
reporters: [
|
||||
reporter.toB58String()
|
||||
],
|
||||
expires: now + this.config.observedAddresses.maxLifetimeBeforeEviction
|
||||
}
|
||||
|
||||
this.observed.add(addrString)
|
||||
this.emit('change:addresses')
|
||||
// we've seen this address before, increase the confidence we have in it
|
||||
if (!wasNewAddr) {
|
||||
addrRecord = this.observed.get(addrString)
|
||||
|
||||
if (!addrRecord.reporters.includes(reporter.toB58String())) {
|
||||
addrRecord.confidence++
|
||||
addrRecord.reporters.push(reporter.toB58String())
|
||||
addrRecord.expires = now + this.config.observedAddresses.maxLifetimeBeforeEviction
|
||||
}
|
||||
}
|
||||
|
||||
this.observed.set(addrString, addrRecord)
|
||||
|
||||
// only emit event if we've reached the minimum confidence
|
||||
if (addrRecord.confidence === this.config.observedAddresses.minConfidence) {
|
||||
this.emit('change:addresses')
|
||||
}
|
||||
|
||||
// evict addresses older than MAX_LOW_CONFIDENCE_ADDR_LIFETIME_MS we are not confident in
|
||||
this.observed.forEach(({ confidence, expires }, key, map) => {
|
||||
if (confidence < this.config.observedAddresses.minConfidence && expires < now) {
|
||||
map.delete(key)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -16,6 +16,12 @@ const DefaultConfig = {
|
||||
announce: [],
|
||||
noAnnounce: []
|
||||
},
|
||||
addressManager: {
|
||||
observedAddresses: {
|
||||
minConfidence: 4,
|
||||
maxLifetimeBeforeEviction: (60 * 10) * 1000
|
||||
}
|
||||
},
|
||||
connectionManager: {
|
||||
minConnections: 25
|
||||
},
|
||||
|
@@ -202,9 +202,8 @@ class IdentifyService {
|
||||
this.peerStore.protoBook.set(id, protocols)
|
||||
this.peerStore.metadataBook.set(id, 'AgentVersion', uint8ArrayFromString(message.agentVersion))
|
||||
|
||||
// TODO: Score our observed addr
|
||||
log('received observed address of %s', observedAddr)
|
||||
this.addressManager.addObservedAddr(observedAddr)
|
||||
this.addressManager.addObservedAddr(observedAddr, id)
|
||||
}
|
||||
|
||||
/**
|
||||
|
10
src/index.js
10
src/index.js
@@ -51,9 +51,6 @@ const { updateSelfPeerRecord } = require('./record/utils')
|
||||
* @typedef {Object} PeerStoreOptions
|
||||
* @property {boolean} persistence
|
||||
*
|
||||
* @typedef {Object} PeerDiscoveryOptions
|
||||
* @property {boolean} autoDial
|
||||
*
|
||||
* @typedef {Object} RelayOptions
|
||||
* @property {boolean} enabled
|
||||
* @property {import('./circuit').RelayAdvertiseOptions} advertise
|
||||
@@ -62,7 +59,7 @@ const { updateSelfPeerRecord } = require('./record/utils')
|
||||
*
|
||||
* @typedef {Object} Libp2pConfig
|
||||
* @property {Object} [dht] dht module options
|
||||
* @property {PeerDiscoveryOptions} [peerDiscovery]
|
||||
* @property {Object} [peerDiscovery]
|
||||
* @property {Pubsub} [pubsub] pubsub module options
|
||||
* @property {RelayOptions} [relay]
|
||||
* @property {Record<string, Object>} [transport] transport options indexed by transport key
|
||||
@@ -140,7 +137,10 @@ class Libp2p extends EventEmitter {
|
||||
|
||||
// Addresses {listen, announce, noAnnounce}
|
||||
this.addresses = this._options.addresses
|
||||
this.addressManager = new AddressManager(this.peerId, this._options.addresses)
|
||||
this.addressManager = new AddressManager(this.peerId, {
|
||||
...this._options.addresses,
|
||||
...this._options.addressManager
|
||||
})
|
||||
|
||||
// when addresses change, update our peer record
|
||||
this.addressManager.on('change:addresses', () => {
|
||||
|
@@ -16,11 +16,11 @@ const {
|
||||
codes: { ERR_INVALID_PARAMETERS }
|
||||
} = require('./errors')
|
||||
const isLoopback = require('libp2p-utils/src/multiaddr/is-loopback')
|
||||
const AddressManager = require('./address-manager')
|
||||
|
||||
/**
|
||||
* @typedef {import('peer-id')} PeerId
|
||||
* @typedef {import('./transport-manager')} TransportManager
|
||||
* @typedef {import('./address-manager')} AddressManager
|
||||
*/
|
||||
|
||||
function highPort (min = 1024, max = 65535) {
|
||||
@@ -118,11 +118,12 @@ class NatManager {
|
||||
protocol: transport.toUpperCase()
|
||||
})
|
||||
|
||||
// add with high confidence
|
||||
this._addressManager.addObservedAddr(Multiaddr.fromNodeAddress({
|
||||
family: 'IPv4',
|
||||
address: publicIp,
|
||||
port: `${publicPort}`
|
||||
}, transport))
|
||||
}, transport), this._peerId, this._addressManager.config.observedAddresses.minConfidence)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,9 +139,9 @@ class NatManager {
|
||||
|
||||
this._client = {
|
||||
// these are all network operations so add a retry
|
||||
map: (...args) => retry(() => map(...args), { onFailedAttempt: log.error }),
|
||||
destroy: (...args) => retry(() => destroy(...args), { onFailedAttempt: log.error }),
|
||||
externalIp: (...args) => retry(() => externalIp(...args), { onFailedAttempt: log.error })
|
||||
map: (...args) => retry(() => map(...args), { onFailedAttempt: log.error, unref: true }),
|
||||
destroy: (...args) => retry(() => destroy(...args), { onFailedAttempt: log.error, unref: true }),
|
||||
externalIp: (...args) => retry(() => externalIp(...args), { onFailedAttempt: log.error, unref: true })
|
||||
}
|
||||
|
||||
return this._client
|
||||
|
@@ -15,9 +15,11 @@ const announceAddreses = ['/dns4/peer.io']
|
||||
|
||||
describe('Address Manager', () => {
|
||||
let peerId
|
||||
let peerIds
|
||||
|
||||
before(async () => {
|
||||
peerId = await PeerId.createFromJSON(Peers[0])
|
||||
peerIds = await Promise.all(Peers.slice(1).map(peerId => PeerId.createFromJSON(peerId)))
|
||||
})
|
||||
|
||||
it('should not need any addresses', () => {
|
||||
@@ -60,7 +62,7 @@ describe('Address Manager', () => {
|
||||
|
||||
expect(am.observed).to.be.empty()
|
||||
|
||||
am.addObservedAddr('/ip4/123.123.123.123/tcp/39201')
|
||||
am.addObservedAddr('/ip4/123.123.123.123/tcp/39201', peerId)
|
||||
|
||||
expect(am.observed).to.have.property('size', 1)
|
||||
})
|
||||
@@ -71,12 +73,12 @@ describe('Address Manager', () => {
|
||||
|
||||
expect(am.observed).to.be.empty()
|
||||
|
||||
am.addObservedAddr(ma)
|
||||
am.addObservedAddr(ma)
|
||||
am.addObservedAddr(ma)
|
||||
am.addObservedAddr(ma, peerId)
|
||||
am.addObservedAddr(ma, peerId)
|
||||
am.addObservedAddr(ma, peerId)
|
||||
|
||||
expect(am.observed).to.have.property('size', 1)
|
||||
expect(am.observed).to.include(ma)
|
||||
expect(Array.from(am.observed.keys())).to.include(ma)
|
||||
})
|
||||
|
||||
it('should only emit one change:addresses event', () => {
|
||||
@@ -88,11 +90,25 @@ describe('Address Manager', () => {
|
||||
eventCount++
|
||||
})
|
||||
|
||||
am.addObservedAddr(ma)
|
||||
am.addObservedAddr(ma)
|
||||
am.addObservedAddr(ma)
|
||||
am.addObservedAddr(`${ma}/p2p/${peerId}`)
|
||||
am.addObservedAddr(`${ma}/p2p/${peerId.toB58String()}`)
|
||||
am.addObservedAddr(ma, peerIds[0])
|
||||
am.addObservedAddr(ma, peerIds[1])
|
||||
am.addObservedAddr(ma, peerIds[2])
|
||||
am.addObservedAddr(`${ma}/p2p/${peerId}`, peerIds[3])
|
||||
am.addObservedAddr(`${ma}/p2p/${peerId.toB58String()}`, peerIds[4])
|
||||
|
||||
expect(eventCount).to.equal(1)
|
||||
})
|
||||
|
||||
it('should emit one change:addresses event when specifying confidence', () => {
|
||||
const ma = '/ip4/123.123.123.123/tcp/39201'
|
||||
const am = new AddressManager(peerId)
|
||||
let eventCount = 0
|
||||
|
||||
am.on('change:addresses', () => {
|
||||
eventCount++
|
||||
})
|
||||
|
||||
am.addObservedAddr(ma, peerId, am.config.observedAddresses.minConfidence)
|
||||
|
||||
expect(eventCount).to.equal(1)
|
||||
})
|
||||
@@ -103,11 +119,12 @@ describe('Address Manager', () => {
|
||||
|
||||
expect(am.observed).to.be.empty()
|
||||
|
||||
am.addObservedAddr(ma)
|
||||
am.addObservedAddr(`${ma}/p2p/${peerId}`)
|
||||
am.addObservedAddr(ma, peerId)
|
||||
am.addObservedAddr(`${ma}/p2p/${peerId}`, peerId)
|
||||
|
||||
expect(am.observed).to.have.property('size', 1)
|
||||
expect(am.observed).to.include(ma)
|
||||
|
||||
expect(Array.from(am.observed.keys())).to.include(ma)
|
||||
})
|
||||
|
||||
it('should strip our peer address from added observed addresses in difference formats', () => {
|
||||
@@ -116,12 +133,71 @@ describe('Address Manager', () => {
|
||||
|
||||
expect(am.observed).to.be.empty()
|
||||
|
||||
am.addObservedAddr(ma)
|
||||
am.addObservedAddr(`${ma}/p2p/${peerId}`) // base32 CID
|
||||
am.addObservedAddr(`${ma}/p2p/${peerId.toB58String()}`) // base58btc
|
||||
am.addObservedAddr(ma, peerId)
|
||||
am.addObservedAddr(`${ma}/p2p/${peerId}`, peerId) // base32 CID
|
||||
am.addObservedAddr(`${ma}/p2p/${peerId.toB58String()}`, peerId) // base58btc
|
||||
|
||||
expect(am.observed).to.have.property('size', 1)
|
||||
expect(am.observed).to.include(ma)
|
||||
|
||||
expect(Array.from(am.observed.keys())).to.include(ma)
|
||||
})
|
||||
|
||||
it('should require a number of confirmations before believing address', () => {
|
||||
const ma = '/ip4/123.123.123.123/tcp/39201'
|
||||
const am = new AddressManager(peerId)
|
||||
|
||||
expect(am.observed).to.be.empty()
|
||||
|
||||
am.addObservedAddr(ma, peerId)
|
||||
|
||||
expect(am.getObservedAddrs().map(ma => ma.toString())).to.not.include(ma)
|
||||
|
||||
for (let i = 0; i < am.config.observedAddresses.minConfidence; i++) {
|
||||
am.addObservedAddr(ma, peerIds[i])
|
||||
}
|
||||
|
||||
expect(am.getObservedAddrs().map(ma => ma.toString())).to.include(ma)
|
||||
})
|
||||
|
||||
it('should require a number of confirmations from different peers', () => {
|
||||
const ma = '/ip4/123.123.123.123/tcp/39201'
|
||||
const am = new AddressManager(peerId)
|
||||
|
||||
expect(am.observed).to.be.empty()
|
||||
|
||||
am.addObservedAddr(ma, peerId)
|
||||
|
||||
expect(am.getObservedAddrs().map(ma => ma.toString())).to.not.include(ma)
|
||||
|
||||
for (let i = 0; i < am.config.observedAddresses.minConfidence; i++) {
|
||||
am.addObservedAddr(ma, peerIds[0])
|
||||
}
|
||||
|
||||
expect(am.getObservedAddrs().map(ma => ma.toString())).to.not.include(ma)
|
||||
})
|
||||
|
||||
it('should evict addresses that do not receive enough confirmations within the timeout', () => {
|
||||
const ma1 = '/ip4/123.123.123.123/tcp/39201'
|
||||
const ma2 = '/ip4/124.124.124.124/tcp/39202'
|
||||
const am = new AddressManager(peerId)
|
||||
|
||||
expect(am.observed).to.be.empty()
|
||||
|
||||
am.addObservedAddr(ma1, peerId)
|
||||
|
||||
const observedAddrs = Array.from(am.observed.values())
|
||||
|
||||
expect(Array.from(am.observed.keys())).to.include(ma1)
|
||||
|
||||
// make expiry date a while ago
|
||||
observedAddrs[0].expires = Date.now() - 1000
|
||||
|
||||
// will evict any old multiaddrs
|
||||
am.addObservedAddr(ma2, peerId)
|
||||
|
||||
// should have been evicted
|
||||
expect(Array.from(am.observed.keys())).to.not.include(ma1)
|
||||
expect(Array.from(am.observed.keys())).to.include(ma2)
|
||||
})
|
||||
})
|
||||
|
||||
|
@@ -164,7 +164,7 @@ describe('libp2p.multiaddrs', () => {
|
||||
|
||||
expect(libp2p.multiaddrs).to.have.lengthOf(listenAddresses.length)
|
||||
|
||||
libp2p.addressManager.addObservedAddr(ma)
|
||||
libp2p.addressManager.addObservedAddr(ma, libp2p.peerId, libp2p.addressManager.config.observedAddresses.minConfidence)
|
||||
|
||||
expect(libp2p.multiaddrs).to.have.lengthOf(listenAddresses.length + 1)
|
||||
expect(libp2p.multiaddrs.map(ma => ma.toString())).to.include(ma)
|
||||
|
@@ -37,7 +37,7 @@ describe('Consume peer record', () => {
|
||||
done = resolve
|
||||
})
|
||||
|
||||
libp2p.addressManager.addObservedAddr('/ip4/123.123.123.123/tcp/3983')
|
||||
libp2p.addressManager.addObservedAddr('/ip4/123.123.123.123/tcp/3983', libp2p.peerId, libp2p.addressManager.config.observedAddresses.minConfidence)
|
||||
|
||||
await p
|
||||
|
||||
|
Reference in New Issue
Block a user