Skip to content

Commit 01aa447

Browse files
authored
feat: auto dial discovered peers (#349)
1 parent 8b62779 commit 01aa447

12 files changed

+431
-154
lines changed

.aegir.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ const after = (done) => {
7979
}
8080

8181
module.exports = {
82-
bundlesize: { maxSize: '217kB' },
82+
bundlesize: { maxSize: '218kB' },
8383
hooks: {
8484
pre: before,
8585
post: after

PEER_DISCOVERY.md

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# Peer Discovery and Auto Dial
2+
3+
**Synopsis**:
4+
* All peers discovered are emitted via `peer:discovery` so applications can take any desired action.
5+
* Libp2p defaults to automatically connecting to new peers, when under the [ConnectionManager](https://github.com/libp2p/js-libp2p-connection-manager) low watermark (minimum peers).
6+
* Applications can disable this via the `peerDiscovery.autoDial` config property, and handle connections themselves.
7+
* Applications who have not disabled this should **never** connect on peer discovery. Applications should use the `peer:connect` event if they wish to take a specific action on new peers.
8+
9+
## Scenarios
10+
In any scenario, if a peer is discovered it should be added to the PeerBook. This ensures that even if we don't dial to a node when we discover it, we know about it in the event that it becomes known as a provider for something we need. The scenarios listed below detail what actions the auto dialer will take when peers are discovered.
11+
12+
### 1. Joining the network
13+
The node is new and needs to join the network. It currently has 0 peers.
14+
**Discovery Mechanisms**: [Ambient Discovery](#ambient-discovery)
15+
16+
### Action to take
17+
Connect to discovered peers. This should have some degree of concurrency limiting. While the case should be low, if we immediately discover more peers than our high watermark we should avoid dialing them all.
18+
19+
### 2. Connected to some
20+
The node is connected to other nodes. The current number of connections is less than the desired low watermark.
21+
**Discovery Mechanisms**: [Ambient Discovery](#ambient-discovery) and [Active Discovery](#active-discovery)
22+
23+
### Action to take
24+
Connect to discovered peers. This should have some degree of concurrency limiting. The concurrency may need to be modified to reflect the current number of peers connected. The more peers we have, the lower the concurrency may need to be.
25+
26+
### 3. Connected to enough
27+
**Discovery Mechanisms**: [Ambient Discovery](#ambient-discovery) and [Active Discovery](#active-discovery)
28+
29+
### Action to take
30+
None. If we are connected to enough peers, the low watermark, we should not connect to discovered peers. As other peers discover us, they may connect to us based on their current scenario.
31+
32+
For example, a long running node with adequate peers is on an MDNS network. A new peer joins the network and both become aware of each other. The new peer should be the peer that dials, as it has too few peers. The existing node has no reason to dial the new peer, but should keep a record of it in case it later becomes an important node due to its contents/capabilities.
33+
34+
Avoiding dials above the low watermark also allows for a pool of connections to be reserved for application specific actions, such as connecting to a specific content provider via a DHT query to find that content (ipfs-bitswap).
35+
36+
### 4. Connected to too many
37+
The node has more connections than it wants. The current number of connections is greater than the high watermark.
38+
39+
[WIP Connection Manager v2 spec](https://github.com/libp2p/specs/pull/161)
40+
**Discovery Mechanisms**: [Ambient Discovery](#ambient-discovery) and [Active Discovery](#active-discovery)
41+
42+
### Action to take
43+
None, the `ConnectionManager` will automatically prune connections.
44+
45+
## Discovery Mechanisms
46+
Means of which a libp2p node discovers other peers.
47+
48+
### Active Discovery
49+
Through active use of the libp2p network, a node may discovery peers.
50+
51+
* Content/Peer routing (DHT, delegated, etc) provider and peer queries
52+
* DHT random walk
53+
* Rendezvous servers
54+
55+
### Ambient Discovery
56+
Leveraging known addresses, or network discovery mechanisms, a node may discover peers outside of the bounds of the libp2p network.
57+
58+
* Bootstrap
59+
* MDNS
60+
* proximity based (bluetooth, sound, etc)

README.md

+4-12
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ class Node extends libp2p {
160160
// libp2p config options (typically found on a config.json)
161161
config: { // The config object is the part of the config that can go into a file, config.json.
162162
peerDiscovery: {
163+
autoDial: true, // Auto connect to discovered peers (limited by ConnectionManager minPeers)
163164
mdns: { // mdns options
164165
interval: 1000, // ms
165166
enabled: true
@@ -305,6 +306,9 @@ Required keys in the `options` object:
305306

306307
> Peer has been discovered.
307308
309+
If `autoDial` is `true`, applications should **not** attempt to connect to the peer
310+
unless they are performing a specific action. See [peer discovery and auto dial](./PEER_DISCOVERY.md) for more information.
311+
308312
- `peer`: instance of [PeerInfo][]
309313

310314
##### `libp2p.on('peer:connect', (peer) => {})`
@@ -509,18 +513,6 @@ Some available network protectors:
509513
> npm run test:browser
510514
```
511515

512-
#### Run interop tests
513-
514-
```sh
515-
N/A
516-
```
517-
518-
#### Run benchmark tests
519-
520-
```sh
521-
N/A
522-
```
523-
524516
### Packages
525517

526518
List of packages currently in existence for libp2p

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
"libp2p-connection-manager": "~0.0.2",
4646
"libp2p-floodsub": "~0.15.8",
4747
"libp2p-ping": "~0.8.5",
48-
"libp2p-switch": "~0.42.7",
48+
"libp2p-switch": "~0.42.8",
4949
"libp2p-websockets": "~0.12.2",
5050
"mafmt": "^6.0.7",
5151
"multiaddr": "^6.0.6",

src/config.js

+85-51
Original file line numberDiff line numberDiff line change
@@ -12,58 +12,88 @@ const transport = s.union([
1212
}),
1313
'function'
1414
])
15+
const modulesSchema = s({
16+
connEncryption: optional(list([s('object|function')])),
17+
// this is hacky to simulate optional because interface doesnt work correctly with it
18+
// change to optional when fixed upstream
19+
connProtector: s.union(['undefined', s.interface({ protect: 'function' })]),
20+
contentRouting: optional(list(['object'])),
21+
dht: optional(s('null|function|object')),
22+
peerDiscovery: optional(list([s('object|function')])),
23+
peerRouting: optional(list(['object'])),
24+
streamMuxer: optional(list([s('object|function')])),
25+
transport: s.intersection([[transport], s.interface({
26+
length (v) {
27+
return v > 0 ? true : 'ERROR_EMPTY'
28+
}
29+
})])
30+
})
31+
32+
const configSchema = s({
33+
peerDiscovery: s('object', {
34+
autoDial: true
35+
}),
36+
relay: s({
37+
enabled: 'boolean',
38+
hop: optional(s({
39+
enabled: 'boolean',
40+
active: 'boolean'
41+
}, {
42+
// HOP defaults
43+
enabled: false,
44+
active: false
45+
}))
46+
}, {
47+
// Relay defaults
48+
enabled: true
49+
}),
50+
// DHT config
51+
dht: s({
52+
kBucketSize: 'number',
53+
enabled: 'boolean?',
54+
validators: 'object?',
55+
selectors: 'object?',
56+
randomWalk: optional(s({
57+
enabled: 'boolean?',
58+
queriesPerPeriod: 'number?',
59+
interval: 'number?',
60+
timeout: 'number?'
61+
}, {
62+
// random walk defaults
63+
enabled: false, // disabled waiting for https://github.com/libp2p/js-libp2p-kad-dht/issues/86
64+
queriesPerPeriod: 1,
65+
interval: 30000,
66+
timeout: 10000
67+
}))
68+
}, {
69+
// DHT defaults
70+
enabled: false,
71+
kBucketSize: 20,
72+
enabledDiscovery: false
73+
}),
74+
// Experimental config
75+
EXPERIMENTAL: s({
76+
pubsub: 'boolean'
77+
}, {
78+
// Experimental defaults
79+
pubsub: false
80+
})
81+
}, {
82+
relay: {},
83+
dht: {},
84+
EXPERIMENTAL: {}
85+
})
1586

16-
const optionsSchema = s(
17-
{
18-
connectionManager: 'object?',
19-
datastore: 'object?',
20-
peerInfo: 'object',
21-
peerBook: 'object?',
22-
modules: s({
23-
connEncryption: optional(list([s('object|function')])),
24-
// this is hacky to simulate optional because interface doesnt work correctly with it
25-
// change to optional when fixed upstream
26-
connProtector: s.union(['undefined', s.interface({ protect: 'function' })]),
27-
contentRouting: optional(list(['object'])),
28-
dht: optional(s('null|function|object')),
29-
peerDiscovery: optional(list([s('object|function')])),
30-
peerRouting: optional(list(['object'])),
31-
streamMuxer: optional(list([s('object|function')])),
32-
transport: s.intersection([[transport], s.interface({
33-
length (v) {
34-
return v > 0 ? true : 'ERROR_EMPTY'
35-
}
36-
})])
37-
}),
38-
config: s({
39-
peerDiscovery: 'object?',
40-
relay: s({
41-
enabled: 'boolean',
42-
hop: optional(s({
43-
enabled: 'boolean',
44-
active: 'boolean'
45-
},
46-
{ enabled: false, active: false }))
47-
}, { enabled: true, hop: {} }),
48-
dht: s({
49-
kBucketSize: 'number',
50-
enabled: 'boolean?',
51-
randomWalk: optional(s({
52-
enabled: 'boolean?', // disabled waiting for https://github.com/libp2p/js-libp2p-kad-dht/issues/86
53-
queriesPerPeriod: 'number?',
54-
interval: 'number?',
55-
timeout: 'number?'
56-
}, { enabled: false, queriesPerPeriod: 1, interval: 30000, timeout: 10000 })),
57-
validators: 'object?',
58-
selectors: 'object?'
59-
}, { enabled: false, kBucketSize: 20, enabledDiscovery: false }),
60-
EXPERIMENTAL: s({
61-
pubsub: 'boolean'
62-
}, { pubsub: false })
63-
}, { relay: {}, dht: {}, EXPERIMENTAL: {} })
64-
},
65-
{ config: {}, modules: {} }
66-
)
87+
const optionsSchema = s({
88+
connectionManager: s('object', {
89+
minPeers: 25
90+
}),
91+
datastore: 'object?',
92+
peerInfo: 'object',
93+
peerBook: 'object?',
94+
modules: modulesSchema,
95+
config: configSchema
96+
})
6797

6898
module.exports.validate = (opts) => {
6999
const [error, options] = optionsSchema.validate(opts)
@@ -78,5 +108,9 @@ module.exports.validate = (opts) => {
78108
}
79109
}
80110

111+
if (options.config.peerDiscovery.autoDial === undefined) {
112+
options.config.peerDiscovery.autoDial = true
113+
}
114+
81115
return options
82116
}

0 commit comments

Comments
 (0)