@waku/core 0.0.26 → 0.0.28-434be7b.0

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 (56) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/bundle/{base_protocol-pDODy0G6.js → base_protocol-BCwLeb-A.js} +134 -89
  3. package/bundle/{browser-mTOOnVZp.js → browser-DoQRY-an.js} +518 -712
  4. package/bundle/{index-cmONXM-V.js → index-vlQahmUj.js} +98 -41
  5. package/bundle/index.js +3081 -21642
  6. package/bundle/lib/base_protocol.js +3 -3
  7. package/bundle/lib/message/version_0.js +3 -3
  8. package/bundle/lib/predefined_bootstrap_nodes.js +1 -1
  9. package/bundle/{version_0-LQTFNC7k.js → version_0-DiakMc1A.js} +1246 -2444
  10. package/dist/.tsbuildinfo +1 -1
  11. package/dist/index.d.ts +1 -5
  12. package/dist/index.js +1 -5
  13. package/dist/index.js.map +1 -1
  14. package/dist/lib/base_protocol.d.ts +15 -13
  15. package/dist/lib/base_protocol.js +35 -22
  16. package/dist/lib/base_protocol.js.map +1 -1
  17. package/dist/lib/connection_manager.d.ts +2 -2
  18. package/dist/lib/connection_manager.js +16 -6
  19. package/dist/lib/connection_manager.js.map +1 -1
  20. package/dist/lib/filter/index.d.ts +1 -1
  21. package/dist/lib/filter/index.js +144 -82
  22. package/dist/lib/filter/index.js.map +1 -1
  23. package/dist/lib/filterPeers.d.ts +8 -5
  24. package/dist/lib/filterPeers.js +12 -5
  25. package/dist/lib/filterPeers.js.map +1 -1
  26. package/dist/lib/keep_alive_manager.d.ts +2 -3
  27. package/dist/lib/keep_alive_manager.js.map +1 -1
  28. package/dist/lib/light_push/index.d.ts +12 -2
  29. package/dist/lib/light_push/index.js +80 -80
  30. package/dist/lib/light_push/index.js.map +1 -1
  31. package/dist/lib/metadata/index.d.ts +2 -2
  32. package/dist/lib/metadata/index.js +58 -16
  33. package/dist/lib/metadata/index.js.map +1 -1
  34. package/dist/lib/store/index.js +1 -3
  35. package/dist/lib/store/index.js.map +1 -1
  36. package/dist/lib/stream_manager.d.ts +2 -2
  37. package/dist/lib/stream_manager.js.map +1 -1
  38. package/dist/lib/wait_for_remote_peer.d.ts +1 -1
  39. package/dist/lib/wait_for_remote_peer.js +42 -10
  40. package/dist/lib/wait_for_remote_peer.js.map +1 -1
  41. package/package.json +1 -127
  42. package/src/index.ts +1 -6
  43. package/src/lib/base_protocol.ts +57 -37
  44. package/src/lib/connection_manager.ts +17 -10
  45. package/src/lib/filter/index.ts +234 -136
  46. package/src/lib/filterPeers.ts +15 -7
  47. package/src/lib/keep_alive_manager.ts +2 -3
  48. package/src/lib/light_push/index.ts +104 -124
  49. package/src/lib/metadata/index.ts +92 -30
  50. package/src/lib/store/index.ts +3 -6
  51. package/src/lib/stream_manager.ts +2 -3
  52. package/src/lib/wait_for_remote_peer.ts +68 -12
  53. package/dist/lib/waku.d.ts +0 -57
  54. package/dist/lib/waku.js +0 -130
  55. package/dist/lib/waku.js.map +0 -1
  56. package/src/lib/waku.ts +0 -214
