-
Notifications
You must be signed in to change notification settings - Fork 471
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
1a344be
commit 50e0b11
Showing
24 changed files
with
491 additions
and
60 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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, once a transport selects a port to listen, the listen addresses will need to be updated. For example tcp may replace `/ip4/0.0.0.0/tcp/0` with something like `/ip4/0.0.0.0/tcp/8989`. | ||
|
||
## 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, No Announce Addresses should also take into account these changes so that they can be matched when No Announce Addresses are being filtered out. | ||
|
||
## Implementation | ||
|
||
Once a libp2p node is started, the Transport Manager component will gather the addresses that the configured libp2p transports should use to listen on. As soon as this node has its transports listening, the Transport Manager should replace the listen addresses with the updated list. | ||
|
||
After the transports being started, 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 and should gather these addresses from the Address Manager. | ||
|
||
## 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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
'use strict' | ||
|
||
const debug = require('debug') | ||
const log = debug('libp2p:addresses') | ||
log.error = debug('libp2p:addresses:error') | ||
|
||
const MultiaddrSet = require('./multiaddr-set') | ||
|
||
/** | ||
* Responsible for managing known peers, as well as their addresses, protocols and metadata. | ||
*/ | ||
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 MultiaddrSet(listen) | ||
this._announce = new MultiaddrSet(announce) | ||
this._noAnnounce = new MultiaddrSet(noAnnounce) | ||
} | ||
|
||
/** | ||
* Get peer addresses to listen. | ||
* @return {Array<Multiaddr>} | ||
*/ | ||
get listen () { | ||
return this._listen.toArray() | ||
} | ||
|
||
/** | ||
* Get peer addresses to announce. | ||
* @return {Array<Multiaddr>} | ||
*/ | ||
get announce () { | ||
return this._listen.toArray() | ||
.concat(this._announce.toArray()) // Concat announce amendment | ||
.filter((ma) => !this._noAnnounce.has(ma)) // Remove no announce addresses | ||
} | ||
|
||
/** | ||
* Get peer addresses to not announce. | ||
* @return {Array<Multiaddr>} | ||
*/ | ||
get noAnnounce () { | ||
return this._noAnnounce.toArray() | ||
} | ||
|
||
/** | ||
* Replace listen multiaddrs after trying to listen the original ones by the transports. | ||
* This should also forward the replace side effects to the NoAnnounce sets. | ||
* @param {Array<Multiaddr>} newMultiaddrs | ||
* @return {Array<Multiaddr>} | ||
*/ | ||
_replaceListen (newMultiaddrs) { | ||
const currentListen = this._listen.toArray() | ||
|
||
this._listen.replace(currentListen, newMultiaddrs) | ||
const newListen = this._listen.toArray() | ||
|
||
// TODO: Update noAnnounce on replace (new Port?) or improve the filter operation in announce getter? | ||
// Note: noAnnounce should take into account encapsulated addresses. | ||
// - For example, if I add /ip4/127.0.0.1 to noAnnounce | ||
// - I expect addresses like /ip4/127.0.0.1/tcp/8080/ipfs/Qm to be filtered out. | ||
|
||
return newListen | ||
} | ||
} | ||
|
||
module.exports = AddressManager |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
'use strict' | ||
|
||
const errCode = require('err-code') | ||
|
||
const multiaddr = require('multiaddr') | ||
|
||
const { codes } = require('../errors') | ||
|
||
/** | ||
* Multiaddr Set. | ||
* Since JavaScript doesn't let you overload the compare in Set().. | ||
*/ | ||
class MultiaddrSet { | ||
/** | ||
* @constructor | ||
* @param {Array<string>} addresses addresses to store. | ||
*/ | ||
constructor (addresses = []) { | ||
this._multiaddrs = addresses.map(a => multiaddr(a)) | ||
} | ||
|
||
get size () { | ||
return this._multiaddrs.length | ||
} | ||
|
||
/** | ||
* Add multiaddr to the set. | ||
* @param {Multiaddr} ma | ||
*/ | ||
add (ma) { | ||
if (!multiaddr.isMultiaddr(ma)) { | ||
throw errCode(new Error('Invalid multiaddr provided'), codes.ERR_INVALID_MULTIADDR) | ||
} | ||
|
||
if (!this.has(ma)) { | ||
this._multiaddrs.push(ma) | ||
} | ||
} | ||
|
||
/** | ||
* Get array of multiaddrs. | ||
* @return {Array<Multiaddr>} | ||
*/ | ||
toArray () { | ||
return this._multiaddrs.slice() | ||
} | ||
|
||
forEach (fn) { | ||
return this._multiaddrs.forEach(fn) | ||
} | ||
|
||
/** | ||
* Has provided multiaddr. | ||
* @param {Multiaddr} ma | ||
* @return {boolean} | ||
*/ | ||
has (ma) { | ||
return this._multiaddrs.some((m) => m.equals(ma)) | ||
} | ||
|
||
delete (ma) { | ||
this._multiaddrs.some((m, i) => { | ||
if (m.equals(ma)) { | ||
this._multiaddrs.splice(i, 1) | ||
return true | ||
} | ||
}) | ||
} | ||
|
||
/** | ||
* Replace given multiaddrs (if existing) by fresh ones | ||
* @param {Array<Multiaddr>} existing | ||
* @param {Array<Multiaddr>} fresh | ||
*/ | ||
replace (existing, fresh) { | ||
existing.forEach((m) => this.delete(m)) | ||
fresh.forEach((m) => this.add(m)) | ||
} | ||
|
||
/** | ||
* Clear set, | ||
*/ | ||
clear () { | ||
this._multiaddrs = [] | ||
} | ||
} | ||
|
||
module.exports = MultiaddrSet |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.