diff --git a/doc/CONFIGURATION.md b/doc/CONFIGURATION.md index 42509485..ffc6048e 100644 --- a/doc/CONFIGURATION.md +++ b/doc/CONFIGURATION.md @@ -499,6 +499,7 @@ Dialing in libp2p can be configured to limit the rate of dialing, and how long d | 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 | +| addressSorter | `(Array
) => Array` | Sort the known addresses of a peer before trying to dial. | The below configuration example shows how the dialer should be configured, with the current defaults: @@ -509,6 +510,7 @@ const MPLEX = require('libp2p-mplex') const { NOISE } = require('libp2p-noise') const { dnsaddrResolver } = require('multiaddr/src/resolvers') +const { publicAddressesFirst } = require('libp2p-utils/src/address-sort') const node = await Libp2p.create({ modules: { @@ -522,7 +524,8 @@ const node = await Libp2p.create({ dialTimeout: 30e3, resolvers: { dnsaddr: dnsaddrResolver - } + }, + addressSorter: publicAddressesFirst } ``` diff --git a/package.json b/package.json index 13f4390e..cc5c5269 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,7 @@ "it-protocol-buffers": "^0.2.0", "libp2p-crypto": "^0.18.0", "libp2p-interfaces": "^0.7.2", - "libp2p-utils": "^0.2.1", + "libp2p-utils": "^0.2.2", "mafmt": "^8.0.0", "merge-options": "^2.0.0", "moving-average": "^1.0.0", diff --git a/src/circuit/auto-relay.js b/src/circuit/auto-relay.js index 00ebc6f5..6b9a4039 100644 --- a/src/circuit/auto-relay.js +++ b/src/circuit/auto-relay.js @@ -4,8 +4,6 @@ const debug = require('debug') const log = debug('libp2p:auto-relay') log.error = debug('libp2p:auto-relay:error') -const isPrivate = require('libp2p-utils/src/multiaddr/is-private') - const uint8ArrayFromString = require('uint8arrays/from-string') const uint8ArrayToString = require('uint8arrays/to-string') const multiaddr = require('multiaddr') @@ -36,6 +34,7 @@ class AutoRelay { this._peerStore = libp2p.peerStore this._connectionManager = libp2p.connectionManager this._transportManager = libp2p.transportManager + this._addressSorter = libp2p.dialer.addressSorter this.maxListeners = maxListeners @@ -129,37 +128,19 @@ class AutoRelay { return } - // Create relay listen addr - let listenAddr, remoteMultiaddr, remoteAddrs + // Get peer known addresses and sort them per public addresses first + const remoteAddrs = this._peerStore.addressBook.getMultiaddrsForPeer( + connection.remotePeer, this._addressSorter + ) - try { - // Get peer known addresses and sort them per public addresses first - remoteAddrs = this._peerStore.addressBook.get(connection.remotePeer) - // TODO: This sort should be customizable in the config (dialer addr sort) - remoteAddrs.sort(multiaddrsCompareFunction) - - remoteMultiaddr = remoteAddrs.find(a => a.isCertified).multiaddr // Get first announced address certified - // TODO: HOP Relays should avoid advertising private addresses! - } catch (_) { - log.error(`${id} does not have announced certified multiaddrs`) - - // Attempt first if existing - if (!remoteAddrs || !remoteAddrs.length) { - return - } - - remoteMultiaddr = remoteAddrs[0].multiaddr + if (!remoteAddrs || !remoteAddrs.length) { + return } - if (!remoteMultiaddr.protoNames().includes('p2p')) { - listenAddr = `${remoteMultiaddr.toString()}/p2p/${connection.remotePeer.toB58String()}/p2p-circuit` - } else { - listenAddr = `${remoteMultiaddr.toString()}/p2p-circuit` - } - - // Attempt to listen on relay + const listenAddr = `${remoteAddrs[0].toString()}/p2p-circuit` this._listenRelays.add(id) + // Attempt to listen on relay try { await this._transportManager.listen([multiaddr(listenAddr)]) // Announce multiaddrs will update on listen success by TransportManager event being triggered @@ -269,24 +250,4 @@ class AutoRelay { } } -/** - * Compare function for array.sort(). - * This sort aims to move the private adresses to the end of the array. - * - * @param {Address} a - * @param {Address} b - * @returns {number} - */ -function multiaddrsCompareFunction (a, b) { - const isAPrivate = isPrivate(a.multiaddr) - const isBPrivate = isPrivate(b.multiaddr) - - if (isAPrivate && !isBPrivate) { - return 1 - } else if (!isAPrivate && isBPrivate) { - return -1 - } - return 0 -} - module.exports = AutoRelay diff --git a/src/config.js b/src/config.js index db948e20..d1ca2d02 100644 --- a/src/config.js +++ b/src/config.js @@ -6,6 +6,7 @@ const { dnsaddrResolver } = require('multiaddr/src/resolvers') const Constants = require('./constants') const RelayConstants = require('./circuit/constants') +const { publicAddressesFirst } = require('libp2p-utils/src/address-sort') const { FaultTolerance } = require('./transport-manager') const DefaultConfig = { @@ -26,7 +27,8 @@ const DefaultConfig = { dialTimeout: Constants.DIAL_TIMEOUT, resolvers: { dnsaddr: dnsaddrResolver - } + }, + addressSorter: publicAddressesFirst }, metrics: { enabled: false diff --git a/src/dialer/index.js b/src/dialer/index.js index 49d77e46..3ee3ada6 100644 --- a/src/dialer/index.js +++ b/src/dialer/index.js @@ -9,6 +9,7 @@ const log = debug('libp2p:dialer') log.error = debug('libp2p:dialer:error') const { DialRequest } = require('./dial-request') +const { publicAddressesFirst } = require('libp2p-utils/src/address-sort') const getPeer = require('../get-peer') const { codes } = require('../errors') @@ -24,6 +25,7 @@ class Dialer { * @param {object} options * @param {TransportManager} options.transportManager * @param {Peerstore} options.peerStore + * @param {(addresses: Array Array} [options.addressSorter = publicAddressesFirst] - Sort the known addresses of a peer before trying to dial. * @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. @@ -32,6 +34,7 @@ class Dialer { constructor ({ transportManager, peerStore, + addressSorter = publicAddressesFirst, concurrency = MAX_PARALLEL_DIALS, timeout = DIAL_TIMEOUT, perPeerLimit = MAX_PER_PEER_DIALS, @@ -39,6 +42,7 @@ class Dialer { }) { this.transportManager = transportManager this.peerStore = peerStore + this.addressSorter = addressSorter this.concurrency = concurrency this.timeout = timeout this.perPeerLimit = perPeerLimit @@ -120,7 +124,7 @@ class Dialer { this.peerStore.addressBook.add(id, multiaddrs) } - let knownAddrs = this.peerStore.addressBook.getMultiaddrsForPeer(id) || [] + let knownAddrs = this.peerStore.addressBook.getMultiaddrsForPeer(id, this.addressSorter) || [] // 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. diff --git a/src/index.js b/src/index.js index 56401c35..c4085b7a 100644 --- a/src/index.js +++ b/src/index.js @@ -136,7 +136,8 @@ class Libp2p extends EventEmitter { concurrency: this._options.dialer.maxParallelDials, perPeerLimit: this._options.dialer.maxDialsPerPeer, timeout: this._options.dialer.dialTimeout, - resolvers: this._options.dialer.resolvers + resolvers: this._options.dialer.resolvers, + addressSorter: this._options.dialer.addressSorter }) this._modules.transport.forEach((Transport) => { diff --git a/src/peer-store/address-book.js b/src/peer-store/address-book.js index 88ed327b..07d8af59 100644 --- a/src/peer-store/address-book.js +++ b/src/peer-store/address-book.js @@ -319,20 +319,22 @@ class AddressBook extends Book { * Returns `undefined` if there are no known multiaddrs for the given peer. * * @param {PeerId} peerId + * @param {(addresses: Array Array} [addressSorter] * @returns {Array