@libp2p/kad-dht 15.1.2 → 15.1.3-ae595d8db
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.min.js +2 -2
- package/dist/index.min.js.map +4 -4
- package/dist/src/constants.d.ts +2 -0
- package/dist/src/constants.d.ts.map +1 -1
- package/dist/src/constants.js +4 -0
- package/dist/src/constants.js.map +1 -1
- package/dist/src/content-fetching/index.d.ts +2 -2
- package/dist/src/content-fetching/index.d.ts.map +1 -1
- package/dist/src/content-fetching/index.js +6 -6
- package/dist/src/content-fetching/index.js.map +1 -1
- package/dist/src/content-routing/index.js +3 -3
- package/dist/src/content-routing/index.js.map +1 -1
- package/dist/src/errors.d.ts +0 -6
- package/dist/src/errors.d.ts.map +1 -1
- package/dist/src/errors.js +0 -9
- package/dist/src/errors.js.map +1 -1
- package/dist/src/index.d.ts +24 -5
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/kad-dht.d.ts +8 -5
- package/dist/src/kad-dht.d.ts.map +1 -1
- package/dist/src/kad-dht.js +25 -18
- 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 +2 -1
- package/dist/src/network.js.map +1 -1
- package/dist/src/peer-distance-list.d.ts +4 -4
- package/dist/src/peer-distance-list.d.ts.map +1 -1
- package/dist/src/peer-distance-list.js +6 -6
- package/dist/src/peer-distance-list.js.map +1 -1
- package/dist/src/peer-routing/index.d.ts +6 -5
- package/dist/src/peer-routing/index.d.ts.map +1 -1
- package/dist/src/peer-routing/index.js +21 -32
- package/dist/src/peer-routing/index.js.map +1 -1
- package/dist/src/providers.d.ts +0 -3
- package/dist/src/providers.d.ts.map +1 -1
- package/dist/src/providers.js +11 -31
- package/dist/src/providers.js.map +1 -1
- package/dist/src/query/manager.d.ts.map +1 -1
- package/dist/src/query/manager.js +7 -3
- package/dist/src/query/manager.js.map +1 -1
- package/dist/src/query/query-path.d.ts.map +1 -1
- package/dist/src/query/query-path.js +11 -5
- package/dist/src/query/query-path.js.map +1 -1
- package/dist/src/query-self.d.ts.map +1 -1
- package/dist/src/query-self.js +2 -1
- package/dist/src/query-self.js.map +1 -1
- package/dist/src/record/validators.d.ts +2 -1
- package/dist/src/record/validators.d.ts.map +1 -1
- package/dist/src/record/validators.js +3 -3
- package/dist/src/record/validators.js.map +1 -1
- package/dist/src/reprovider.d.ts +1 -4
- package/dist/src/reprovider.d.ts.map +1 -1
- package/dist/src/reprovider.js +13 -13
- package/dist/src/reprovider.js.map +1 -1
- package/dist/src/routing-table/index.d.ts +6 -5
- package/dist/src/routing-table/index.d.ts.map +1 -1
- package/dist/src/routing-table/index.js +72 -44
- package/dist/src/routing-table/index.js.map +1 -1
- package/dist/src/routing-table/k-bucket.d.ts +20 -8
- package/dist/src/routing-table/k-bucket.d.ts.map +1 -1
- package/dist/src/routing-table/k-bucket.js +35 -16
- package/dist/src/routing-table/k-bucket.js.map +1 -1
- package/dist/src/routing-table/refresh.d.ts +5 -5
- package/dist/src/routing-table/refresh.d.ts.map +1 -1
- package/dist/src/routing-table/refresh.js +21 -15
- package/dist/src/routing-table/refresh.js.map +1 -1
- package/dist/src/rpc/handlers/find-node.d.ts.map +1 -1
- package/dist/src/rpc/handlers/find-node.js +40 -24
- package/dist/src/rpc/handlers/find-node.js.map +1 -1
- package/dist/src/rpc/handlers/get-providers.js +1 -1
- package/dist/src/rpc/handlers/get-providers.js.map +1 -1
- package/dist/src/rpc/handlers/get-value.js +1 -1
- package/dist/src/rpc/handlers/get-value.js.map +1 -1
- package/dist/src/rpc/index.d.ts +2 -1
- package/dist/src/rpc/index.d.ts.map +1 -1
- package/dist/src/rpc/index.js +50 -19
- package/dist/src/rpc/index.js.map +1 -1
- package/dist/src/topology-listener.d.ts +1 -1
- package/dist/src/topology-listener.d.ts.map +1 -1
- package/dist/src/topology-listener.js +1 -1
- package/dist/src/topology-listener.js.map +1 -1
- package/dist/src/utils.d.ts +3 -3
- package/dist/src/utils.d.ts.map +1 -1
- package/dist/src/utils.js +4 -3
- package/dist/src/utils.js.map +1 -1
- package/package.json +17 -17
- package/src/constants.ts +6 -0
- package/src/content-fetching/index.ts +7 -7
- package/src/content-routing/index.ts +3 -3
- package/src/errors.ts +0 -10
- package/src/index.ts +27 -5
- package/src/kad-dht.ts +28 -20
- package/src/network.ts +2 -1
- package/src/peer-distance-list.ts +7 -7
- package/src/peer-routing/index.ts +23 -34
- package/src/providers.ts +15 -33
- package/src/query/manager.ts +7 -3
- package/src/query/query-path.ts +11 -5
- package/src/query-self.ts +3 -1
- package/src/record/validators.ts +4 -3
- package/src/reprovider.ts +13 -16
- package/src/routing-table/index.ts +74 -45
- package/src/routing-table/k-bucket.ts +54 -20
- package/src/routing-table/refresh.ts +21 -16
- package/src/rpc/handlers/find-node.ts +41 -27
- package/src/rpc/handlers/get-providers.ts +1 -1
- package/src/rpc/handlers/get-value.ts +1 -1
- package/src/rpc/index.ts +54 -23
- package/src/topology-listener.ts +1 -1
- package/src/utils.ts +5 -4
- package/dist/typedoc-urls.json +0 -63
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@libp2p/kad-dht",
|
|
3
|
-
"version": "15.1.
|
|
3
|
+
"version": "15.1.3-ae595d8db",
|
|
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",
|
|
@@ -47,21 +47,20 @@
|
|
|
47
47
|
"doc-check": "aegir doc-check"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@libp2p/crypto": "
|
|
51
|
-
"@libp2p/interface": "
|
|
52
|
-
"@libp2p/interface-internal": "
|
|
53
|
-
"@libp2p/peer-collections": "
|
|
54
|
-
"@libp2p/peer-id": "
|
|
55
|
-
"@libp2p/ping": "
|
|
56
|
-
"@libp2p/record": "
|
|
57
|
-
"@libp2p/utils": "
|
|
50
|
+
"@libp2p/crypto": "5.1.5-ae595d8db",
|
|
51
|
+
"@libp2p/interface": "2.10.3-ae595d8db",
|
|
52
|
+
"@libp2p/interface-internal": "2.3.15-ae595d8db",
|
|
53
|
+
"@libp2p/peer-collections": "6.0.31-ae595d8db",
|
|
54
|
+
"@libp2p/peer-id": "5.1.6-ae595d8db",
|
|
55
|
+
"@libp2p/ping": "2.0.33-ae595d8db",
|
|
56
|
+
"@libp2p/record": "4.0.7-ae595d8db",
|
|
57
|
+
"@libp2p/utils": "6.6.6-ae595d8db",
|
|
58
58
|
"@multiformats/multiaddr": "^12.4.0",
|
|
59
59
|
"any-signal": "^4.1.1",
|
|
60
60
|
"interface-datastore": "^8.3.1",
|
|
61
61
|
"it-all": "^3.0.8",
|
|
62
62
|
"it-drain": "^3.0.9",
|
|
63
63
|
"it-length": "^3.0.8",
|
|
64
|
-
"it-length-prefixed": "^10.0.1",
|
|
65
64
|
"it-map": "^3.1.3",
|
|
66
65
|
"it-merge": "^3.0.11",
|
|
67
66
|
"it-parallel": "^3.0.11",
|
|
@@ -69,8 +68,8 @@
|
|
|
69
68
|
"it-protobuf-stream": "^2.0.2",
|
|
70
69
|
"it-pushable": "^3.2.3",
|
|
71
70
|
"it-take": "^3.0.8",
|
|
72
|
-
"
|
|
73
|
-
"multiformats": "^13.3.
|
|
71
|
+
"main-event": "^1.0.1",
|
|
72
|
+
"multiformats": "^13.3.6",
|
|
74
73
|
"p-defer": "^4.0.1",
|
|
75
74
|
"p-event": "^6.0.1",
|
|
76
75
|
"progress-events": "^1.0.1",
|
|
@@ -81,26 +80,27 @@
|
|
|
81
80
|
"uint8arrays": "^5.1.0"
|
|
82
81
|
},
|
|
83
82
|
"devDependencies": {
|
|
84
|
-
"@libp2p/interface-compliance-tests": "
|
|
85
|
-
"@libp2p/logger": "
|
|
86
|
-
"@libp2p/peer-store": "
|
|
83
|
+
"@libp2p/interface-compliance-tests": "6.4.9-ae595d8db",
|
|
84
|
+
"@libp2p/logger": "5.1.19-ae595d8db",
|
|
85
|
+
"@libp2p/peer-store": "11.2.3-ae595d8db",
|
|
87
86
|
"@types/lodash.random": "^3.2.9",
|
|
88
87
|
"@types/lodash.range": "^3.2.9",
|
|
89
88
|
"@types/sinon": "^17.0.4",
|
|
90
89
|
"@types/which": "^3.0.4",
|
|
91
|
-
"aegir": "^47.0.
|
|
90
|
+
"aegir": "^47.0.14",
|
|
92
91
|
"benchmark": "^2.1.4",
|
|
93
92
|
"datastore-core": "^10.0.2",
|
|
94
93
|
"delay": "^6.0.0",
|
|
95
94
|
"execa": "^9.5.3",
|
|
96
95
|
"it-filter": "^3.1.3",
|
|
97
96
|
"it-last": "^3.0.8",
|
|
97
|
+
"it-length-prefixed": "^10.0.1",
|
|
98
98
|
"it-pair": "^2.0.6",
|
|
99
99
|
"it-stream-types": "^2.0.2",
|
|
100
100
|
"lodash.random": "^3.2.0",
|
|
101
101
|
"lodash.range": "^3.2.0",
|
|
102
102
|
"p-retry": "^6.2.1",
|
|
103
|
-
"protons": "^7.6.
|
|
103
|
+
"protons": "^7.6.1",
|
|
104
104
|
"sinon": "^20.0.0",
|
|
105
105
|
"sinon-ts": "^2.0.0",
|
|
106
106
|
"which": "^5.0.0"
|
package/src/constants.ts
CHANGED
|
@@ -27,8 +27,14 @@ export const REPROVIDE_MAX_QUEUE_SIZE = 16_384
|
|
|
27
27
|
// How often to check if records need re-providing
|
|
28
28
|
export const REPROVIDE_INTERVAL = hour
|
|
29
29
|
|
|
30
|
+
// How long to reprovide for
|
|
31
|
+
export const REPROVIDE_TIMEOUT = hour
|
|
32
|
+
|
|
30
33
|
export const READ_MESSAGE_TIMEOUT = 10 * second
|
|
31
34
|
|
|
35
|
+
// How long to process newly connected peers for
|
|
36
|
+
export const ON_PEER_CONNECT_TIMEOUT = 10 * second
|
|
37
|
+
|
|
32
38
|
// The number of records that will be retrieved on a call to getMany()
|
|
33
39
|
export const GET_MANY_RECORD_COUNT = 16
|
|
34
40
|
|
|
@@ -22,7 +22,7 @@ import type { Network, SendMessageOptions } from '../network.js'
|
|
|
22
22
|
import type { PeerRouting } from '../peer-routing/index.js'
|
|
23
23
|
import type { QueryManager } from '../query/manager.js'
|
|
24
24
|
import type { QueryFunc } from '../query/types.js'
|
|
25
|
-
import type { Logger, RoutingOptions } from '@libp2p/interface'
|
|
25
|
+
import type { AbortOptions, Logger, RoutingOptions } from '@libp2p/interface'
|
|
26
26
|
|
|
27
27
|
export interface ContentFetchingInit {
|
|
28
28
|
validators: Validators
|
|
@@ -68,19 +68,19 @@ export class ContentFetching {
|
|
|
68
68
|
* Attempt to retrieve the value for the given key from
|
|
69
69
|
* the local datastore
|
|
70
70
|
*/
|
|
71
|
-
async getLocal (key: Uint8Array): Promise<Libp2pRecord> {
|
|
71
|
+
async getLocal (key: Uint8Array, options?: AbortOptions): Promise<Libp2pRecord> {
|
|
72
72
|
this.log('getLocal %b', key)
|
|
73
73
|
|
|
74
74
|
const dsKey = bufferToRecordKey(this.datastorePrefix, key)
|
|
75
75
|
|
|
76
76
|
this.log('fetching record for key %k', dsKey)
|
|
77
77
|
|
|
78
|
-
const raw = await this.components.datastore.get(dsKey)
|
|
78
|
+
const raw = await this.components.datastore.get(dsKey, options)
|
|
79
79
|
this.log('found %k in local datastore', dsKey)
|
|
80
80
|
|
|
81
81
|
const rec = Libp2pRecord.deserialize(raw)
|
|
82
82
|
|
|
83
|
-
await verifyRecord(this.validators, rec)
|
|
83
|
+
await verifyRecord(this.validators, rec, options)
|
|
84
84
|
|
|
85
85
|
return rec
|
|
86
86
|
}
|
|
@@ -104,7 +104,7 @@ export class ContentFetching {
|
|
|
104
104
|
try {
|
|
105
105
|
const dsKey = bufferToRecordKey(this.datastorePrefix, key)
|
|
106
106
|
this.log(`Storing corrected record for key ${dsKey.toString()}`)
|
|
107
|
-
await this.components.datastore.put(dsKey, fixupRec.subarray())
|
|
107
|
+
await this.components.datastore.put(dsKey, fixupRec.subarray(), options)
|
|
108
108
|
} catch (err: any) {
|
|
109
109
|
this.log.error('Failed error correcting self', err)
|
|
110
110
|
}
|
|
@@ -148,7 +148,7 @@ export class ContentFetching {
|
|
|
148
148
|
// store the record locally
|
|
149
149
|
const dsKey = bufferToRecordKey(this.datastorePrefix, key)
|
|
150
150
|
this.log(`storing record for key ${dsKey.toString()}`)
|
|
151
|
-
await this.components.datastore.put(dsKey, record.subarray())
|
|
151
|
+
await this.components.datastore.put(dsKey, record.subarray(), options)
|
|
152
152
|
|
|
153
153
|
// put record to the closest peers
|
|
154
154
|
yield * pipe(
|
|
@@ -265,7 +265,7 @@ export class ContentFetching {
|
|
|
265
265
|
this.log('getMany values for %b', key)
|
|
266
266
|
|
|
267
267
|
try {
|
|
268
|
-
const localRec = await this.getLocal(key)
|
|
268
|
+
const localRec = await this.getLocal(key, options)
|
|
269
269
|
|
|
270
270
|
yield valueEvent({
|
|
271
271
|
value: localRec.value,
|
|
@@ -83,7 +83,7 @@ export class ContentRouting {
|
|
|
83
83
|
const target = key.multihash.bytes
|
|
84
84
|
|
|
85
85
|
// Add peer as provider
|
|
86
|
-
await this.providers.addProvider(key, this.components.peerId)
|
|
86
|
+
await this.providers.addProvider(key, this.components.peerId, options)
|
|
87
87
|
|
|
88
88
|
const msg: Partial<Message> = {
|
|
89
89
|
type: MessageType.ADD_PROVIDER,
|
|
@@ -182,7 +182,7 @@ export class ContentRouting {
|
|
|
182
182
|
|
|
183
183
|
this.log('findProviders %c', key)
|
|
184
184
|
|
|
185
|
-
const provs = await this.providers.getProviders(key)
|
|
185
|
+
const provs = await this.providers.getProviders(key, options)
|
|
186
186
|
|
|
187
187
|
// yield values if we have some, also slice because maybe we got lucky and already have too many?
|
|
188
188
|
if (provs.length > 0) {
|
|
@@ -190,7 +190,7 @@ export class ContentRouting {
|
|
|
190
190
|
|
|
191
191
|
for (const peerId of provs.slice(0, toFind)) {
|
|
192
192
|
try {
|
|
193
|
-
const peer = await this.components.peerStore.get(peerId)
|
|
193
|
+
const peer = await this.components.peerStore.get(peerId, options)
|
|
194
194
|
|
|
195
195
|
providers.push({
|
|
196
196
|
id: peerId,
|
package/src/errors.ts
CHANGED
|
@@ -8,16 +8,6 @@ export class QueryError extends Error {
|
|
|
8
8
|
}
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
/**
|
|
12
|
-
* A query was aborted
|
|
13
|
-
*/
|
|
14
|
-
export class QueryAbortedError extends Error {
|
|
15
|
-
constructor (message = 'Query aborted') {
|
|
16
|
-
super(message)
|
|
17
|
-
this.name = 'QueryAbortedError'
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
11
|
/**
|
|
22
12
|
* An invalid record was received
|
|
23
13
|
*/
|
package/src/index.ts
CHANGED
|
@@ -135,11 +135,12 @@
|
|
|
135
135
|
import { KadDHT as KadDHTClass } from './kad-dht.js'
|
|
136
136
|
import { MessageType } from './message/dht.js'
|
|
137
137
|
import { removePrivateAddressesMapper, removePublicAddressesMapper, passthroughMapper } from './utils.js'
|
|
138
|
-
import type { Libp2pEvents, ComponentLogger,
|
|
138
|
+
import type { Libp2pEvents, ComponentLogger, Metrics, PeerId, PeerInfo, PeerStore, RoutingOptions, PrivateKey, AbortOptions } from '@libp2p/interface'
|
|
139
139
|
import type { AddressManager, ConnectionManager, Registrar } from '@libp2p/interface-internal'
|
|
140
140
|
import type { Ping } from '@libp2p/ping'
|
|
141
141
|
import type { AdaptiveTimeoutInit } from '@libp2p/utils/adaptive-timeout'
|
|
142
142
|
import type { Datastore } from 'interface-datastore'
|
|
143
|
+
import type { TypedEventTarget } from 'main-event'
|
|
143
144
|
import type { CID } from 'multiformats/cid'
|
|
144
145
|
import type { ProgressEvent } from 'progress-events'
|
|
145
146
|
|
|
@@ -302,6 +303,10 @@ export interface PeerInfoMapper {
|
|
|
302
303
|
(peer: PeerInfo): PeerInfo
|
|
303
304
|
}
|
|
304
305
|
|
|
306
|
+
export interface SetModeOptions extends AbortOptions {
|
|
307
|
+
force?: boolean
|
|
308
|
+
}
|
|
309
|
+
|
|
305
310
|
export interface KadDHT {
|
|
306
311
|
/**
|
|
307
312
|
* This is the maximum size of the k-buckets and how many peers are looked up
|
|
@@ -350,7 +355,7 @@ export interface KadDHT {
|
|
|
350
355
|
* Provider records must be re-published every 24 hours - pass a previously
|
|
351
356
|
* provided CID here to not re-publish a record for it any more
|
|
352
357
|
*/
|
|
353
|
-
cancelReprovide(key: CID): Promise<void>
|
|
358
|
+
cancelReprovide(key: CID, options?: AbortOptions): Promise<void>
|
|
354
359
|
|
|
355
360
|
/**
|
|
356
361
|
* Store the passed value under the passed key on the DHT
|
|
@@ -366,12 +371,12 @@ export interface KadDHT {
|
|
|
366
371
|
* If 'server' this node will respond to DHT queries, if 'client' this node
|
|
367
372
|
* will not.
|
|
368
373
|
*/
|
|
369
|
-
setMode(mode: 'client' | 'server'): Promise<void>
|
|
374
|
+
setMode(mode: 'client' | 'server', options?: SetModeOptions): Promise<void>
|
|
370
375
|
|
|
371
376
|
/**
|
|
372
377
|
* Force a routing table refresh
|
|
373
378
|
*/
|
|
374
|
-
refreshRoutingTable(): Promise<void>
|
|
379
|
+
refreshRoutingTable(options?: AbortOptions): Promise<void>
|
|
375
380
|
}
|
|
376
381
|
|
|
377
382
|
export interface SingleKadDHT extends KadDHT {
|
|
@@ -388,7 +393,7 @@ export interface SelectFn { (key: Uint8Array, records: Uint8Array[]): number }
|
|
|
388
393
|
* A validator function takes a DHT key and the value of the record for that key
|
|
389
394
|
* and throws if the record is invalid
|
|
390
395
|
*/
|
|
391
|
-
export interface ValidateFn { (key: Uint8Array, value: Uint8Array): Promise<void> }
|
|
396
|
+
export interface ValidateFn { (key: Uint8Array, value: Uint8Array, options?: AbortOptions): Promise<void> }
|
|
392
397
|
|
|
393
398
|
/**
|
|
394
399
|
* Selectors are a map of key prefixes to selector functions
|
|
@@ -680,6 +685,23 @@ export interface KadDHTInit {
|
|
|
680
685
|
* Dynamic network timeout settings for sending messages to peers
|
|
681
686
|
*/
|
|
682
687
|
networkDialTimeout?: Omit<AdaptiveTimeoutInit, 'metricsName' | 'metrics'>
|
|
688
|
+
|
|
689
|
+
/**
|
|
690
|
+
* When a peer that supports the KAD-DHT protocol connects we try to add it to
|
|
691
|
+
* the routing table. This setting is how long we will try to do that for in
|
|
692
|
+
* ms.
|
|
693
|
+
*
|
|
694
|
+
* @default 10_000
|
|
695
|
+
*/
|
|
696
|
+
onPeerConnectTimeout?: number
|
|
697
|
+
|
|
698
|
+
/**
|
|
699
|
+
* When acting as a DHT server, all incoming RPC requests must complete within
|
|
700
|
+
* this timeout in ms otherwise the stream will be closed.
|
|
701
|
+
*
|
|
702
|
+
* @default 10_000
|
|
703
|
+
*/
|
|
704
|
+
incomingMessageTimeout?: number
|
|
683
705
|
}
|
|
684
706
|
|
|
685
707
|
export interface KadDHTComponents {
|
package/src/kad-dht.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { NotFoundError,
|
|
1
|
+
import { NotFoundError, contentRoutingSymbol, peerDiscoverySymbol, peerRoutingSymbol, serviceCapabilities, serviceDependencies, start, stop } from '@libp2p/interface'
|
|
2
2
|
import drain from 'it-drain'
|
|
3
|
-
import
|
|
3
|
+
import { setMaxListeners, TypedEventEmitter } from 'main-event'
|
|
4
4
|
import pDefer from 'p-defer'
|
|
5
|
-
import { ALPHA, PROTOCOL } from './constants.js'
|
|
5
|
+
import { ALPHA, ON_PEER_CONNECT_TIMEOUT, PROTOCOL } from './constants.js'
|
|
6
6
|
import { ContentFetching } from './content-fetching/index.js'
|
|
7
7
|
import { ContentRouting as KADDHTContentRouting } from './content-routing/index.js'
|
|
8
8
|
import { Network } from './network.js'
|
|
@@ -22,8 +22,9 @@ import {
|
|
|
22
22
|
removePrivateAddressesMapper,
|
|
23
23
|
timeOperationGenerator
|
|
24
24
|
} from './utils.js'
|
|
25
|
-
import type { KadDHTComponents, KadDHTInit, Validators, Selectors, KadDHT as KadDHTInterface, QueryEvent, PeerInfoMapper } from './index.js'
|
|
25
|
+
import type { KadDHTComponents, KadDHTInit, Validators, Selectors, KadDHT as KadDHTInterface, QueryEvent, PeerInfoMapper, SetModeOptions } from './index.js'
|
|
26
26
|
import type { ContentRouting, CounterGroup, Logger, MetricGroup, PeerDiscovery, PeerDiscoveryEvents, PeerId, PeerInfo, PeerRouting, RoutingOptions, Startable } from '@libp2p/interface'
|
|
27
|
+
import type { AbortOptions } from 'it-pushable'
|
|
27
28
|
import type { CID } from 'multiformats/cid'
|
|
28
29
|
|
|
29
30
|
/**
|
|
@@ -142,6 +143,7 @@ export class KadDHT extends TypedEventEmitter<PeerDiscoveryEvents> implements Ka
|
|
|
142
143
|
private readonly dhtPeerRouting: DHTPeerRouting
|
|
143
144
|
private readonly peerInfoMapper: PeerInfoMapper
|
|
144
145
|
private readonly reprovider: Reprovider
|
|
146
|
+
private readonly onPeerConnectTimeout: number
|
|
145
147
|
|
|
146
148
|
/**
|
|
147
149
|
* Create a new KadDHT
|
|
@@ -171,14 +173,12 @@ export class KadDHT extends TypedEventEmitter<PeerDiscoveryEvents> implements Ka
|
|
|
171
173
|
this.maxInboundStreams = init.maxInboundStreams ?? DEFAULT_MAX_INBOUND_STREAMS
|
|
172
174
|
this.maxOutboundStreams = init.maxOutboundStreams ?? DEFAULT_MAX_OUTBOUND_STREAMS
|
|
173
175
|
this.peerInfoMapper = init.peerInfoMapper ?? removePrivateAddressesMapper
|
|
174
|
-
|
|
175
|
-
const providerLock = createMortice()
|
|
176
|
+
this.onPeerConnectTimeout = init.onPeerConnectTimeout ?? ON_PEER_CONNECT_TIMEOUT
|
|
176
177
|
|
|
177
178
|
this.providers = new Providers(components, {
|
|
178
179
|
...init.providers,
|
|
179
180
|
logPrefix,
|
|
180
|
-
datastorePrefix
|
|
181
|
-
lock: providerLock
|
|
181
|
+
datastorePrefix
|
|
182
182
|
})
|
|
183
183
|
|
|
184
184
|
this.validators = {
|
|
@@ -289,7 +289,6 @@ export class KadDHT extends TypedEventEmitter<PeerDiscoveryEvents> implements Ka
|
|
|
289
289
|
metricsPrefix,
|
|
290
290
|
datastorePrefix,
|
|
291
291
|
contentRouting: this.contentRouting,
|
|
292
|
-
lock: providerLock,
|
|
293
292
|
operationMetrics
|
|
294
293
|
})
|
|
295
294
|
|
|
@@ -366,7 +365,8 @@ export class KadDHT extends TypedEventEmitter<PeerDiscoveryEvents> implements Ka
|
|
|
366
365
|
readonly [serviceCapabilities]: string[] = [
|
|
367
366
|
'@libp2p/content-routing',
|
|
368
367
|
'@libp2p/peer-routing',
|
|
369
|
-
'@libp2p/peer-discovery'
|
|
368
|
+
'@libp2p/peer-discovery',
|
|
369
|
+
'@libp2p/kad-dht'
|
|
370
370
|
]
|
|
371
371
|
|
|
372
372
|
readonly [serviceDependencies]: string[] = [
|
|
@@ -396,8 +396,13 @@ export class KadDHT extends TypedEventEmitter<PeerDiscoveryEvents> implements Ka
|
|
|
396
396
|
return
|
|
397
397
|
}
|
|
398
398
|
|
|
399
|
+
const signal = AbortSignal.timeout(this.onPeerConnectTimeout)
|
|
400
|
+
setMaxListeners(Infinity, signal)
|
|
401
|
+
|
|
399
402
|
try {
|
|
400
|
-
await this.routingTable.add(peerData.id
|
|
403
|
+
await this.routingTable.add(peerData.id, {
|
|
404
|
+
signal
|
|
405
|
+
})
|
|
401
406
|
} catch (err: any) {
|
|
402
407
|
this.log.error('could not add %p to routing table', peerData.id, err)
|
|
403
408
|
}
|
|
@@ -420,16 +425,16 @@ export class KadDHT extends TypedEventEmitter<PeerDiscoveryEvents> implements Ka
|
|
|
420
425
|
/**
|
|
421
426
|
* If 'server' this node will respond to DHT queries, if 'client' this node will not
|
|
422
427
|
*/
|
|
423
|
-
async setMode (mode: 'client' | 'server',
|
|
424
|
-
if (mode === this.getMode() &&
|
|
428
|
+
async setMode (mode: 'client' | 'server', options?: SetModeOptions): Promise<void> {
|
|
429
|
+
if (mode === this.getMode() && options?.force !== true) {
|
|
425
430
|
this.log('already in %s mode', mode)
|
|
426
431
|
return
|
|
427
432
|
}
|
|
428
433
|
|
|
429
|
-
await this.components.registrar.unhandle(this.protocol)
|
|
434
|
+
await this.components.registrar.unhandle(this.protocol, options)
|
|
430
435
|
|
|
431
436
|
// check again after async work
|
|
432
|
-
if (mode === this.getMode() &&
|
|
437
|
+
if (mode === this.getMode() && options?.force !== true) {
|
|
433
438
|
this.log('already in %s mode', mode)
|
|
434
439
|
return
|
|
435
440
|
}
|
|
@@ -441,6 +446,7 @@ export class KadDHT extends TypedEventEmitter<PeerDiscoveryEvents> implements Ka
|
|
|
441
446
|
this.log('enabling server mode while in %s mode', this.getMode())
|
|
442
447
|
this.clientMode = false
|
|
443
448
|
await this.components.registrar.handle(this.protocol, this.rpc.onIncomingStream.bind(this.rpc), {
|
|
449
|
+
signal: options?.signal,
|
|
444
450
|
maxInboundStreams: this.maxInboundStreams,
|
|
445
451
|
maxOutboundStreams: this.maxOutboundStreams
|
|
446
452
|
})
|
|
@@ -458,7 +464,9 @@ export class KadDHT extends TypedEventEmitter<PeerDiscoveryEvents> implements Ka
|
|
|
458
464
|
this.running = true
|
|
459
465
|
|
|
460
466
|
// Only respond to queries when not in client mode
|
|
461
|
-
await this.setMode(this.clientMode ? 'client' : 'server',
|
|
467
|
+
await this.setMode(this.clientMode ? 'client' : 'server', {
|
|
468
|
+
force: true
|
|
469
|
+
})
|
|
462
470
|
|
|
463
471
|
await start(
|
|
464
472
|
this.routingTable,
|
|
@@ -520,8 +528,8 @@ export class KadDHT extends TypedEventEmitter<PeerDiscoveryEvents> implements Ka
|
|
|
520
528
|
* Provider records must be re-published every 24 hours - pass a previously
|
|
521
529
|
* provided CID here to not re-publish a record for it any more
|
|
522
530
|
*/
|
|
523
|
-
async cancelReprovide (key: CID): Promise<void> {
|
|
524
|
-
await this.providers.removeProvider(key, this.components.peerId)
|
|
531
|
+
async cancelReprovide (key: CID, options?: AbortOptions): Promise<void> {
|
|
532
|
+
await this.providers.removeProvider(key, this.components.peerId, options)
|
|
525
533
|
}
|
|
526
534
|
|
|
527
535
|
/**
|
|
@@ -547,7 +555,7 @@ export class KadDHT extends TypedEventEmitter<PeerDiscoveryEvents> implements Ka
|
|
|
547
555
|
yield * this.peerRouting.getClosestPeers(key, options)
|
|
548
556
|
}
|
|
549
557
|
|
|
550
|
-
async refreshRoutingTable (): Promise<void> {
|
|
551
|
-
this.routingTableRefresh.refreshTable(true)
|
|
558
|
+
async refreshRoutingTable (options?: AbortOptions): Promise<void> {
|
|
559
|
+
this.routingTableRefresh.refreshTable(true, options)
|
|
552
560
|
}
|
|
553
561
|
}
|
package/src/network.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { InvalidParametersError
|
|
1
|
+
import { InvalidParametersError } from '@libp2p/interface'
|
|
2
2
|
import { Libp2pRecord } from '@libp2p/record'
|
|
3
3
|
import { AdaptiveTimeout } from '@libp2p/utils/adaptive-timeout'
|
|
4
4
|
import { pbStream } from 'it-protobuf-stream'
|
|
5
|
+
import { TypedEventEmitter } from 'main-event'
|
|
5
6
|
import { Message } from './message/dht.js'
|
|
6
7
|
import { fromPbPeerInfo } from './message/utils.js'
|
|
7
8
|
import {
|
|
@@ -2,7 +2,7 @@ import { xor as uint8ArrayXor } from 'uint8arrays/xor'
|
|
|
2
2
|
import { xorCompare as uint8ArrayXorCompare } from 'uint8arrays/xor-compare'
|
|
3
3
|
import { convertPeerId } from './utils.js'
|
|
4
4
|
import type { DisjointPath } from './index.js'
|
|
5
|
-
import type { PeerId, PeerInfo } from '@libp2p/interface'
|
|
5
|
+
import type { AbortOptions, PeerId, PeerInfo } from '@libp2p/interface'
|
|
6
6
|
|
|
7
7
|
interface PeerDistance {
|
|
8
8
|
peer: PeerInfo
|
|
@@ -49,8 +49,8 @@ export class PeerDistanceList {
|
|
|
49
49
|
/**
|
|
50
50
|
* Add a peerId to the list.
|
|
51
51
|
*/
|
|
52
|
-
async add (peer: PeerInfo, path: DisjointPath = { index: -1, queued: 0, running: 0, total: 0 }): Promise<void> {
|
|
53
|
-
const dhtKey = await convertPeerId(peer.id)
|
|
52
|
+
async add (peer: PeerInfo, path: DisjointPath = { index: -1, queued: 0, running: 0, total: 0 }, options?: AbortOptions): Promise<void> {
|
|
53
|
+
const dhtKey = await convertPeerId(peer.id, options)
|
|
54
54
|
|
|
55
55
|
this.addWithKadId(peer, dhtKey, path)
|
|
56
56
|
}
|
|
@@ -100,12 +100,12 @@ export class PeerDistanceList {
|
|
|
100
100
|
* Indicates whether any of the peerIds passed as a parameter are closer
|
|
101
101
|
* to the origin key than the furthest peerId in the PeerDistanceList.
|
|
102
102
|
*/
|
|
103
|
-
async isCloser (peerId: PeerId): Promise<boolean> {
|
|
103
|
+
async isCloser (peerId: PeerId, options?: AbortOptions): Promise<boolean> {
|
|
104
104
|
if (this.length === 0) {
|
|
105
105
|
return true
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
-
const dhtKey = await convertPeerId(peerId)
|
|
108
|
+
const dhtKey = await convertPeerId(peerId, options)
|
|
109
109
|
const dhtKeyXor = uint8ArrayXor(dhtKey, this.originDhtKey)
|
|
110
110
|
const furthestDistance = this.peerDistances[this.peerDistances.length - 1].distance
|
|
111
111
|
|
|
@@ -116,13 +116,13 @@ export class PeerDistanceList {
|
|
|
116
116
|
* Indicates whether any of the peerIds passed as a parameter are closer
|
|
117
117
|
* to the origin key than the furthest peerId in the PeerDistanceList.
|
|
118
118
|
*/
|
|
119
|
-
async anyCloser (peerIds: PeerId[]): Promise<boolean> {
|
|
119
|
+
async anyCloser (peerIds: PeerId[], options?: AbortOptions): Promise<boolean> {
|
|
120
120
|
if (peerIds.length === 0) {
|
|
121
121
|
return false
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
return Promise.any(
|
|
125
|
-
peerIds.map(async peerId => this.isCloser(peerId))
|
|
125
|
+
peerIds.map(async peerId => this.isCloser(peerId, options))
|
|
126
126
|
)
|
|
127
127
|
}
|
|
128
128
|
}
|
|
@@ -3,8 +3,6 @@ import { InvalidPublicKeyError, NotFoundError } from '@libp2p/interface'
|
|
|
3
3
|
import { peerIdFromPublicKey, peerIdFromMultihash } from '@libp2p/peer-id'
|
|
4
4
|
import { Libp2pRecord } from '@libp2p/record'
|
|
5
5
|
import * as Digest from 'multiformats/hashes/digest'
|
|
6
|
-
import { xor as uint8ArrayXor } from 'uint8arrays/xor'
|
|
7
|
-
import { xorCompare as uint8ArrayXorCompare } from 'uint8arrays/xor-compare'
|
|
8
6
|
import { QueryError, InvalidRecordError } from '../errors.js'
|
|
9
7
|
import { MessageType } from '../message/dht.js'
|
|
10
8
|
import { PeerDistanceList } from '../peer-distance-list.js'
|
|
@@ -14,15 +12,17 @@ import {
|
|
|
14
12
|
valueEvent
|
|
15
13
|
} from '../query/events.js'
|
|
16
14
|
import { verifyRecord } from '../record/validators.js'
|
|
17
|
-
import { convertBuffer,
|
|
15
|
+
import { convertBuffer, keyForPublicKey } from '../utils.js'
|
|
18
16
|
import type { DHTRecord, FinalPeerEvent, QueryEvent, Validators } from '../index.js'
|
|
19
17
|
import type { Message } from '../message/dht.js'
|
|
20
18
|
import type { Network, SendMessageOptions } from '../network.js'
|
|
21
19
|
import type { QueryManager, QueryOptions } from '../query/manager.js'
|
|
22
20
|
import type { QueryFunc } from '../query/types.js'
|
|
23
21
|
import type { RoutingTable } from '../routing-table/index.js'
|
|
22
|
+
import type { GetClosestPeersOptions } from '../routing-table/k-bucket.ts'
|
|
24
23
|
import type { ComponentLogger, Logger, Metrics, PeerId, PeerInfo, PeerStore, RoutingOptions } from '@libp2p/interface'
|
|
25
24
|
import type { ConnectionManager } from '@libp2p/interface-internal'
|
|
25
|
+
import type { AbortOptions } from 'it-pushable'
|
|
26
26
|
|
|
27
27
|
export interface PeerRoutingComponents {
|
|
28
28
|
peerId: PeerId
|
|
@@ -68,15 +68,15 @@ export class PeerRouting {
|
|
|
68
68
|
* Look if we are connected to a peer with the given id.
|
|
69
69
|
* Returns its id and addresses, if found, otherwise `undefined`.
|
|
70
70
|
*/
|
|
71
|
-
async findPeerLocal (peer: PeerId): Promise<PeerInfo | undefined> {
|
|
71
|
+
async findPeerLocal (peer: PeerId, options?: AbortOptions): Promise<PeerInfo | undefined> {
|
|
72
72
|
let peerData
|
|
73
|
-
const p = await this.routingTable.find(peer)
|
|
73
|
+
const p = await this.routingTable.find(peer, options)
|
|
74
74
|
|
|
75
75
|
if (p != null) {
|
|
76
76
|
this.log('findPeerLocal found %p in routing table', peer)
|
|
77
77
|
|
|
78
78
|
try {
|
|
79
|
-
peerData = await this.components.peerStore.get(p)
|
|
79
|
+
peerData = await this.components.peerStore.get(p, options)
|
|
80
80
|
} catch (err: any) {
|
|
81
81
|
if (err.name !== 'NotFoundError') {
|
|
82
82
|
throw err
|
|
@@ -86,7 +86,7 @@ export class PeerRouting {
|
|
|
86
86
|
|
|
87
87
|
if (peerData == null) {
|
|
88
88
|
try {
|
|
89
|
-
peerData = await this.components.peerStore.get(peer)
|
|
89
|
+
peerData = await this.components.peerStore.get(peer, options)
|
|
90
90
|
} catch (err: any) {
|
|
91
91
|
if (err.name !== 'NotFoundError') {
|
|
92
92
|
throw err
|
|
@@ -168,7 +168,7 @@ export class PeerRouting {
|
|
|
168
168
|
|
|
169
169
|
if (options.useCache !== false) {
|
|
170
170
|
// Try to find locally
|
|
171
|
-
const pi = await this.findPeerLocal(id)
|
|
171
|
+
const pi = await this.findPeerLocal(id, options)
|
|
172
172
|
|
|
173
173
|
// already got it
|
|
174
174
|
if (pi != null) {
|
|
@@ -240,12 +240,12 @@ export class PeerRouting {
|
|
|
240
240
|
*/
|
|
241
241
|
async * getClosestPeers (key: Uint8Array, options: QueryOptions = {}): AsyncGenerator<QueryEvent> {
|
|
242
242
|
this.log('getClosestPeers to %b', key)
|
|
243
|
-
const kadId = await convertBuffer(key)
|
|
243
|
+
const kadId = await convertBuffer(key, options)
|
|
244
244
|
const peers = new PeerDistanceList(kadId, this.routingTable.kBucketSize)
|
|
245
245
|
const self = this
|
|
246
246
|
|
|
247
247
|
const getCloserPeersQuery: QueryFunc = async function * ({ peer, path, peerKadId, signal }) {
|
|
248
|
-
self.log('getClosestPeers asking %p', peer)
|
|
248
|
+
self.log('getClosestPeers asking %p', peer.id)
|
|
249
249
|
const request: Partial<Message> = {
|
|
250
250
|
type: MessageType.FIND_NODE,
|
|
251
251
|
key
|
|
@@ -268,7 +268,7 @@ export class PeerRouting {
|
|
|
268
268
|
for (let { peer, path } of peers.peers) {
|
|
269
269
|
try {
|
|
270
270
|
if (peer.multiaddrs.length === 0) {
|
|
271
|
-
peer = await self.components.peerStore.getInfo(peer.id)
|
|
271
|
+
peer = await self.components.peerStore.getInfo(peer.id, options)
|
|
272
272
|
}
|
|
273
273
|
|
|
274
274
|
if (peer.multiaddrs.length === 0) {
|
|
@@ -277,7 +277,7 @@ export class PeerRouting {
|
|
|
277
277
|
|
|
278
278
|
yield finalPeerEvent({
|
|
279
279
|
from: this.components.peerId,
|
|
280
|
-
peer: await self.components.peerStore.getInfo(peer.id),
|
|
280
|
+
peer: await self.components.peerStore.getInfo(peer.id, options),
|
|
281
281
|
path: {
|
|
282
282
|
index: path.index,
|
|
283
283
|
queued: 0,
|
|
@@ -303,7 +303,7 @@ export class PeerRouting {
|
|
|
303
303
|
if (event.record != null) {
|
|
304
304
|
// We have a record
|
|
305
305
|
try {
|
|
306
|
-
await this._verifyRecordOnline(event.record)
|
|
306
|
+
await this._verifyRecordOnline(event.record, options)
|
|
307
307
|
} catch (err: any) {
|
|
308
308
|
const errMsg = 'invalid record received, discarded'
|
|
309
309
|
this.log(errMsg)
|
|
@@ -326,19 +326,18 @@ export class PeerRouting {
|
|
|
326
326
|
* Verify a record, fetching missing public keys from the network.
|
|
327
327
|
* Throws an error if the record is invalid.
|
|
328
328
|
*/
|
|
329
|
-
async _verifyRecordOnline (record: DHTRecord): Promise<void> {
|
|
329
|
+
async _verifyRecordOnline (record: DHTRecord, options?: AbortOptions): Promise<void> {
|
|
330
330
|
if (record.timeReceived == null) {
|
|
331
331
|
throw new InvalidRecordError('invalid record received')
|
|
332
332
|
}
|
|
333
333
|
|
|
334
|
-
await verifyRecord(this.validators, new Libp2pRecord(record.key, record.value, record.timeReceived))
|
|
334
|
+
await verifyRecord(this.validators, new Libp2pRecord(record.key, record.value, record.timeReceived), options)
|
|
335
335
|
}
|
|
336
336
|
|
|
337
337
|
/**
|
|
338
|
-
* Get the peers in our routing table that are
|
|
339
|
-
* to the passed key
|
|
338
|
+
* Get the peers in our routing table that are closest to the passed key
|
|
340
339
|
*/
|
|
341
|
-
async
|
|
340
|
+
async getClosestPeersOffline (key: Uint8Array, options?: GetClosestPeersOptions): Promise<PeerInfo[]> {
|
|
342
341
|
const output: PeerInfo[] = []
|
|
343
342
|
|
|
344
343
|
// try getting the peer directly
|
|
@@ -346,7 +345,7 @@ export class PeerRouting {
|
|
|
346
345
|
const multihash = Digest.decode(key)
|
|
347
346
|
const targetPeerId = peerIdFromMultihash(multihash)
|
|
348
347
|
|
|
349
|
-
const peer = await this.components.peerStore.get(targetPeerId)
|
|
348
|
+
const peer = await this.components.peerStore.get(targetPeerId, options)
|
|
350
349
|
|
|
351
350
|
output.push({
|
|
352
351
|
id: peer.id,
|
|
@@ -354,22 +353,12 @@ export class PeerRouting {
|
|
|
354
353
|
})
|
|
355
354
|
} catch {}
|
|
356
355
|
|
|
357
|
-
const keyKadId = await convertBuffer(key)
|
|
358
|
-
const ids = this.routingTable.closestPeers(keyKadId)
|
|
359
|
-
const closerThanKadId = await convertPeerId(closerThan)
|
|
360
|
-
const requesterXor = uint8ArrayXor(closerThanKadId, keyKadId)
|
|
356
|
+
const keyKadId = await convertBuffer(key, options)
|
|
357
|
+
const ids = this.routingTable.closestPeers(keyKadId, options)
|
|
361
358
|
|
|
362
359
|
for (const peerId of ids) {
|
|
363
|
-
const peerKadId = await convertPeerId(peerId)
|
|
364
|
-
const peerXor = uint8ArrayXor(peerKadId, keyKadId)
|
|
365
|
-
|
|
366
|
-
// only include if peer is closer than requester
|
|
367
|
-
if (uint8ArrayXorCompare(peerXor, requesterXor) !== -1) {
|
|
368
|
-
continue
|
|
369
|
-
}
|
|
370
|
-
|
|
371
360
|
try {
|
|
372
|
-
output.push(await this.components.peerStore.getInfo(peerId))
|
|
361
|
+
output.push(await this.components.peerStore.getInfo(peerId, options))
|
|
373
362
|
} catch (err: any) {
|
|
374
363
|
if (err.name !== 'NotFoundError') {
|
|
375
364
|
throw err
|
|
@@ -378,9 +367,9 @@ export class PeerRouting {
|
|
|
378
367
|
}
|
|
379
368
|
|
|
380
369
|
if (output.length > 0) {
|
|
381
|
-
this.log('
|
|
370
|
+
this.log('getClosestPeersOffline returning the %d closest peer(s) %b we know', output.length, key)
|
|
382
371
|
} else {
|
|
383
|
-
this.log('
|
|
372
|
+
this.log('getClosestPeersOffline could not any peers close to %b with %d peers in the routing table', key, this.routingTable.size)
|
|
384
373
|
}
|
|
385
374
|
|
|
386
375
|
return output
|