Skip to content
This repository was archived by the owner on Jul 21, 2023. It is now read-only.

Commit 10f0cc8

Browse files
authored
feat: periodically fill the routing table with KADIds (#215)
In order to make queries in fewer hops it's useful to fill the routing table with imaginary peers that have IDs that are uniformly distributed over the sha2-256 value space. This means we've always got a peer ID on hand that's kind of xor-close to anything we might be looking up. We can then issue period DHT queries for any actual existant peers that are close to our imaginary peers to ensure we've got a good range of peers we know about, so making queries requires fewer hops to locate ones that are xor-close to the data we are interested in. BREAKING CHANGE: .start() is now async and random walk has been removed
1 parent 57f4029 commit 10f0cc8

25 files changed

+5767
-731
lines changed

.aegir.js

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,33 @@
1+
'use strict'
2+
3+
/** @type {import('aegir').Options["build"]["config"]} */
4+
const esbuild = {
5+
plugins: [
6+
{
7+
name: 'node built ins',
8+
setup (build) {
9+
build.onResolve({ filter: /^stream$/ }, () => {
10+
return { path: require.resolve('readable-stream') }
11+
})
12+
build.onResolve({ filter: /^crypto$/ }, () => {
13+
return { path: require.resolve('crypto-browserify') }
14+
})
15+
}
16+
}
17+
]
18+
}
19+
20+
/** @type {import('aegir').PartialOptions} */
121
module.exports = {
22+
test: {
23+
browser: {
24+
config: {
25+
buildConfig: esbuild
26+
}
27+
}
28+
},
229
build: {
3-
bundlesizeMax: '182kB'
30+
bundlesizeMax: '499KB',
31+
config: esbuild
432
}
533
}

README.md

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,17 +72,15 @@ function addDHT(libp2p) {
7272
Note that you may want to supply your own peer discovery function and datastore
7373
### Peer Routing
7474

75-
[![](https://raw.githubusercontent.com/libp2p/js-libp2p-interfaces/master/src/peer-routing/img/badge.png)](https://github.com/libp2p/js-libp2p-interfaces/tree/master/src/peer-routing)
75+
[![](https://raw.githubusercontent.com/libp2p/js-libp2p-interfaces/master/src/peer-routing/img/badge.png)](https://github.com/libp2p/js-libp2p-interfaces/tree/master/packages/interfaces/src/peer-routing)
7676

7777
### Content Routing
7878

79-
[![](https://raw.githubusercontent.com/libp2p/js-libp2p-interfaces/master/src/content-routing/img/badge.png)](https://github.com/libp2p/js-libp2p-interfaces/tree/master/src/content-routing)
79+
[![](https://raw.githubusercontent.com/libp2p/js-libp2p-interfaces/master/src/content-routing/img/badge.png)](https://github.com/libp2p/js-libp2p-interfaces/tree/master/packages/interfaces/src/content-routing)
8080

8181
### Peer Discovery
8282

83-
[![](https://raw.githubusercontent.com/libp2p/js-libp2p-interfaces/master/src/peer-discovery/img/badge.png)](https://github.com/libp2p/js-libp2p-interfaces/tree/master/src/peer-discovery)
84-
85-
`libp2p-kad-dht` provides a discovery service called `Random Walk` (random walks on the DHT to discover more nodes). It is accessible through `dht.randomWalk` and exposes the [Peer Discovery interface](https://github.com/libp2p/js-libp2p-interfaces/tree/master/src/peer-discovery).
83+
[![](https://raw.githubusercontent.com/libp2p/js-libp2p-interfaces/master/src/peer-discovery/img/badge.png)](https://github.com/libp2p/js-libp2p-interfaces/tree/master/packages/interfaces/src/peer-discovery)
8684

8785
### Implementation Summary
8886

package.json

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,13 @@
4747
"homepage": "https://github.com/libp2p/js-libp2p-kad-dht",
4848
"types": "dist/src/index.d.ts",
4949
"dependencies": {
50-
"abort-controller": "^3.0.0",
5150
"debug": "^4.3.1",
5251
"err-code": "^3.0.0",
5352
"hashlru": "^2.3.0",
5453
"heap": "~0.2.6",
5554
"interface-datastore": "^5.1.1",
5655
"it-first": "^1.0.4",
56+
"it-length": "^1.0.3",
5757
"it-length-prefixed": "^5.0.2",
5858
"it-pipe": "^1.1.0",
5959
"k-bucket": "^5.1.0",
@@ -65,21 +65,20 @@
6565
"p-map": "^4.0.0",
6666
"p-queue": "^6.6.2",
6767
"p-timeout": "^4.1.0",
68-
"p-times": "^3.0.0",
6968
"peer-id": "^0.15.0",
7069
"protobufjs": "^6.10.2",
7170
"streaming-iterables": "^6.0.0",
7271
"uint8arrays": "^3.0.0",
73-
"varint": "^6.0.0",
74-
"xor-distance": "^2.0.0"
72+
"varint": "^6.0.0"
7573
},
7674
"devDependencies": {
7775
"@types/debug": "^4.1.7",
78-
"@types/node": "^16.6.1",
7976
"aegir": "^35.0.1",
8077
"async-iterator-all": "^1.0.0",
78+
"crypto-browserify": "^3.12.0",
8179
"datastore-level": "^6.0.2",
8280
"delay": "^5.0.0",
81+
"execa": "^5.1.1",
8382
"it-pair": "^1.0.0",
8483
"libp2p": "^0.32.3",
8584
"lodash.random": "^3.2.0",
@@ -88,7 +87,8 @@
8887
"p-each-series": "^2.1.0",
8988
"p-map-series": "^2.1.0",
9089
"p-retry": "^4.2.0",
91-
"sinon": "^11.1.1"
90+
"sinon": "^11.1.1",
91+
"which": "^2.0.2"
9292
},
9393
"contributors": [
9494
"Vasco Santos <[email protected]>",
@@ -110,5 +110,8 @@
110110
"Pedro Teixeira <[email protected]>",
111111
"Qmstream <[email protected]>",
112112
"Thomas Eizinger <[email protected]>"
113-
]
113+
],
114+
"browser": {
115+
"src/routing-table/generated-prefix-list.json": "src/routing-table/generated-prefix-list-browser.json"
116+
}
114117
}

src/constants.js

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,3 @@ exports.K = 20
3333

3434
// Alpha is the concurrency for asynchronous requests
3535
exports.ALPHA = 3
36-
37-
exports.defaultRandomWalk = {
38-
enabled: true,
39-
queriesPerPeriod: 1,
40-
interval: 5 * minute,
41-
timeout: 10 * second,
42-
delay: 10 * second
43-
}

src/index.js

Lines changed: 15 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const { MemoryDatastore } = require('interface-datastore')
88
const { equals: uint8ArrayEquals } = require('uint8arrays/equals')
99
const { toString: uint8ArrayToString } = require('uint8arrays/to-string')
1010

11-
const RoutingTable = require('./routing')
11+
const RoutingTable = require('./routing-table')
1212
const utils = require('./utils')
1313
const c = require('./constants')
1414
const Network = require('./network')
@@ -17,7 +17,6 @@ const contentRouting = require('./content-routing')
1717
const peerRouting = require('./peer-routing')
1818
const Message = require('./message')
1919
const Providers = require('./providers')
20-
const RandomWalk = require('./random-walk')
2120
const QueryManager = require('./query-manager')
2221

2322
const Record = libp2pRecord.Record
@@ -34,13 +33,6 @@ const Record = libp2pRecord.Record
3433
* @typedef {object} PeerData
3534
* @property {PeerId} id
3635
* @property {Multiaddr[]} multiaddrs
37-
*
38-
* @typedef {object} RandomWalkOptions
39-
* @property {boolean} enabled discovery enabled (default: true)
40-
* @property {number} queriesPerPeriod how many queries to run per period (default: 1)
41-
* @property {number} interval how often to run the the random-walk process, in milliseconds (default: 300000)
42-
* @property {number} timeout how long to wait for the the random-walk query to run, in milliseconds (default: 30000)
43-
* @property {number} delay how long to wait before starting the first random walk, in milliseconds (default: 10000)
4436
*/
4537

4638
/**
@@ -65,7 +57,6 @@ class KadDHT extends EventEmitter {
6557
* @param {Datastore} props.datastore - datastore (default MemoryDatastore)
6658
* @param {object} props.validators - validators object with namespace as keys and function(key, record, callback)
6759
* @param {object} props.selectors - selectors object with namespace as keys and function(key, records)
68-
* @param {RandomWalkOptions} props.randomWalk - randomWalk options
6960
* @param {function(import('libp2p-record').Record, PeerId): void} [props.onPut] - Called when an entry is added to or changed in the datastore
7061
* @param {function(import('libp2p-record').Record): void} [props.onRemove] - Called when an entry is removed from the datastore
7162
*/
@@ -83,13 +74,6 @@ class KadDHT extends EventEmitter {
8374
concurrency = c.ALPHA,
8475
validators = {},
8576
selectors = {},
86-
randomWalk = {
87-
enabled: false,
88-
queriesPerPeriod: 1,
89-
interval: 300000,
90-
timeout: 30000,
91-
delay: 10000
92-
},
9377
onPut = () => {},
9478
onRemove = () => {}
9579
}) {
@@ -170,7 +154,7 @@ class KadDHT extends EventEmitter {
170154
*
171155
* @type {RoutingTable}
172156
*/
173-
this.routingTable = new RoutingTable(this.peerId, this.kBucketSize)
157+
this.routingTable = new RoutingTable(this, { kBucketSize: this.kBucketSize })
174158

175159
/**
176160
* Reference to the datastore, uses an in-memory store if none given.
@@ -200,13 +184,6 @@ class KadDHT extends EventEmitter {
200184

201185
this._log = utils.logger(this.peerId)
202186

203-
/**
204-
* Random walk management
205-
*
206-
* @type {RandomWalk}
207-
*/
208-
this.randomWalk = new RandomWalk(this, randomWalk)
209-
210187
/**
211188
* Keeps track of running queries
212189
*
@@ -237,17 +214,14 @@ class KadDHT extends EventEmitter {
237214
* Start listening to incoming connections.
238215
*/
239216
start () {
240-
if (this._running) {
241-
return
242-
}
243-
244217
this._running = true
245-
this.providers.start()
246-
this._queryManager.start()
247-
this.network.start()
248218

249-
// Start random walk, it will not run if it's disabled
250-
this.randomWalk.start()
219+
return Promise.all([
220+
this.providers.start(),
221+
this._queryManager.start(),
222+
this.network.start(),
223+
this.routingTable.start()
224+
])
251225
}
252226

253227
/**
@@ -256,10 +230,13 @@ class KadDHT extends EventEmitter {
256230
*/
257231
stop () {
258232
this._running = false
259-
this.randomWalk.stop()
260-
this.network.stop()
261-
this._queryManager.stop()
262-
this.providers.stop()
233+
234+
return Promise.all([
235+
this.providers.stop(),
236+
this._queryManager.stop(),
237+
this.network.stop(),
238+
this.routingTable.stop()
239+
])
263240
}
264241

265242
/**

src/peer-list/peer-distance-list.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
'use strict'
22

3-
// @ts-ignore
4-
const distance = require('xor-distance')
53
const utils = require('../utils')
64
const pMap = require('p-map')
75
const { equals: uint8ArrayEquals } = require('uint8arrays/equals')
6+
const { compare: uint8ArrayCompare } = require('uint8arrays/compare')
7+
const { xor: uint8ArrayXor } = require('uint8arrays/xor')
88

99
/**
1010
* @typedef {import('peer-id')} PeerId
@@ -56,11 +56,11 @@ class PeerDistanceList {
5656
const dhtKey = await utils.convertPeerId(peerId)
5757
const el = {
5858
peerId,
59-
distance: distance(this.originDhtKey, dhtKey)
59+
distance: uint8ArrayXor(this.originDhtKey, dhtKey)
6060
}
6161

6262
this.peerDistances.push(el)
63-
this.peerDistances.sort((a, b) => distance.compare(a.distance, b.distance))
63+
this.peerDistances.sort((a, b) => uint8ArrayCompare(a.distance, b.distance))
6464
this.peerDistances = this.peerDistances.slice(0, this.capacity)
6565
}
6666

@@ -83,9 +83,9 @@ class PeerDistanceList {
8383
const furthestDistance = this.peerDistances[this.peerDistances.length - 1].distance
8484

8585
for (const dhtKey of dhtKeys) {
86-
const keyDistance = distance(this.originDhtKey, dhtKey)
86+
const keyDistance = uint8ArrayXor(this.originDhtKey, dhtKey)
8787

88-
if (distance.compare(keyDistance, furthestDistance) < 0) {
88+
if (uint8ArrayCompare(keyDistance, furthestDistance) < 0) {
8989
return true
9090
}
9191
}

src/peer-list/peer-queue.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22

33
// @ts-ignore
44
const Heap = require('heap')
5-
// @ts-ignore
6-
const distance = require('xor-distance')
5+
const { xor: uint8ArrayXor } = require('uint8arrays/xor')
76
const debug = require('debug')
87

98
const utils = require('../utils')
@@ -65,7 +64,7 @@ class PeerQueue {
6564

6665
const el = {
6766
id: id,
68-
distance: distance(this.from, key)
67+
distance: uint8ArrayXor(this.from, key)
6968
}
7069

7170
this.heap.push(el)

src/providers.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,12 @@ class Providers {
6868
* Start the provider cleanup service
6969
*/
7070
start () {
71+
if (this._started) {
72+
return
73+
}
74+
75+
this._started = true
76+
7177
this._cleaner = setInterval(
7278
() => this._cleanup(),
7379
this.cleanupInterval
@@ -78,6 +84,8 @@ class Providers {
7884
* Release any resources.
7985
*/
8086
stop () {
87+
this._started = false
88+
8189
if (this._cleaner) {
8290
clearInterval(this._cleaner)
8391
this._cleaner = null

0 commit comments

Comments
 (0)