@libp2p/kad-dht 15.0.1 → 15.0.2-185b23eac

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.
Files changed (69) hide show
  1. package/dist/index.min.js +2 -15
  2. package/dist/index.min.js.map +7 -0
  3. package/dist/src/content-fetching/index.d.ts +4 -4
  4. package/dist/src/content-fetching/index.d.ts.map +1 -1
  5. package/dist/src/content-fetching/index.js +14 -7
  6. package/dist/src/content-fetching/index.js.map +1 -1
  7. package/dist/src/content-routing/index.d.ts.map +1 -1
  8. package/dist/src/content-routing/index.js +8 -4
  9. package/dist/src/content-routing/index.js.map +1 -1
  10. package/dist/src/index.d.ts +9 -2
  11. package/dist/src/index.d.ts.map +1 -1
  12. package/dist/src/index.js.map +1 -1
  13. package/dist/src/kad-dht.js +2 -2
  14. package/dist/src/kad-dht.js.map +1 -1
  15. package/dist/src/network.d.ts +10 -2
  16. package/dist/src/network.d.ts.map +1 -1
  17. package/dist/src/network.js +10 -11
  18. package/dist/src/network.js.map +1 -1
  19. package/dist/src/peer-distance-list.d.ts +9 -3
  20. package/dist/src/peer-distance-list.d.ts.map +1 -1
  21. package/dist/src/peer-distance-list.js +6 -5
  22. package/dist/src/peer-distance-list.js.map +1 -1
  23. package/dist/src/peer-routing/index.d.ts +3 -3
  24. package/dist/src/peer-routing/index.d.ts.map +1 -1
  25. package/dist/src/peer-routing/index.js +33 -15
  26. package/dist/src/peer-routing/index.js.map +1 -1
  27. package/dist/src/providers.d.ts +4 -4
  28. package/dist/src/providers.d.ts.map +1 -1
  29. package/dist/src/providers.js +8 -8
  30. package/dist/src/providers.js.map +1 -1
  31. package/dist/src/query/events.d.ts +8 -7
  32. package/dist/src/query/events.d.ts.map +1 -1
  33. package/dist/src/query/events.js +0 -9
  34. package/dist/src/query/events.js.map +1 -1
  35. package/dist/src/query/manager.d.ts +2 -0
  36. package/dist/src/query/manager.d.ts.map +1 -1
  37. package/dist/src/query/manager.js +23 -8
  38. package/dist/src/query/manager.js.map +1 -1
  39. package/dist/src/query/query-path.d.ts +3 -3
  40. package/dist/src/query/query-path.d.ts.map +1 -1
  41. package/dist/src/query/query-path.js +8 -16
  42. package/dist/src/query/query-path.js.map +1 -1
  43. package/dist/src/query/types.d.ts +1 -1
  44. package/dist/src/query/types.d.ts.map +1 -1
  45. package/dist/src/query-self.d.ts +2 -3
  46. package/dist/src/query-self.d.ts.map +1 -1
  47. package/dist/src/query-self.js +11 -14
  48. package/dist/src/query-self.js.map +1 -1
  49. package/dist/src/routing-table/closest-peers.js +1 -1
  50. package/dist/src/routing-table/closest-peers.js.map +1 -1
  51. package/dist/src/routing-table/k-bucket.js +1 -1
  52. package/dist/src/routing-table/k-bucket.js.map +1 -1
  53. package/package.json +12 -12
  54. package/src/content-fetching/index.ts +15 -8
  55. package/src/content-routing/index.ts +8 -4
  56. package/src/index.ts +9 -2
  57. package/src/kad-dht.ts +2 -2
  58. package/src/network.ts +18 -11
  59. package/src/peer-distance-list.ts +9 -7
  60. package/src/peer-routing/index.ts +34 -16
  61. package/src/providers.ts +9 -9
  62. package/src/query/events.ts +8 -19
  63. package/src/query/manager.ts +26 -8
  64. package/src/query/query-path.ts +11 -19
  65. package/src/query/types.ts +1 -1
  66. package/src/query-self.ts +15 -17
  67. package/src/routing-table/closest-peers.ts +1 -1
  68. package/src/routing-table/k-bucket.ts +1 -1
  69. package/dist/typedoc-urls.json +0 -59
