@libp2p/kad-dht 13.1.2 → 14.0.0-d4da56961
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/index.min.js +2 -2
- package/dist/src/index.d.ts +28 -6
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/kad-dht.d.ts.map +1 -1
- package/dist/src/kad-dht.js +25 -11
- package/dist/src/kad-dht.js.map +1 -1
- package/dist/src/network.d.ts +1 -1
- package/dist/src/network.d.ts.map +1 -1
- package/dist/src/network.js +1 -3
- package/dist/src/network.js.map +1 -1
- package/dist/src/peer-distance-list.d.ts.map +1 -0
- package/dist/src/{peer-list/peer-distance-list.js → peer-distance-list.js} +1 -1
- package/dist/src/peer-distance-list.js.map +1 -0
- package/dist/src/peer-routing/index.js +1 -1
- package/dist/src/peer-routing/index.js.map +1 -1
- package/dist/src/query-self.d.ts.map +1 -1
- package/dist/src/query-self.js +13 -6
- package/dist/src/query-self.js.map +1 -1
- package/dist/src/routing-table/closest-peers.d.ts +43 -0
- package/dist/src/routing-table/closest-peers.d.ts.map +1 -0
- package/dist/src/routing-table/closest-peers.js +86 -0
- package/dist/src/routing-table/closest-peers.js.map +1 -0
- package/dist/src/routing-table/index.d.ts +55 -32
- package/dist/src/routing-table/index.d.ts.map +1 -1
- package/dist/src/routing-table/index.js +259 -161
- package/dist/src/routing-table/index.js.map +1 -1
- package/dist/src/routing-table/k-bucket.d.ts +65 -21
- package/dist/src/routing-table/k-bucket.d.ts.map +1 -1
- package/dist/src/routing-table/k-bucket.js +122 -66
- package/dist/src/routing-table/k-bucket.js.map +1 -1
- package/dist/src/routing-table/refresh.d.ts.map +1 -1
- package/dist/src/routing-table/refresh.js +4 -1
- package/dist/src/routing-table/refresh.js.map +1 -1
- package/dist/src/rpc/index.d.ts.map +1 -1
- package/dist/src/rpc/index.js +3 -7
- package/dist/src/rpc/index.js.map +1 -1
- package/package.json +11 -12
- package/src/index.ts +32 -6
- package/src/kad-dht.ts +29 -13
- package/src/network.ts +1 -4
- package/src/{peer-list/peer-distance-list.ts → peer-distance-list.ts} +1 -1
- package/src/peer-routing/index.ts +1 -1
- package/src/query-self.ts +14 -6
- package/src/routing-table/closest-peers.ts +113 -0
- package/src/routing-table/index.ts +300 -194
- package/src/routing-table/k-bucket.ts +194 -81
- package/src/routing-table/refresh.ts +5 -1
- package/src/rpc/index.ts +4 -7
- package/dist/src/peer-list/index.d.ts +0 -29
- package/dist/src/peer-list/index.d.ts.map +0 -1
- package/dist/src/peer-list/index.js +0 -45
- package/dist/src/peer-list/index.js.map +0 -1
- package/dist/src/peer-list/peer-distance-list.d.ts.map +0 -1
- package/dist/src/peer-list/peer-distance-list.js.map +0 -1
- package/dist/typedoc-urls.json +0 -56
- package/src/peer-list/index.ts +0 -54
- /package/dist/src/{peer-list/peer-distance-list.d.ts → peer-distance-list.d.ts} +0 -0
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@libp2p/kad-dht",
|
3
|
-
"version": "
|
3
|
+
"version": "14.0.0-d4da56961",
|
4
4
|
"description": "JavaScript implementation of the Kad-DHT for libp2p",
|
5
5
|
"license": "Apache-2.0 OR MIT",
|
6
6
|
"homepage": "https://github.com/libp2p/js-libp2p/tree/main/packages/kad-dht#readme",
|
@@ -57,13 +57,13 @@
|
|
57
57
|
"doc-check": "aegir doc-check"
|
58
58
|
},
|
59
59
|
"dependencies": {
|
60
|
-
"@libp2p/crypto": "
|
61
|
-
"@libp2p/interface": "
|
62
|
-
"@libp2p/interface-internal": "
|
63
|
-
"@libp2p/peer-collections": "
|
64
|
-
"@libp2p/peer-id": "
|
65
|
-
"@libp2p/record": "
|
66
|
-
"@libp2p/utils": "
|
60
|
+
"@libp2p/crypto": "5.0.4-d4da56961",
|
61
|
+
"@libp2p/interface": "2.1.2-d4da56961",
|
62
|
+
"@libp2p/interface-internal": "2.0.7-d4da56961",
|
63
|
+
"@libp2p/peer-collections": "6.0.7-d4da56961",
|
64
|
+
"@libp2p/peer-id": "5.0.4-d4da56961",
|
65
|
+
"@libp2p/record": "4.0.4-d4da56961",
|
66
|
+
"@libp2p/utils": "6.1.0-d4da56961",
|
67
67
|
"@multiformats/multiaddr": "^12.2.3",
|
68
68
|
"any-signal": "^4.1.1",
|
69
69
|
"hashlru": "^2.3.0",
|
@@ -89,9 +89,9 @@
|
|
89
89
|
"uint8arrays": "^5.1.0"
|
90
90
|
},
|
91
91
|
"devDependencies": {
|
92
|
-
"@libp2p/interface-compliance-tests": "
|
93
|
-
"@libp2p/logger": "
|
94
|
-
"@libp2p/peer-store": "
|
92
|
+
"@libp2p/interface-compliance-tests": "6.1.5-d4da56961",
|
93
|
+
"@libp2p/logger": "5.1.0-d4da56961",
|
94
|
+
"@libp2p/peer-store": "11.0.7-d4da56961",
|
95
95
|
"@types/lodash.random": "^3.2.9",
|
96
96
|
"@types/lodash.range": "^3.2.9",
|
97
97
|
"@types/sinon": "^17.0.3",
|
@@ -109,7 +109,6 @@
|
|
109
109
|
"lodash.random": "^3.2.0",
|
110
110
|
"lodash.range": "^3.2.0",
|
111
111
|
"p-retry": "^6.2.0",
|
112
|
-
"p-wait-for": "^5.0.2",
|
113
112
|
"protons": "^7.5.0",
|
114
113
|
"sinon": "^18.0.0",
|
115
114
|
"sinon-ts": "^2.0.0",
|
package/src/index.ts
CHANGED
@@ -397,12 +397,10 @@ export interface KadDHTInit {
|
|
397
397
|
logPrefix?: string
|
398
398
|
|
399
399
|
/**
|
400
|
-
*
|
401
|
-
* should be evicted from the routing table or not.
|
402
|
-
*
|
403
|
-
* @default 10000
|
400
|
+
* Settings for how long to wait in ms when pinging DHT peers to decide if
|
401
|
+
* they should be evicted from the routing table or not.
|
404
402
|
*/
|
405
|
-
|
403
|
+
pingOldContactTimeout?: Omit<AdaptiveTimeoutInit, 'metricsName' | 'metrics'>
|
406
404
|
|
407
405
|
/**
|
408
406
|
* How many peers to ping in parallel when deciding if they should
|
@@ -410,7 +408,35 @@ export interface KadDHTInit {
|
|
410
408
|
*
|
411
409
|
* @default 10
|
412
410
|
*/
|
413
|
-
|
411
|
+
pingOldContactConcurrency?: number
|
412
|
+
|
413
|
+
/**
|
414
|
+
* How long the queue to ping peers is allowed to grow
|
415
|
+
*
|
416
|
+
* @default 100
|
417
|
+
*/
|
418
|
+
pingOldContactMaxQueueSize?: number
|
419
|
+
|
420
|
+
/**
|
421
|
+
* Settings for how long to wait in ms when pinging DHT peers to decide if
|
422
|
+
* they should be added to the routing table or not.
|
423
|
+
*/
|
424
|
+
pingNewContactTimeout?: Omit<AdaptiveTimeoutInit, 'metricsName' | 'metrics'>
|
425
|
+
|
426
|
+
/**
|
427
|
+
* How many peers to ping in parallel when deciding if they should be added to
|
428
|
+
* the routing table or not
|
429
|
+
*
|
430
|
+
* @default 10
|
431
|
+
*/
|
432
|
+
pingNewContactConcurrency?: number
|
433
|
+
|
434
|
+
/**
|
435
|
+
* How long the queue to ping peers is allowed to grow
|
436
|
+
*
|
437
|
+
* @default 100
|
438
|
+
*/
|
439
|
+
pingNewContactMaxQueueSize?: number
|
414
440
|
|
415
441
|
/**
|
416
442
|
* How many parallel incoming streams to allow on the DHT protocol per
|
package/src/kad-dht.ts
CHANGED
@@ -138,8 +138,6 @@ export class KadDHT extends TypedEventEmitter<PeerDiscoveryEvents> implements Ka
|
|
138
138
|
querySelfInterval,
|
139
139
|
protocol,
|
140
140
|
logPrefix,
|
141
|
-
pingTimeout,
|
142
|
-
pingConcurrency,
|
143
141
|
maxInboundStreams,
|
144
142
|
maxOutboundStreams,
|
145
143
|
providers: providersInit
|
@@ -156,13 +154,6 @@ export class KadDHT extends TypedEventEmitter<PeerDiscoveryEvents> implements Ka
|
|
156
154
|
this.maxInboundStreams = maxInboundStreams ?? DEFAULT_MAX_INBOUND_STREAMS
|
157
155
|
this.maxOutboundStreams = maxOutboundStreams ?? DEFAULT_MAX_OUTBOUND_STREAMS
|
158
156
|
this.peerInfoMapper = init.peerInfoMapper ?? removePrivateAddressesMapper
|
159
|
-
this.routingTable = new RoutingTable(components, {
|
160
|
-
kBucketSize,
|
161
|
-
pingTimeout,
|
162
|
-
pingConcurrency,
|
163
|
-
protocol: this.protocol,
|
164
|
-
logPrefix: loggingPrefix
|
165
|
-
})
|
166
157
|
|
167
158
|
this.providers = new Providers(components, providersInit ?? {})
|
168
159
|
|
@@ -179,6 +170,21 @@ export class KadDHT extends TypedEventEmitter<PeerDiscoveryEvents> implements Ka
|
|
179
170
|
logPrefix: loggingPrefix
|
180
171
|
})
|
181
172
|
|
173
|
+
this.routingTable = new RoutingTable(components, {
|
174
|
+
kBucketSize,
|
175
|
+
pingOldContactTimeout: init.pingOldContactTimeout,
|
176
|
+
pingOldContactConcurrency: init.pingOldContactConcurrency,
|
177
|
+
pingOldContactMaxQueueSize: init.pingOldContactMaxQueueSize,
|
178
|
+
pingNewContactTimeout: init.pingNewContactTimeout,
|
179
|
+
pingNewContactConcurrency: init.pingNewContactConcurrency,
|
180
|
+
pingNewContactMaxQueueSize: init.pingNewContactMaxQueueSize,
|
181
|
+
protocol: this.protocol,
|
182
|
+
logPrefix: loggingPrefix,
|
183
|
+
prefixLength: init.prefixLength,
|
184
|
+
splitThreshold: init.kBucketSplitThreshold,
|
185
|
+
network: this.network
|
186
|
+
})
|
187
|
+
|
182
188
|
// all queries should wait for the initial query-self query to run so we have
|
183
189
|
// some peers and don't force consumers to use arbitrary timeouts
|
184
190
|
const initialQuerySelfHasRun = pDefer<any>()
|
@@ -374,11 +380,17 @@ export class KadDHT extends TypedEventEmitter<PeerDiscoveryEvents> implements Ka
|
|
374
380
|
|
375
381
|
await this.components.registrar.unhandle(this.protocol)
|
376
382
|
|
383
|
+
// check again after async work
|
384
|
+
if (mode === this.getMode() && !force) {
|
385
|
+
this.log('already in %s mode', mode)
|
386
|
+
return
|
387
|
+
}
|
388
|
+
|
377
389
|
if (mode === 'client') {
|
378
|
-
this.log('enabling client mode')
|
390
|
+
this.log('enabling client mode while in %s mode', this.getMode())
|
379
391
|
this.clientMode = true
|
380
392
|
} else {
|
381
|
-
this.log('enabling server mode')
|
393
|
+
this.log('enabling server mode while in %s mode', this.getMode())
|
382
394
|
this.clientMode = false
|
383
395
|
await this.components.registrar.handle(this.protocol, this.rpc.onIncomingStream.bind(this.rpc), {
|
384
396
|
maxInboundStreams: this.maxInboundStreams,
|
@@ -397,14 +409,18 @@ export class KadDHT extends TypedEventEmitter<PeerDiscoveryEvents> implements Ka
|
|
397
409
|
await this.setMode(this.clientMode ? 'client' : 'server', true)
|
398
410
|
|
399
411
|
await start(
|
400
|
-
this.
|
412
|
+
this.routingTable,
|
401
413
|
this.providers,
|
402
414
|
this.queryManager,
|
403
415
|
this.network,
|
404
|
-
this.routingTable,
|
405
416
|
this.topologyListener,
|
406
417
|
this.routingTableRefresh
|
407
418
|
)
|
419
|
+
|
420
|
+
// Query self after other components are configured
|
421
|
+
await start(
|
422
|
+
this.querySelf
|
423
|
+
)
|
408
424
|
}
|
409
425
|
|
410
426
|
/**
|
package/src/network.ts
CHANGED
@@ -85,7 +85,7 @@ export class Network extends TypedEventEmitter<NetworkEvents> implements Startab
|
|
85
85
|
}
|
86
86
|
|
87
87
|
/**
|
88
|
-
* Send a request and
|
88
|
+
* Send a request and read a response
|
89
89
|
*/
|
90
90
|
async * sendRequest (to: PeerId, msg: Partial<Message>, options: RoutingOptions = {}): AsyncGenerator<QueryEvent> {
|
91
91
|
if (!this.running) {
|
@@ -204,7 +204,6 @@ export class Network extends TypedEventEmitter<NetworkEvents> implements Startab
|
|
204
204
|
async _writeMessage (stream: Stream, msg: Partial<Message>, options: AbortOptions): Promise<void> {
|
205
205
|
const pb = pbStream(stream)
|
206
206
|
await pb.write(msg, Message, options)
|
207
|
-
await pb.unwrap().close(options)
|
208
207
|
}
|
209
208
|
|
210
209
|
/**
|
@@ -219,8 +218,6 @@ export class Network extends TypedEventEmitter<NetworkEvents> implements Startab
|
|
219
218
|
|
220
219
|
const message = await pb.read(Message, options)
|
221
220
|
|
222
|
-
await pb.unwrap().close(options)
|
223
|
-
|
224
221
|
// tell any listeners about new peers we've seen
|
225
222
|
message.closer.forEach(peerData => {
|
226
223
|
this.safeDispatchEvent<PeerInfo>('peer', {
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import { xor as uint8ArrayXor } from 'uint8arrays/xor'
|
2
2
|
import { xorCompare as uint8ArrayXorCompare } from 'uint8arrays/xor-compare'
|
3
|
-
import { convertPeerId } from '
|
3
|
+
import { convertPeerId } from './utils.js'
|
4
4
|
import type { PeerId, PeerInfo } from '@libp2p/interface'
|
5
5
|
|
6
6
|
interface PeerDistance {
|
@@ -5,7 +5,7 @@ import { Libp2pRecord } from '@libp2p/record'
|
|
5
5
|
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
|
6
6
|
import { QueryError, InvalidRecordError } from '../errors.js'
|
7
7
|
import { MessageType } from '../message/dht.js'
|
8
|
-
import { PeerDistanceList } from '../peer-
|
8
|
+
import { PeerDistanceList } from '../peer-distance-list.js'
|
9
9
|
import {
|
10
10
|
queryErrorEvent,
|
11
11
|
finalPeerEvent,
|
package/src/query-self.ts
CHANGED
@@ -106,19 +106,27 @@ export class QuerySelf implements Startable {
|
|
106
106
|
|
107
107
|
if (this.started) {
|
108
108
|
this.controller = new AbortController()
|
109
|
-
const
|
110
|
-
const signal = anySignal([this.controller.signal, timeoutSignal])
|
109
|
+
const signals = [this.controller.signal]
|
111
110
|
|
112
|
-
//
|
113
|
-
|
111
|
+
// add a shorter timeout if we've already run our initial self query
|
112
|
+
if (this.initialQuerySelfHasRun == null) {
|
113
|
+
const timeoutSignal = AbortSignal.timeout(this.queryTimeout)
|
114
|
+
setMaxListeners(Infinity, timeoutSignal)
|
115
|
+
signals.push(timeoutSignal)
|
116
|
+
}
|
117
|
+
|
118
|
+
const signal = anySignal(signals)
|
119
|
+
setMaxListeners(Infinity, signal, this.controller.signal)
|
114
120
|
|
115
121
|
try {
|
116
122
|
if (this.routingTable.size === 0) {
|
117
123
|
this.log('routing table was empty, waiting for some peers before running query')
|
118
|
-
// wait to discover at least one DHT peer
|
124
|
+
// wait to discover at least one DHT peer that isn't us
|
119
125
|
await pEvent(this.routingTable, 'peer:add', {
|
120
|
-
signal
|
126
|
+
signal,
|
127
|
+
filter: (event) => !this.peerId.equals(event.detail)
|
121
128
|
})
|
129
|
+
this.log('routing table has peers, continuing with query')
|
122
130
|
}
|
123
131
|
|
124
132
|
this.log('run self-query, look for %d peers timing out after %dms', this.count, this.queryTimeout)
|
@@ -0,0 +1,113 @@
|
|
1
|
+
import { KEEP_ALIVE } from '@libp2p/interface'
|
2
|
+
import { PeerSet } from '@libp2p/peer-collections'
|
3
|
+
import { PeerDistanceList } from '../peer-distance-list.js'
|
4
|
+
import { convertPeerId } from '../utils.js'
|
5
|
+
import type { RoutingTable } from './index.js'
|
6
|
+
import type { ComponentLogger, Logger, Metrics, PeerId, PeerStore, Startable } from '@libp2p/interface'
|
7
|
+
|
8
|
+
export const PEER_SET_SIZE = 20
|
9
|
+
export const REFRESH_INTERVAL = 5000
|
10
|
+
export const KAD_CLOSE_TAG_NAME = 'kad-close'
|
11
|
+
export const KAD_CLOSE_TAG_VALUE = 50
|
12
|
+
|
13
|
+
export interface ClosestPeersInit {
|
14
|
+
logPrefix: string
|
15
|
+
routingTable: RoutingTable
|
16
|
+
peerSetSize?: number
|
17
|
+
refreshInterval?: number
|
18
|
+
closeTagName?: string
|
19
|
+
closeTagValue?: number
|
20
|
+
}
|
21
|
+
|
22
|
+
export interface ClosestPeersComponents {
|
23
|
+
peerId: PeerId
|
24
|
+
peerStore: PeerStore
|
25
|
+
metrics?: Metrics
|
26
|
+
logger: ComponentLogger
|
27
|
+
}
|
28
|
+
|
29
|
+
/**
|
30
|
+
* Contains a list of the kad-closest peers encountered on the network.
|
31
|
+
*
|
32
|
+
* Once every few seconds, if the list has changed, it tags the closest peers.
|
33
|
+
*/
|
34
|
+
export class ClosestPeers implements Startable {
|
35
|
+
private readonly routingTable: RoutingTable
|
36
|
+
private readonly components: ClosestPeersComponents
|
37
|
+
private closestPeers: PeerSet
|
38
|
+
private newPeers?: PeerDistanceList
|
39
|
+
private readonly refreshInterval: number
|
40
|
+
private readonly peerSetSize: number
|
41
|
+
private timeout?: ReturnType<typeof setTimeout>
|
42
|
+
private readonly closeTagName: string
|
43
|
+
private readonly closeTagValue: number
|
44
|
+
private readonly log: Logger
|
45
|
+
|
46
|
+
constructor (components: ClosestPeersComponents, init: ClosestPeersInit) {
|
47
|
+
this.components = components
|
48
|
+
this.log = components.logger.forComponent(`${init.logPrefix}:routing-table`)
|
49
|
+
this.routingTable = init.routingTable
|
50
|
+
this.refreshInterval = init.refreshInterval ?? REFRESH_INTERVAL
|
51
|
+
this.peerSetSize = init.peerSetSize ?? PEER_SET_SIZE
|
52
|
+
this.closeTagName = init.closeTagName ?? KAD_CLOSE_TAG_NAME
|
53
|
+
this.closeTagValue = init.closeTagValue ?? KAD_CLOSE_TAG_VALUE
|
54
|
+
|
55
|
+
this.closestPeers = new PeerSet()
|
56
|
+
this.onPeerPing = this.onPeerPing.bind(this)
|
57
|
+
}
|
58
|
+
|
59
|
+
async start (): Promise<void> {
|
60
|
+
const targetKadId = await convertPeerId(this.components.peerId)
|
61
|
+
this.newPeers = new PeerDistanceList(targetKadId, this.peerSetSize)
|
62
|
+
this.routingTable.addEventListener('peer:ping', this.onPeerPing)
|
63
|
+
|
64
|
+
this.timeout = setInterval(() => {
|
65
|
+
this.updatePeerTags()
|
66
|
+
.catch(err => {
|
67
|
+
this.log.error('error updating peer tags - %e', err)
|
68
|
+
})
|
69
|
+
}, this.refreshInterval)
|
70
|
+
}
|
71
|
+
|
72
|
+
stop (): void {
|
73
|
+
this.routingTable.removeEventListener('peer:ping', this.onPeerPing)
|
74
|
+
clearTimeout(this.timeout)
|
75
|
+
}
|
76
|
+
|
77
|
+
onPeerPing (event: CustomEvent<PeerId>): void {
|
78
|
+
this.newPeers?.add({ id: event.detail, multiaddrs: [] })
|
79
|
+
.catch(err => {
|
80
|
+
this.log.error('error adding peer to distance list - %e', err)
|
81
|
+
})
|
82
|
+
}
|
83
|
+
|
84
|
+
async updatePeerTags (): Promise<void> {
|
85
|
+
const newClosest = new PeerSet(this.newPeers?.peers.map(peer => peer.id))
|
86
|
+
const added = newClosest.difference(this.closestPeers)
|
87
|
+
const removed = this.closestPeers.difference(newClosest)
|
88
|
+
this.closestPeers = newClosest
|
89
|
+
|
90
|
+
await Promise.all([
|
91
|
+
...[...added].map(async peerId => {
|
92
|
+
await this.components.peerStore.merge(peerId, {
|
93
|
+
tags: {
|
94
|
+
[this.closeTagName]: {
|
95
|
+
value: this.closeTagValue
|
96
|
+
},
|
97
|
+
[KEEP_ALIVE]: {
|
98
|
+
value: 1
|
99
|
+
}
|
100
|
+
}
|
101
|
+
})
|
102
|
+
}),
|
103
|
+
...[...removed].map(async peerId => {
|
104
|
+
await this.components.peerStore.merge(peerId, {
|
105
|
+
tags: {
|
106
|
+
[this.closeTagName]: undefined,
|
107
|
+
[KEEP_ALIVE]: undefined
|
108
|
+
}
|
109
|
+
})
|
110
|
+
})
|
111
|
+
])
|
112
|
+
}
|
113
|
+
}
|