@@ -1,6 +1,6 @@
1
- import { Stream } from "@libp2p/interface/connection";
2
- import type { Peer } from "@libp2p/interface/peer-store";
3
- import type { IncomingStreamData } from "@libp2p/interface-internal/registrar";
1
+ import { Stream } from "@libp2p/interface";
2
+ import type { Peer } from "@libp2p/interface";
3
+ import type { IncomingStreamData } from "@libp2p/interface-internal";
4
4
  import type {
5
5
  Callback,
6
6
  ContentTopic,
@@ -11,13 +11,13 @@ import type {
11
11
  IProtoMessage,
12
12
  IReceiver,
13
13
  Libp2p,
14
- PeerIdStr,
15
14
  ProtocolCreateOptions,
16
15
  PubsubTopic,
17
16
  SingleShardInfo,
18
17
  Unsubscribe
19
18
  } from "@waku/interfaces";
20
19
  import { DefaultPubsubTopic } from "@waku/interfaces";
20
+ import { messageHashStr } from "@waku/message-hash";
21
21
  import { WakuMessage } from "@waku/proto";
22
22
  import {
23
23
  ensurePubsubTopicIsConfigured,
@@ -50,10 +50,14 @@ export const FilterCodecs = {
50
50
  PUSH: "/vac/waku/filter-push/2.0.0-beta1"
51
51
  };
52
52
 
53
+ /**
54
+ * A subscription object refers to a subscription to a given pubsub topic.
55
+ */
53
56
  class Subscription {
54
- private readonly peer: Peer;
57
+ readonly peers: Peer[];
55
58
  private readonly pubsubTopic: PubsubTopic;
56
59
  private newStream: (peer: Peer) => Promise<Stream>;
60
+ readonly receivedMessagesHashStr: string[] = [];
57
61
 
58
62
  private subscriptionCallbacks: Map<
59
63
  ContentTopic,
@@ -62,10 +66,10 @@ class Subscription {
62
66
 
63
67
  constructor(
64
68
  pubsubTopic: PubsubTopic,
65
- remotePeer: Peer,
69
+ remotePeers: Peer[],
66
70
  newStream: (peer: Peer) => Promise<Stream>
67
71
  ) {
68
- this.peer = remotePeer;
72
+ this.peers = remotePeers;
69
73
  this.pubsubTopic = pubsubTopic;
70
74
  this.newStream = newStream;
71
75
  this.subscriptionCallbacks = new Map();
@@ -89,53 +93,59 @@ class Subscription {
89
93
  const decodersGroupedByCT = groupByContentTopic(decodersArray);
90
94
  const contentTopics = Array.from(decodersGroupedByCT.keys());
91
95
 
92
- const stream = await this.newStream(this.peer);
96
+ const promises = this.peers.map(async (peer) => {
97
+ const stream = await this.newStream(peer);
93
98
 
94
- const request = FilterSubscribeRpc.createSubscribeRequest(
95
- this.pubsubTopic,
96
- contentTopics
97
- );
98
-
99
- try {
100
- const res = await pipe(
101
- [request.encode()],
102
- lp.encode,
103
- stream,
104
- lp.decode,
105
- async (source) => await all(source)
99
+ const request = FilterSubscribeRpc.createSubscribeRequest(
100
+ this.pubsubTopic,
101
+ contentTopics
106
102
  );
107
103
 
108
- if (!res || !res.length) {
109
- throw Error(
110
- `No response received for request ${request.requestId}: ${res}`
104
+ try {
105
+ const res = await pipe(
106
+ [request.encode()],
107
+ lp.encode,
108
+ stream,
109
+ lp.decode,
110
+ async (source) => await all(source)
111
111
  );
112
- }
113
112
 
114
- const { statusCode, requestId, statusDesc } =
115
- FilterSubscribeResponse.decode(res[0].slice());
113
+ if (!res || !res.length) {
114
+ throw Error(
115
+ `No response received for request ${request.requestId}: ${res}`
116
+ );
117
+ }
118
+
119
+ const { statusCode, requestId, statusDesc } =
120
+ FilterSubscribeResponse.decode(res[0].slice());
121
+
122
+ if (statusCode < 200 || statusCode >= 300) {
123
+ throw new Error(
124
+ `Filter subscribe request ${requestId} failed with status code ${statusCode}: ${statusDesc}`
125
+ );
126
+ }
116
127
 
117
- if (statusCode < 200 || statusCode >= 300) {
128
+ log.info(
129
+ "Subscribed to peer ",
130
+ peer.id.toString(),
131
+ "for content topics",
132
+ contentTopics
133
+ );
134
+ } catch (e) {
118
135
  throw new Error(
119
- `Filter subscribe request ${requestId} failed with status code ${statusCode}: ${statusDesc}`
136
+ "Error subscribing to peer: " +
137
+ peer.id.toString() +
138
+ " for content topics: " +
139
+ contentTopics +
140
+ ": " +
141
+ e
120
142
  );
121
143
  }
144
+ });
122
145
 
123
- log.info(
124
- "Subscribed to peer ",
125
- this.peer.id.toString(),
126
- "for content topics",
127
- contentTopics
128
- );
129
- } catch (e) {
130
- throw new Error(
131
- "Error subscribing to peer: " +
132
- this.peer.id.toString() +
133
- " for content topics: " +
134
- contentTopics +
135
- ": " +
136
- e
137
- );
138
- }
146
+ const results = await Promise.allSettled(promises);
147
+
148
+ this.handleErrors(results, "subscribe");
139
149
 
140
150
  // Save the callback functions by content topics so they
141
151
  // can easily be removed (reciprocally replaced) if `unsubscribe` (reciprocally `subscribe`)
@@ -155,133 +165,213 @@ class Subscription {
155
165
  }
156
166
 
157
167
  async unsubscribe(contentTopics: ContentTopic[]): Promise<void> {
158
- const stream = await this.newStream(this.peer);
159
- const unsubscribeRequest = FilterSubscribeRpc.createUnsubscribeRequest(
160
- this.pubsubTopic,
161
- contentTopics
162
- );
168
+ const promises = this.peers.map(async (peer) => {
169
+ const stream = await this.newStream(peer);
170
+ const unsubscribeRequest = FilterSubscribeRpc.createUnsubscribeRequest(
171
+ this.pubsubTopic,
172
+ contentTopics
173
+ );
163
174
 
164
- try {
165
- await pipe([unsubscribeRequest.encode()], lp.encode, stream.sink);
166
- } catch (error) {
167
- throw new Error("Error subscribing: " + error);
168
- }
175
+ try {
176
+ await pipe([unsubscribeRequest.encode()], lp.encode, stream.sink);
177
+ } catch (error) {
178
+ throw new Error("Error unsubscribing: " + error);
179
+ }
169
180
 
170
- contentTopics.forEach((contentTopic: string) => {
171
- this.subscriptionCallbacks.delete(contentTopic);
181
+ contentTopics.forEach((contentTopic: string) => {
182
+ this.subscriptionCallbacks.delete(contentTopic);
183
+ });
172
184
  });
185
+
186
+ const results = await Promise.allSettled(promises);
187
+
188
+ this.handleErrors(results, "unsubscribe");
173
189
  }
174
190
 
175
191
  async ping(): Promise<void> {
176
- const stream = await this.newStream(this.peer);
192
+ const promises = this.peers.map(async (peer) => {
193
+ const stream = await this.newStream(peer);
194
+
195
+ const request = FilterSubscribeRpc.createSubscriberPingRequest();
196
+
197
+ try {
198
+ const res = await pipe(
199
+ [request.encode()],
200
+ lp.encode,
201
+ stream,
202
+ lp.decode,
203
+ async (source) => await all(source)
204
+ );
177
205
 
178
- const request = FilterSubscribeRpc.createSubscriberPingRequest();
206
+ if (!res || !res.length) {
207
+ throw Error(
208
+ `No response received for request ${request.requestId}: ${res}`
209
+ );
210
+ }
179
211
 
180
- try {
181
- const res = await pipe(
182
- [request.encode()],
183
- lp.encode,
184
- stream,
185
- lp.decode,
186
- async (source) => await all(source)
187
- );
212
+ const { statusCode, requestId, statusDesc } =
213
+ FilterSubscribeResponse.decode(res[0].slice());
188
214
 
189
- if (!res || !res.length) {
190
- throw Error(
191
- `No response received for request ${request.requestId}: ${res}`
192
- );
215
+ if (statusCode < 200 || statusCode >= 300) {
216
+ throw new Error(
217
+ `Filter ping request ${requestId} failed with status code ${statusCode}: ${statusDesc}`
218
+ );
219
+ }
220
+ log.info(`Ping successful for peer ${peer.id.toString()}`);
221
+ } catch (error) {
222
+ log.error("Error pinging: ", error);
223
+ throw error; // Rethrow the actual error instead of wrapping it
193
224
  }
225
+ });
194
226
 
195
- const { statusCode, requestId, statusDesc } =
196
- FilterSubscribeResponse.decode(res[0].slice());
197
-
198
- if (statusCode < 200 || statusCode >= 300) {
199
- throw new Error(
200
- `Filter ping request ${requestId} failed with status code ${statusCode}: ${statusDesc}`
201
- );
202
- }
227
+ const results = await Promise.allSettled(promises);
203
228
 
204
- log.info("Ping successful");
205
- } catch (error) {
206
- log.error("Error pinging: ", error);
207
- throw new Error("Error pinging: " + error);
208
- }
229
+ this.handleErrors(results, "ping");
209
230
  }
210
231
 
211
232
  async unsubscribeAll(): Promise<void> {
212
- const stream = await this.newStream(this.peer);
213
-
214
- const request = FilterSubscribeRpc.createUnsubscribeAllRequest(
215
- this.pubsubTopic
216
- );
233
+ const promises = this.peers.map(async (peer) => {
234
+ const stream = await this.newStream(peer);
217
235
 
218
- try {
219
- const res = await pipe(
220
- [request.encode()],
221
- lp.encode,
222
- stream,
223
- lp.decode,
224
- async (source) => await all(source)
236
+ const request = FilterSubscribeRpc.createUnsubscribeAllRequest(
237
+ this.pubsubTopic
225
238
  );
226
239
 
227
- if (!res || !res.length) {
228
- throw Error(
229
- `No response received for request ${request.requestId}: ${res}`
240
+ try {
241
+ const res = await pipe(
242
+ [request.encode()],
243
+ lp.encode,
244
+ stream,
245
+ lp.decode,
246
+ async (source) => await all(source)
230
247
  );
231
- }
232
248
 
233
- const { statusCode, requestId, statusDesc } =
234
- FilterSubscribeResponse.decode(res[0].slice());
249
+ if (!res || !res.length) {
250
+ throw Error(
251
+ `No response received for request ${request.requestId}: ${res}`
252
+ );
253
+ }
254
+
255
+ const { statusCode, requestId, statusDesc } =
256
+ FilterSubscribeResponse.decode(res[0].slice());
235
257
 
236
- if (statusCode < 200 || statusCode >= 300) {
258
+ if (statusCode < 200 || statusCode >= 300) {
259
+ throw new Error(
260
+ `Filter unsubscribe all request ${requestId} failed with status code ${statusCode}: ${statusDesc}`
261
+ );
262
+ }
263
+
264
+ this.subscriptionCallbacks.clear();
265
+ log.info(
266
+ `Unsubscribed from all content topics for pubsub topic ${this.pubsubTopic}`
267
+ );
268
+ } catch (error) {
237
269
  throw new Error(
238
- `Filter unsubscribe all request ${requestId} failed with status code ${statusCode}: ${statusDesc}`
270
+ "Error unsubscribing from all content topics: " + error
239
271
  );
240
272
  }
273
+ });
241
274
 
242
- this.subscriptionCallbacks.clear();
243
- log.info("Unsubscribed from all content topics");
244
- } catch (error) {
245
- throw new Error("Error unsubscribing from all content topics: " + error);
246
- }
275
+ const results = await Promise.allSettled(promises);
276
+
277
+ this.handleErrors(results, "unsubscribeAll");
247
278
  }
248
279
 
249
280
  async processMessage(message: WakuMessage): Promise<void> {
250
- const contentTopic = message.contentTopic;
281
+ const hashedMessageStr = messageHashStr(
282
+ this.pubsubTopic,
283
+ message as IProtoMessage
284
+ );
285
+ if (this.receivedMessagesHashStr.includes(hashedMessageStr)) {
286
+ log.info("Message already received, skipping");
287
+ return;
288
+ }
289
+ this.receivedMessagesHashStr.push(hashedMessageStr);
290
+
291
+ const { contentTopic } = message;
251
292
  const subscriptionCallback = this.subscriptionCallbacks.get(contentTopic);
252
293
  if (!subscriptionCallback) {
253
294
  log.error("No subscription callback available for ", contentTopic);
254
295
  return;
255
296
  }
297
+ log.info(
298
+ "Processing message with content topic ",
299
+ contentTopic,
300
+ " on pubsub topic ",
301
+ this.pubsubTopic
302
+ );
256
303
  await pushMessage(subscriptionCallback, this.pubsubTopic, message);
257
304
  }
305
+
306
+ // Filter out only the rejected promises and extract & handle their reasons
307
+ private handleErrors(
308
+ results: PromiseSettledResult<void>[],
309
+ type: "ping" | "subscribe" | "unsubscribe" | "unsubscribeAll"
310
+ ): void {
311
+ const errors = results
312
+ .filter(
313
+ (result): result is PromiseRejectedResult =>
314
+ result.status === "rejected"
315
+ )
316
+ .map((rejectedResult) => rejectedResult.reason);
317
+
318
+ if (errors.length === this.peers.length) {
319
+ const errorCounts = new Map<string, number>();
320
+ // TODO: streamline error logging with https://github.com/orgs/waku-org/projects/2/views/1?pane=issue&itemId=42849952
321
+ errors.forEach((error) => {
322
+ const message = error instanceof Error ? error.message : String(error);
323
+ errorCounts.set(message, (errorCounts.get(message) || 0) + 1);
324
+ });
325
+
326
+ const uniqueErrorMessages = Array.from(
327
+ errorCounts,
328
+ ([message, count]) => `${message} (occurred ${count} times)`
329
+ ).join(", ");
330
+ throw new Error(`Error ${type} all peers: ${uniqueErrorMessages}`);
331
+ } else if (errors.length > 0) {
332
+ // TODO: handle renewing faulty peers with new peers (https://github.com/waku-org/js-waku/issues/1463)
333
+ log.warn(
334
+ `Some ${type} failed. These will be refreshed with new peers`,
335
+ errors
336
+ );
337
+ } else {
338
+ log.info(`${type} successful for all peers`);
339
+ }
340
+ }
258
341
  }
259
342
 
343
+ const DEFAULT_NUM_PEERS = 3;
344
+
260
345
  class Filter extends BaseProtocol implements IReceiver {
261
- private readonly pubsubTopics: PubsubTopic[] = [];
262
346
  private activeSubscriptions = new Map<string, Subscription>();
263
- private readonly NUM_PEERS_PROTOCOL = 1;
264
347
 
265
348
  private getActiveSubscription(
266
- pubsubTopic: PubsubTopic,
267
- peerIdStr: PeerIdStr
349
+ pubsubTopic: PubsubTopic
268
350
  ): Subscription | undefined {
269
- return this.activeSubscriptions.get(`${pubsubTopic}_${peerIdStr}`);
351
+ return this.activeSubscriptions.get(pubsubTopic);
270
352
  }
271
353
 
272
354
  private setActiveSubscription(
273
355
  pubsubTopic: PubsubTopic,
274
- peerIdStr: PeerIdStr,
275
356
  subscription: Subscription
276
357
  ): Subscription {
277
- this.activeSubscriptions.set(`${pubsubTopic}_${peerIdStr}`, subscription);
358
+ this.activeSubscriptions.set(pubsubTopic, subscription);
278
359
  return subscription;
279
360
  }
280
361
 
362
+ //TODO: Remove when FilterCore and FilterSDK are introduced
363
+ private readonly numPeersToUse: number;
364
+
281
365
  constructor(libp2p: Libp2p, options?: ProtocolCreateOptions) {
282
- super(FilterCodecs.SUBSCRIBE, libp2p.components);
366
+ super(
367
+ FilterCodecs.SUBSCRIBE,
368
+ libp2p.components,
369
+ log,
370
+ options!.pubsubTopics!,
371
+ options
372
+ );
283
373
 
284
- this.pubsubTopics = this.initializePubsubTopic(options);
374
+ this.numPeersToUse = options?.numPeersToUse ?? DEFAULT_NUM_PEERS;
285
375
 
286
376
  libp2p.handle(FilterCodecs.PUSH, this.onRequest.bind(this)).catch((e) => {
287
377
  log.error("Failed to register ", FilterCodecs.PUSH, e);
@@ -290,6 +380,12 @@ class Filter extends BaseProtocol implements IReceiver {
290
380
  this.activeSubscriptions = new Map();
291
381
  }
292
382
 
383
+ /**
384
+ * Creates a new subscription to the given pubsub topic.
385
+ * The subscription is made to multiple peers for decentralization.
386
+ * @param pubsubTopicShardInfo The pubsub topic to subscribe to.
387
+ * @returns The subscription object.
388
+ */
293
389
  async createSubscription(
294
390
  pubsubTopicShardInfo: SingleShardInfo | PubsubTopic = DefaultPubsubTopic
295
391
  ): Promise<Subscription> {
@@ -300,21 +396,24 @@ class Filter extends BaseProtocol implements IReceiver {
300
396
 
301
397
  ensurePubsubTopicIsConfigured(pubsubTopic, this.pubsubTopics);
302
398
 
303
- //TODO: get a relevant peer for the topic/shard
304
- // https://github.com/waku-org/js-waku/pull/1586#discussion_r1336428230
305
- const peer = (
306
- await this.getPeers({
307
- maxBootstrapPeers: 1,
308
- numPeers: this.NUM_PEERS_PROTOCOL
309
- })
310
- )[0];
399
+ const peers = await this.getPeers({
400
+ maxBootstrapPeers: 1,
401
+ numPeers: this.numPeersToUse
402
+ });
403
+ if (peers.length === 0) {
404
+ throw new Error("No peer found to initiate subscription.");
405
+ }
406
+
407
+ log.info(
408
+ `Creating filter subscription with ${peers.length} peers: `,
409
+ peers.map((peer) => peer.id.toString())
410
+ );
311
411
 
312
412
  const subscription =
313
- this.getActiveSubscription(pubsubTopic, peer.id.toString()) ??
413
+ this.getActiveSubscription(pubsubTopic) ??
314
414
  this.setActiveSubscription(
315
415
  pubsubTopic,
316
- peer.id.toString(),
317
- new Subscription(pubsubTopic, peer, this.getStream.bind(this, peer))
416
+ new Subscription(pubsubTopic, peers, this.getStream.bind(this))
318
417
  );
319
418
 
320
419
  return subscription;
@@ -361,8 +460,11 @@ class Filter extends BaseProtocol implements IReceiver {
361
460
  }
362
461
 
363
462
  private onRequest(streamData: IncomingStreamData): void {
463
+ const { connection, stream } = streamData;
464
+ const { remotePeer } = connection;
465
+ log.info(`Received message from ${remotePeer.toString()}`);
364
466
  try {
365
- pipe(streamData.stream, lp.decode, async (source) => {
467
+ pipe(stream, lp.decode, async (source) => {
366
468
  for await (const bytes of source) {
367
469
  const response = FilterPushRpc.decode(bytes.slice());
368
470
 
@@ -378,11 +480,7 @@ class Filter extends BaseProtocol implements IReceiver {
378
480
  return;
379
481
  }
380
482
 
381
- const peerIdStr = streamData.connection.remotePeer.toString();
382
- const subscription = this.getActiveSubscription(
383
- pubsubTopic,
384
- peerIdStr
385
- );
483
+ const subscription = this.getActiveSubscription(pubsubTopic);
386
484
 
387
485
  if (!subscription) {
388
486
  log.error(
@@ -408,7 +506,7 @@ class Filter extends BaseProtocol implements IReceiver {
408
506
  }
409
507
 
410
508
  export function wakuFilter(
411
- init: Partial<ProtocolCreateOptions> = {}
509
+ init: ProtocolCreateOptions = { pubsubTopics: [] }
412
510
  ): (libp2p: Libp2p) => IFilter {
413
511
  return (libp2p: Libp2p) => new Filter(libp2p, init);
414
512
  }
@@ -1,24 +1,32 @@
1
- import { Peer } from "@libp2p/interface/peer-store";
1
+ import { Peer } from "@libp2p/interface";
2
2
  import { Tags } from "@waku/interfaces";
3
3
 
4
4
  /**
5
- * Retrieves a list of peers based on the specified criteria.
5
+ * Retrieves a list of peers based on the specified criteria:
6
+ * 1. If numPeers is 0, return all peers
7
+ * 2. Bootstrap peers are prioritized
8
+ * 3. Non-bootstrap peers are randomly selected to fill up to numPeers
6
9
  *
7
10
  * @param peers - The list of peers to filter from.
8
- * @param numPeers - The total number of peers to retrieve. If 0, all peers are returned.
11
+ * @param numPeers - The total number of peers to retrieve. If 0, all peers are returned, irrespective of `maxBootstrapPeers`.
9
12
  * @param maxBootstrapPeers - The maximum number of bootstrap peers to retrieve.
10
- * @returns A Promise that resolves to an array of peers based on the specified criteria.
13
+ * @returns An array of peers based on the specified criteria.
11
14
  */
12
- export async function filterPeers(
15
+ export function filterPeersByDiscovery(
13
16
  peers: Peer[],
14
17
  numPeers: number,
15
18
  maxBootstrapPeers: number
16
- ): Promise<Peer[]> {
19
+ ): Peer[] {
17
20
  // Collect the bootstrap peers up to the specified maximum
18
- const bootstrapPeers = peers
21
+ let bootstrapPeers = peers
19
22
  .filter((peer) => peer.tags.has(Tags.BOOTSTRAP))
20
23
  .slice(0, maxBootstrapPeers);
21
24
 
25
+ // If numPeers is less than the number of bootstrap peers, adjust the bootstrapPeers array
26
+ if (numPeers > 0 && numPeers < bootstrapPeers.length) {
27
+ bootstrapPeers = bootstrapPeers.slice(0, numPeers);
28
+ }
29
+
22
30
  // Collect non-bootstrap peers
23
31
  const nonBootstrapPeers = peers.filter(
24
32
  (peer) => !peer.tags.has(Tags.BOOTSTRAP)
@@ -1,10 +1,9 @@
1
- import type { PeerId } from "@libp2p/interface/peer-id";
2
- import type { PeerStore } from "@libp2p/interface/peer-store";
1
+ import type { PeerId, PeerStore } from "@libp2p/interface";
2
+ import type { PingService } from "@libp2p/ping";
3
3
  import type { IRelay, PeerIdStr } from "@waku/interfaces";
4
4
  import type { KeepAliveOptions } from "@waku/interfaces";
5
5
  import { Logger, pubsubTopicToSingleShardInfo } from "@waku/utils";
6
6
  import { utf8ToBytes } from "@waku/utils/bytes";
7
- import type { PingService } from "libp2p/ping";
8
7
 
9
8
  import { createEncoder } from "./message/version_0.js";
10
9