@@ -6,6 +6,7 @@ import type { PeerId, PeerInfo } from '@libp2p/interface'
6
6
  interface PeerDistance {
7
7
  peer: PeerInfo
8
8
  distance: Uint8Array
9
+ path: number
9
10
  }
10
11
 
11
12
  /**
@@ -40,30 +41,31 @@ export class PeerDistanceList {
40
41
  /**
41
42
  * The peers in the list, in order of distance from the origin key
42
43
  */
43
- get peers (): PeerInfo[] {
44
- return this.peerDistances.map(pd => pd.peer)
44
+ get peers (): PeerDistance[] {
45
+ return [...this.peerDistances]
45
46
  }
46
47
 
47
48
  /**
48
49
  * Add a peerId to the list.
49
50
  */
50
- async add (peer: PeerInfo): Promise<void> {
51
+ async add (peer: PeerInfo, path: number = -1): Promise<void> {
51
52
  const dhtKey = await convertPeerId(peer.id)
52
53
 
53
- this.addWithKadId(peer, dhtKey)
54
+ this.addWithKadId(peer, dhtKey, path)
54
55
  }
55
56
 
56
57
  /**
57
58
  * Add a peerId to the list.
58
59
  */
59
- addWithKadId (peer: PeerInfo, kadId: Uint8Array): void {
60
+ addWithKadId (peer: PeerInfo, kadId: Uint8Array, path: number = -1): void {
60
61
  if (this.peerDistances.find(pd => pd.peer.id.equals(peer.id)) != null) {
61
62
  return
62
63
  }
63
64
 
64
- const el = {
65
+ const el: PeerDistance = {
65
66
  peer,
66
- distance: uint8ArrayXor(this.originDhtKey, kadId)
67
+ distance: uint8ArrayXor(this.originDhtKey, kadId),
68
+ path
67
69
  }
68
70
 
69
71
  let added = false
@@ -18,7 +18,7 @@ import { verifyRecord } from '../record/validators.js'
18
18
  import { convertBuffer, convertPeerId, keyForPublicKey } from '../utils.js'
19
19
  import type { DHTRecord, FinalPeerEvent, QueryEvent, Validators } from '../index.js'
20
20
  import type { Message } from '../message/dht.js'
21
- import type { Network } from '../network.js'
21
+ import type { Network, SendMessageOptions } from '../network.js'
22
22
  import type { QueryManager, QueryOptions } from '../query/manager.js'
23
23
  import type { QueryFunc } from '../query/types.js'
24
24
  import type { RoutingTable } from '../routing-table/index.js'
@@ -110,7 +110,7 @@ export class PeerRouting {
110
110
  /**
111
111
  * Get a value via rpc call for the given parameters
112
112
  */
113
- async * _getValueSingle (peer: PeerId, key: Uint8Array, options: RoutingOptions = {}): AsyncGenerator<QueryEvent> {
113
+ async * _getValueSingle (peer: PeerId, key: Uint8Array, options: SendMessageOptions): AsyncGenerator<QueryEvent> {
114
114
  const msg: Partial<Message> = {
115
115
  type: MessageType.GET_VALUE,
116
116
  key
@@ -125,7 +125,10 @@ export class PeerRouting {
125
125
  async * getPublicKeyFromNode (peer: PeerId, options: RoutingOptions = {}): AsyncGenerator<QueryEvent> {
126
126
  const pkKey = keyForPublicKey(peer)
127
127
 
128
- for await (const event of this._getValueSingle(peer, pkKey, options)) {
128
+ for await (const event of this._getValueSingle(peer, pkKey, {
129
+ ...options,
130
+ path: -1
131
+ })) {
129
132
  yield event
130
133
 
131
134
  if (event.name === 'PEER_RESPONSE' && event.record != null) {
@@ -166,7 +169,8 @@ export class PeerRouting {
166
169
  this.log('found local')
167
170
  yield finalPeerEvent({
168
171
  from: this.peerId,
169
- peer: pi
172
+ peer: pi,
173
+ path: -1
170
174
  }, options)
171
175
  return
172
176
  }
@@ -177,7 +181,7 @@ export class PeerRouting {
177
181
  if (options.useNetwork !== false) {
178
182
  const self = this // eslint-disable-line @typescript-eslint/no-this-alias
179
183
 
180
- const findPeerQuery: QueryFunc = async function * ({ peer, signal }) {
184
+ const findPeerQuery: QueryFunc = async function * ({ peer, signal, path }) {
181
185
  const request: Partial<Message> = {
182
186
  type: MessageType.FIND_NODE,
183
187
  key: id.toMultihash().bytes
@@ -185,7 +189,8 @@ export class PeerRouting {
185
189
 
186
190
  for await (const event of self.network.sendRequest(peer, request, {
187
191
  ...options,
188
- signal
192
+ signal,
193
+ path
189
194
  })) {
190
195
  yield event
191
196
 
@@ -194,7 +199,11 @@ export class PeerRouting {
194
199
 
195
200
  // found the peer
196
201
  if (match != null) {
197
- yield finalPeerEvent({ from: event.from, peer: match }, options)
202
+ yield finalPeerEvent({
203
+ from: event.from,
204
+ peer: match,
205
+ path: event.path
206
+ }, options)
198
207
  }
199
208
  }
200
209
  }
@@ -210,7 +219,10 @@ export class PeerRouting {
210
219
  }
211
220
 
212
221
  if (!foundPeer) {
213
- yield queryErrorEvent({ from: this.peerId, error: new NotFoundError('Not found') }, options)
222
+ yield queryErrorEvent({
223
+ from: this.peerId,
224
+ error: new NotFoundError('Not found')
225
+ }, options)
214
226
  }
215
227
  }
216
228
 
@@ -225,9 +237,9 @@ export class PeerRouting {
225
237
  const self = this // eslint-disable-line @typescript-eslint/no-this-alias
226
238
 
227
239
  const peers = new PeerDistanceList(kadId, this.routingTable.kBucketSize)
228
- await Promise.all(tablePeers.map(async peer => { await peers.add({ id: peer, multiaddrs: [] }) }))
240
+ await Promise.all(tablePeers.map(async peer => { await peers.add({ id: peer, multiaddrs: [] }, -1) }))
229
241
 
230
- const getCloserPeersQuery: QueryFunc = async function * ({ peer, signal }) {
242
+ const getCloserPeersQuery: QueryFunc = async function * ({ peer, signal, path }) {
231
243
  self.log('closerPeersSingle %s from %p', uint8ArrayToString(key, 'base32'), peer)
232
244
  const request: Partial<Message> = {
233
245
  type: MessageType.FIND_NODE,
@@ -236,14 +248,15 @@ export class PeerRouting {
236
248
 
237
249
  yield * self.network.sendRequest(peer, request, {
238
250
  ...options,
239
- signal
251
+ signal,
252
+ path
240
253
  })
241
254
  }
242
255
 
243
256
  for await (const event of this.queryManager.run(key, getCloserPeersQuery, options)) {
244
257
  if (event.name === 'PEER_RESPONSE') {
245
258
  await Promise.all(event.closer.map(async peerData => {
246
- await peers.add(peerData)
259
+ await peers.add(peerData, event.path)
247
260
  }))
248
261
  }
249
262
 
@@ -252,10 +265,11 @@ export class PeerRouting {
252
265
 
253
266
  this.log('found %d peers close to %b', peers.length, key)
254
267
 
255
- for (const peer of peers.peers) {
268
+ for (const { peer, path } of peers.peers) {
256
269
  yield finalPeerEvent({
257
270
  from: this.peerId,
258
- peer
271
+ peer,
272
+ path
259
273
  }, options)
260
274
  }
261
275
  }
@@ -266,7 +280,7 @@ export class PeerRouting {
266
280
  *
267
281
  * Note: The peerStore is updated with new addresses found for the given peer.
268
282
  */
269
- async * getValueOrPeers (peer: PeerId, key: Uint8Array, options: RoutingOptions = {}): AsyncGenerator<QueryEvent> {
283
+ async * getValueOrPeers (peer: PeerId, key: Uint8Array, options: SendMessageOptions): AsyncGenerator<QueryEvent> {
270
284
  for await (const event of this._getValueSingle(peer, key, options)) {
271
285
  if (event.name === 'PEER_RESPONSE') {
272
286
  if (event.record != null) {
@@ -277,7 +291,11 @@ export class PeerRouting {
277
291
  const errMsg = 'invalid record received, discarded'
278
292
  this.log(errMsg)
279
293
 
280
- yield queryErrorEvent({ from: event.from, error: new QueryError(errMsg) }, options)
294
+ yield queryErrorEvent({
295
+ from: event.from,
296
+ error: new QueryError(errMsg),
297
+ path: options.path
298
+ }, options)
281
299
  continue
282
300
  }
283
301
  }
package/src/providers.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { PeerMap } from '@libp2p/peer-collections'
2
2
  import * as varint from 'uint8-varint'
3
3
  import { parseProviderKey, readProviderTime, toProviderKey } from './utils.js'
4
- import type { ComponentLogger, Logger, Metrics, PeerId } from '@libp2p/interface'
4
+ import type { AbortOptions, ComponentLogger, Logger, Metrics, PeerId } from '@libp2p/interface'
5
5
  import type { Datastore } from 'interface-datastore'
6
6
  import type { Mortice } from 'mortice'
7
7
  import type { CID } from 'multiformats'
@@ -37,7 +37,7 @@ export class Providers {
37
37
  /**
38
38
  * Add a new provider for the given CID
39
39
  */
40
- async addProvider (cid: CID, provider: PeerId): Promise<void> {
40
+ async addProvider (cid: CID, provider: PeerId, options?: AbortOptions): Promise<void> {
41
41
  const release = await this.lock.readLock()
42
42
 
43
43
  try {
@@ -51,7 +51,7 @@ export class Providers {
51
51
  /**
52
52
  * Remove a provider for the given CID
53
53
  */
54
- async removeProvider (cid: CID, provider: PeerId): Promise<void> {
54
+ async removeProvider (cid: CID, provider: PeerId, options?: AbortOptions): Promise<void> {
55
55
  const release = await this.lock.writeLock()
56
56
 
57
57
  try {
@@ -66,12 +66,12 @@ export class Providers {
66
66
  /**
67
67
  * Get a list of providers for the given CID
68
68
  */
69
- async getProviders (cid: CID): Promise<PeerId[]> {
69
+ async getProviders (cid: CID, options?: AbortOptions): Promise<PeerId[]> {
70
70
  const release = await this.lock.readLock()
71
71
 
72
72
  try {
73
73
  this.log('get providers for %c', cid)
74
- const provs = await this.loadProviders(cid)
74
+ const provs = await this.loadProviders(cid, options)
75
75
  this.log('got %d providers for %c', provs.size, cid)
76
76
 
77
77
  return [...provs.keys()]
@@ -83,21 +83,21 @@ export class Providers {
83
83
  /**
84
84
  * Write a provider into the given store
85
85
  */
86
- private async writeProviderEntry (cid: CID, peerId: PeerId, time: Date = new Date()): Promise<void> {
86
+ private async writeProviderEntry (cid: CID, peerId: PeerId, time: Date = new Date(), options?: AbortOptions): Promise<void> {
87
87
  const key = toProviderKey(this.datastorePrefix, cid, peerId)
88
88
  const buffer = varint.encode(time.getTime())
89
89
 
90
- await this.datastore.put(key, buffer)
90
+ await this.datastore.put(key, buffer, options)
91
91
  }
92
92
 
93
93
  /**
94
94
  * Load providers for the given CID from the store
95
95
  */
96
- private async loadProviders (cid: CID): Promise<PeerMap<Date>> {
96
+ private async loadProviders (cid: CID, options?: AbortOptions): Promise<PeerMap<Date>> {
97
97
  const providers = new PeerMap<Date>()
98
98
  const key = toProviderKey(this.datastorePrefix, cid)
99
99
 
100
- for await (const entry of this.datastore.query({ prefix: key.toString() })) {
100
+ for await (const entry of this.datastore.query({ prefix: key.toString() }, options)) {
101
101
  const { peerId } = parseProviderKey(entry.key)
102
102
  providers.set(peerId, readProviderTime(entry.value))
103
103
  }
@@ -1,4 +1,4 @@
1
- import type { MessageType, SendQueryEvent, PeerResponseEvent, DialPeerEvent, AddPeerEvent, ValueEvent, ProviderEvent, QueryErrorEvent, FinalPeerEvent } from '../index.js'
1
+ import type { MessageType, SendQueryEvent, PeerResponseEvent, AddPeerEvent, ValueEvent, ProviderEvent, QueryErrorEvent, FinalPeerEvent } from '../index.js'
2
2
  import type { PeerId, PeerInfo } from '@libp2p/interface'
3
3
  import type { Libp2pRecord } from '@libp2p/record'
4
4
  import type { ProgressOptions } from 'progress-events'
@@ -6,6 +6,7 @@ import type { ProgressOptions } from 'progress-events'
6
6
  export interface QueryEventFields {
7
7
  to: PeerId
8
8
  type: MessageType
9
+ path: number
9
10
  }
10
11
 
11
12
  export function sendQueryEvent (fields: QueryEventFields, options: ProgressOptions = {}): SendQueryEvent {
@@ -25,6 +26,7 @@ export function sendQueryEvent (fields: QueryEventFields, options: ProgressOptio
25
26
  export interface PeerResponseEventFields {
26
27
  from: PeerId
27
28
  messageType: MessageType
29
+ path: number
28
30
  closer?: PeerInfo[]
29
31
  providers?: PeerInfo[]
30
32
  record?: Libp2pRecord
@@ -48,6 +50,7 @@ export function peerResponseEvent (fields: PeerResponseEventFields, options: Pro
48
50
  export interface FinalPeerEventFields {
49
51
  from: PeerId
50
52
  peer: PeerInfo
53
+ path: number
51
54
  }
52
55
 
53
56
  export function finalPeerEvent (fields: FinalPeerEventFields, options: ProgressOptions = {}): FinalPeerEvent {
@@ -65,6 +68,7 @@ export function finalPeerEvent (fields: FinalPeerEventFields, options: ProgressO
65
68
  export interface ErrorEventFields {
66
69
  from: PeerId
67
70
  error: Error
71
+ path?: number
68
72
  }
69
73
 
70
74
  export function queryErrorEvent (fields: ErrorEventFields, options: ProgressOptions = {}): QueryErrorEvent {
@@ -113,11 +117,12 @@ export function valueEvent (fields: ValueEventFields, options: ProgressOptions =
113
117
  return event
114
118
  }
115
119
 
116
- export interface PeerEventFields {
120
+ export interface AddPeerEventFields {
117
121
  peer: PeerId
122
+ path: number
118
123
  }
119
124
 
120
- export function addPeerEvent (fields: PeerEventFields, options: ProgressOptions = {}): AddPeerEvent {
125
+ export function addPeerEvent (fields: AddPeerEventFields, options: ProgressOptions = {}): AddPeerEvent {
121
126
  const event: AddPeerEvent = {
122
127
  ...fields,
123
128
  name: 'ADD_PEER',
@@ -128,19 +133,3 @@ export function addPeerEvent (fields: PeerEventFields, options: ProgressOptions
128
133
 
129
134
  return event
130
135
  }
131
-
132
- export interface DialPeerEventFields {
133
- peer: PeerId
134
- }
135
-
136
- export function dialPeerEvent (fields: DialPeerEventFields, options: ProgressOptions = {}): DialPeerEvent {
137
- const event: DialPeerEvent = {
138
- ...fields,
139
- name: 'DIAL_PEER',
140
- type: 7
141
- }
142
-
143
- options.onProgress?.(new CustomEvent('kad-dht:query:dial-peer', { detail: event }))
144
-
145
- return event
146
- }
@@ -2,6 +2,7 @@ import { setMaxListeners } from '@libp2p/interface'
2
2
  import { PeerSet } from '@libp2p/peer-collections'
3
3
  import { anySignal } from 'any-signal'
4
4
  import merge from 'it-merge'
5
+ import { pEvent } from 'p-event'
5
6
  import { raceSignal } from 'race-signal'
6
7
  import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
7
8
  import {
@@ -26,6 +27,7 @@ export interface QueryManagerInit {
26
27
  disjointPaths?: number
27
28
  alpha?: number
28
29
  initialQuerySelfHasRun: DeferredPromise<void>
30
+ allowQueryWithZeroPeers?: boolean
29
31
  routingTable: RoutingTable
30
32
  }
31
33
 
@@ -59,6 +61,7 @@ export class QueryManager implements Startable {
59
61
  private readonly routingTable: RoutingTable
60
62
  private initialQuerySelfHasRun?: DeferredPromise<void>
61
63
  private readonly logPrefix: string
64
+ private readonly allowQueryWithZeroPeers: boolean
62
65
 
63
66
  constructor (components: QueryManagerComponents, init: QueryManagerInit) {
64
67
  this.logPrefix = init.logPrefix
@@ -69,6 +72,7 @@ export class QueryManager implements Startable {
69
72
  this.logger = components.logger
70
73
  this.peerId = components.peerId
71
74
  this.connectionManager = components.connectionManager
75
+ this.allowQueryWithZeroPeers = init.allowQueryWithZeroPeers ?? false
72
76
 
73
77
  // allow us to stop queries on shut down
74
78
  this.shutDownController = new AbortController()
@@ -146,6 +150,16 @@ export class QueryManager implements Startable {
146
150
  let queryFinished = false
147
151
 
148
152
  try {
153
+ if (this.routingTable.size === 0 && !this.allowQueryWithZeroPeers) {
154
+ log('routing table was empty, waiting for some peers before running%s query', options.isSelfQuery === true ? ' self' : '')
155
+ // wait to discover at least one DHT peer that isn't us
156
+ await pEvent(this.routingTable, 'peer:add', {
157
+ signal,
158
+ filter: (event) => !this.peerId.equals(event.detail)
159
+ })
160
+ log('routing table has peers, continuing with%s query', options.isSelfQuery === true ? ' self' : '')
161
+ }
162
+
149
163
  if (options.isSelfQuery !== true && this.initialQuerySelfHasRun != null) {
150
164
  log('waiting for initial query-self query before continuing')
151
165
 
@@ -161,7 +175,7 @@ export class QueryManager implements Startable {
161
175
  const peersToQuery = peers.slice(0, Math.min(this.disjointPaths, peers.length))
162
176
 
163
177
  if (peers.length === 0) {
164
- log.error('Running query with no peers')
178
+ log.error('running query with no peers')
165
179
  return
166
180
  }
167
181
 
@@ -177,7 +191,7 @@ export class QueryManager implements Startable {
177
191
  ourPeerId: this.peerId,
178
192
  signal,
179
193
  query: queryFunc,
180
- pathIndex: index,
194
+ path: index,
181
195
  numPaths: peersToQuery.length,
182
196
  alpha: this.alpha,
183
197
  queryFuncTimeout: options.queryFuncTimeout,
@@ -197,22 +211,26 @@ export class QueryManager implements Startable {
197
211
  if (event.name === 'PEER_RESPONSE') {
198
212
  for (const peer of [...event.closer, ...event.providers]) {
199
213
  // eslint-disable-next-line max-depth
200
- if (!(await this.connectionManager.isDialable(peer.multiaddrs))) {
214
+ if (!(await this.connectionManager.isDialable(peer.multiaddrs, {
215
+ signal
216
+ }))) {
201
217
  continue
202
218
  }
203
219
 
204
- await this.routingTable.add(peer.id)
220
+ await this.routingTable.add(peer.id, {
221
+ signal
222
+ })
205
223
  }
206
224
  }
207
225
 
208
226
  yield event
227
+ signal.throwIfAborted()
209
228
  }
210
229
 
211
230
  queryFinished = true
212
- } catch (err: any) {
213
- if (!this.running && err.name === 'QueryAbortedError') {
214
- // ignore query aborted errors that were thrown during query manager shutdown
215
- } else {
231
+ } catch (err) {
232
+ if (this.running) {
233
+ // ignore errors thrown during shut down
216
234
  throw err
217
235
  }
218
236
  } finally {
@@ -3,7 +3,6 @@ import { Queue } from '@libp2p/utils/queue'
3
3
  import { anySignal } from 'any-signal'
4
4
  import { xor as uint8ArrayXor } from 'uint8arrays/xor'
5
5
  import { xorCompare as uint8ArrayXorCompare } from 'uint8arrays/xor-compare'
6
- import { QueryAbortedError } from '../errors.js'
7
6
  import { convertPeerId, convertBuffer } from '../utils.js'
8
7
  import { queryErrorEvent } from './events.js'
9
8
  import type { QueryEvent } from '../index.js'
@@ -44,12 +43,12 @@ export interface QueryPathOptions extends RoutingOptions {
44
43
  alpha: number
45
44
 
46
45
  /**
47
- * How many concurrent node/value lookups to run
46
+ * The index within `k` this path represents
48
47
  */
49
- pathIndex: number
48
+ path: number
50
49
 
51
50
  /**
52
- * How many concurrent node/value lookups to run
51
+ * How many disjoint paths are in this query
53
52
  */
54
53
  numPaths: number
55
54
 
@@ -83,7 +82,7 @@ interface QueryQueueOptions extends AbortOptions {
83
82
  * every peer encountered that we have not seen before
84
83
  */
85
84
  export async function * queryPath (options: QueryPathOptions): AsyncGenerator<QueryEvent, void, undefined> {
86
- const { key, startingPeer, ourPeerId, signal, query, alpha, pathIndex, numPaths, queryFuncTimeout, log, peersSeen, connectionManager } = options
85
+ const { key, startingPeer, ourPeerId, signal, query, alpha, path, numPaths, queryFuncTimeout, log, peersSeen, connectionManager } = options
87
86
  // Only ALPHA node/value lookups are allowed at any given time for each process
88
87
  // https://github.com/libp2p/specs/tree/master/kad-dht#alpha-concurrency-parameter-%CE%B1
89
88
  const queue = new Queue<QueryEvent | undefined, QueryQueueOptions>({
@@ -125,7 +124,7 @@ export async function * queryPath (options: QueryPathOptions): AsyncGenerator<Qu
125
124
  key,
126
125
  peer,
127
126
  signal: compoundSignal,
128
- pathIndex,
127
+ path,
129
128
  numPaths
130
129
  })) {
131
130
  if (compoundSignal.aborted) {
@@ -172,7 +171,8 @@ export async function * queryPath (options: QueryPathOptions): AsyncGenerator<Qu
172
171
  if (!signal.aborted) {
173
172
  return queryErrorEvent({
174
173
  from: peer,
175
- error: err
174
+ error: err,
175
+ path
176
176
  }, options)
177
177
  }
178
178
  } finally {
@@ -188,18 +188,10 @@ export async function * queryPath (options: QueryPathOptions): AsyncGenerator<Qu
188
188
  // begin the query with the starting peer
189
189
  queryPeer(startingPeer, await convertPeerId(startingPeer))
190
190
 
191
- try {
192
- // yield results as they come in
193
- for await (const event of queue.toGenerator({ signal })) {
194
- if (event != null) {
195
- yield event
196
- }
191
+ // yield results as they come in
192
+ for await (const event of queue.toGenerator({ signal })) {
193
+ if (event != null) {
194
+ yield event
197
195
  }
198
- } catch (err) {
199
- if (signal.aborted) {
200
- throw new QueryAbortedError('Query aborted')
201
- }
202
-
203
- throw err
204
196
  }
205
197
  }
@@ -9,7 +9,7 @@ export interface QueryContext {
9
9
  // if this signal emits an 'abort' event, any long-lived processes or requests started as part of this query should be terminated
10
10
  signal: AbortSignal
11
11
  // which disjoint path we are following
12
- pathIndex: number
12
+ path: number
13
13
  // the total number of disjoint paths being executed
14
14
  numPaths: number
15
15
  }
package/src/query-self.ts CHANGED
@@ -4,18 +4,16 @@ import length from 'it-length'
4
4
  import { pipe } from 'it-pipe'
5
5
  import take from 'it-take'
6
6
  import pDefer from 'p-defer'
7
- import { pEvent } from 'p-event'
8
7
  import { QUERY_SELF_INTERVAL, QUERY_SELF_TIMEOUT, K, QUERY_SELF_INITIAL_INTERVAL } from './constants.js'
9
8
  import { timeOperationMethod } from './utils.js'
10
9
  import type { OperationMetrics } from './kad-dht.js'
11
10
  import type { PeerRouting } from './peer-routing/index.js'
12
- import type { RoutingTable } from './routing-table/index.js'
13
11
  import type { ComponentLogger, Logger, Metrics, PeerId, Startable } from '@libp2p/interface'
14
12
  import type { DeferredPromise } from 'p-defer'
13
+
15
14
  export interface QuerySelfInit {
16
15
  logPrefix: string
17
16
  peerRouting: PeerRouting
18
- routingTable: RoutingTable
19
17
  count?: number
20
18
  interval?: number
21
19
  initialInterval?: number
@@ -28,6 +26,7 @@ export interface QuerySelfComponents {
28
26
  peerId: PeerId
29
27
  logger: ComponentLogger
30
28
  metrics?: Metrics
29
+ events: EventTarget
31
30
  }
32
31
 
33
32
  /**
@@ -37,7 +36,7 @@ export class QuerySelf implements Startable {
37
36
  private readonly log: Logger
38
37
  private readonly peerId: PeerId
39
38
  private readonly peerRouting: PeerRouting
40
- private readonly routingTable: RoutingTable
39
+ private readonly events: EventTarget
41
40
  private readonly count: number
42
41
  private readonly interval: number
43
42
  private readonly initialInterval: number
@@ -51,9 +50,9 @@ export class QuerySelf implements Startable {
51
50
  constructor (components: QuerySelfComponents, init: QuerySelfInit) {
52
51
  this.peerId = components.peerId
53
52
  this.log = components.logger.forComponent(`${init.logPrefix}:query-self`)
53
+ this.events = components.events
54
54
  this.running = false
55
55
  this.peerRouting = init.peerRouting
56
- this.routingTable = init.routingTable
57
56
  this.count = init.count ?? K
58
57
  this.interval = init.interval ?? QUERY_SELF_INTERVAL
59
58
  this.initialInterval = init.initialInterval ?? QUERY_SELF_INITIAL_INTERVAL
@@ -122,20 +121,10 @@ export class QuerySelf implements Startable {
122
121
  setMaxListeners(Infinity, signal, this.controller.signal)
123
122
 
124
123
  try {
125
- if (this.routingTable.size === 0) {
126
- this.log('routing table was empty, waiting for some peers before running query')
127
- // wait to discover at least one DHT peer that isn't us
128
- await pEvent(this.routingTable, 'peer:add', {
129
- signal,
130
- filter: (event) => !this.peerId.equals(event.detail)
131
- })
132
- this.log('routing table has peers, continuing with query')
133
- }
134
-
135
124
  this.log('run self-query, look for %d peers timing out after %dms', this.count, this.queryTimeout)
136
125
  const start = Date.now()
137
126
 
138
- const found = await pipe(
127
+ const peers = await pipe(
139
128
  this.peerRouting.getClosestPeers(this.peerId.toMultihash().bytes, {
140
129
  signal,
141
130
  isSelfQuery: true
@@ -144,7 +133,16 @@ export class QuerySelf implements Startable {
144
133
  async (source) => length(source)
145
134
  )
146
135
 
147
- this.log('self-query found %d peers in %dms', found, Date.now() - start)
136
+ const duration = Date.now() - start
137
+
138
+ this.log('self-query found %d peers in %dms', peers, duration)
139
+
140
+ this.events.dispatchEvent(new CustomEvent('kad-dht:query:self', {
141
+ detail: {
142
+ peers,
143
+ duration
144
+ }
145
+ }))
148
146
  } catch (err: any) {
149
147
  this.log.error('self-query error', err)
150
148
  } finally {
@@ -91,7 +91,7 @@ export class ClosestPeers implements Startable {
91
91
  }
92
92
 
93
93
  async updatePeerTags (): Promise<void> {
94
- const newClosest = new PeerSet(this.newPeers?.peers.map(peer => peer.id))
94
+ const newClosest = new PeerSet(this.newPeers?.peers.map(({ peer }) => peer.id))
95
95
  const added = newClosest.difference(this.closestPeers)
96
96
  const removed = this.closestPeers.difference(newClosest)
97
97
  this.closestPeers = newClosest
@@ -300,7 +300,7 @@ export class KBucket {
300
300
  list.addWithKadId({ id: peer.peerId, multiaddrs: [] }, peer.kadId)
301
301
  }
302
302
 
303
- yield * map(list.peers, info => info.id)
303
+ yield * map(list.peers, ({ peer }) => peer.id)
304
304
  }
305
305
 
306
306
  /**