@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,20 +1,16 @@
1
- import type { Stream } from "@libp2p/interface/connection";
2
- import type { PeerId } from "@libp2p/interface/peer-id";
1
+ import type { Peer, PeerId, Stream } from "@libp2p/interface";
3
2
  import {
3
+ Failure,
4
+ IBaseProtocolCore,
4
5
  IEncoder,
5
- ILightPush,
6
6
  IMessage,
7
7
  Libp2p,
8
8
  ProtocolCreateOptions,
9
- PubsubTopic,
10
- SendError,
11
- SendResult
9
+ ProtocolError,
10
+ ProtocolResult
12
11
  } from "@waku/interfaces";
13
12
  import { PushResponse } from "@waku/proto";
14
- import {
15
- ensurePubsubTopicIsConfigured,
16
- isMessageSizeUnderCap
17
- } from "@waku/utils";
13
+ import { isMessageSizeUnderCap } from "@waku/utils";
18
14
  import { Logger } from "@waku/utils";
19
15
  import all from "it-all";
20
16
  import * as lp from "it-length-prefixed";
@@ -30,42 +26,37 @@ const log = new Logger("light-push");
30
26
  export const LightPushCodec = "/vac/waku/lightpush/2.0.0-beta1";
31
27
  export { PushResponse };
32
28
 
33
- type PreparePushMessageResult =
34
- | {
35
- query: PushRpc;
36
- error: null;
37
- }
38
- | {
39
- query: null;
40
- error: SendError;
41
- };
29
+ type PreparePushMessageResult = ProtocolResult<"query", PushRpc>;
30
+
31
+ type CoreSendResult = ProtocolResult<"success", PeerId, "failure", Failure>;
42
32
 
43
33
  /**
44
34
  * Implements the [Waku v2 Light Push protocol](https://rfc.vac.dev/spec/19/).
45
35
  */
46
- class LightPush extends BaseProtocol implements ILightPush {
47
- private readonly pubsubTopics: PubsubTopic[];
48
- private readonly NUM_PEERS_PROTOCOL = 1;
49
-
36
+ export class LightPushCore extends BaseProtocol implements IBaseProtocolCore {
50
37
  constructor(libp2p: Libp2p, options?: ProtocolCreateOptions) {
51
- super(LightPushCodec, libp2p.components);
52
- this.pubsubTopics = this.initializePubsubTopic(options);
38
+ super(
39
+ LightPushCodec,
40
+ libp2p.components,
41
+ log,
42
+ options!.pubsubTopics!,
43
+ options
44
+ );
53
45
  }
54
46
 
55
47
  private async preparePushMessage(
56
48
  encoder: IEncoder,
57
- message: IMessage,
58
- pubsubTopic: string
49
+ message: IMessage
59
50
  ): Promise<PreparePushMessageResult> {
60
51
  try {
61
52
  if (!message.payload || message.payload.length === 0) {
62
53
  log.error("Failed to send waku light push: payload is empty");
63
- return { query: null, error: SendError.EMPTY_PAYLOAD };
54
+ return { query: null, error: ProtocolError.EMPTY_PAYLOAD };
64
55
  }
65
56
 
66
57
  if (!(await isMessageSizeUnderCap(encoder, message))) {
67
58
  log.error("Failed to send waku light push: message is bigger than 1MB");
68
- return { query: null, error: SendError.SIZE_TOO_BIG };
59
+ return { query: null, error: ProtocolError.SIZE_TOO_BIG };
69
60
  }
70
61
 
71
62
  const protoMessage = await encoder.toProtoObj(message);
@@ -73,131 +64,120 @@ class LightPush extends BaseProtocol implements ILightPush {
73
64
  log.error("Failed to encode to protoMessage, aborting push");
74
65
  return {
75
66
  query: null,
76
- error: SendError.ENCODE_FAILED
67
+ error: ProtocolError.ENCODE_FAILED
77
68
  };
78
69
  }
79
70
 
80
- const query = PushRpc.createRequest(protoMessage, pubsubTopic);
71
+ const query = PushRpc.createRequest(protoMessage, encoder.pubsubTopic);
81
72
  return { query, error: null };
82
73
  } catch (error) {
83
74
  log.error("Failed to prepare push message", error);
84
75
 
85
76
  return {
86
77
  query: null,
87
- error: SendError.GENERIC_FAIL
78
+ error: ProtocolError.GENERIC_FAIL
88
79
  };
89
80
  }
90
81
  }
91
82
 
92
- async send(encoder: IEncoder, message: IMessage): Promise<SendResult> {
93
- const { pubsubTopic } = encoder;
94
- ensurePubsubTopicIsConfigured(pubsubTopic, this.pubsubTopics);
95
-
96
- const recipients: PeerId[] = [];
97
-
83
+ async send(
84
+ encoder: IEncoder,
85
+ message: IMessage,
86
+ peer: Peer
87
+ ): Promise<CoreSendResult> {
98
88
  const { query, error: preparationError } = await this.preparePushMessage(
99
89
  encoder,
100
- message,
101
- pubsubTopic
90
+ message
102
91
  );
103
92
 
104
93
  if (preparationError || !query) {
105
94
  return {
106
- recipients,
107
- errors: [preparationError]
95
+ success: null,
96
+ failure: {
97
+ error: preparationError,
98
+ peerId: peer.id
99
+ }
108
100
  };
109
101
  }
110
102
 
111
- //TODO: get a relevant peer for the topic/shard
112
- const peers = await this.getPeers({
113
- maxBootstrapPeers: 1,
114
- numPeers: this.NUM_PEERS_PROTOCOL
115
- });
116
-
117
- if (!peers.length) {
103
+ let stream: Stream | undefined;
104
+ try {
105
+ stream = await this.getStream(peer);
106
+ } catch (err) {
107
+ log.error(
108
+ `Failed to get a stream for remote peer${peer.id.toString()}`,
109
+ err
110
+ );
118
111
  return {
119
- recipients,
120
- errors: [SendError.NO_PEER_AVAILABLE]
112
+ success: null,
113
+ failure: {
114
+ error: ProtocolError.REMOTE_PEER_FAULT,
115
+ peerId: peer.id
116
+ }
121
117
  };
122
118
  }
123
119
 
124
- const promises = peers.map(async (peer) => {
125
- let stream: Stream | undefined;
126
- try {
127
- stream = await this.getStream(peer);
128
- } catch (err) {
129
- log.error(
130
- `Failed to get a stream for remote peer${peer.id.toString()}`,
131
- err
132
- );
133
- return { recipients, error: SendError.REMOTE_PEER_FAULT };
134
- }
135
-
136
- let res: Uint8ArrayList[] | undefined;
137
- try {
138
- res = await pipe(
139
- [query.encode()],
140
- lp.encode,
141
- stream,
142
- lp.decode,
143
- async (source) => await all(source)
144
- );
145
- } catch (err) {
146
- log.error("Failed to send waku light push request", err);
147
- return { recipients, error: SendError.GENERIC_FAIL };
148
- }
149
-
150
- const bytes = new Uint8ArrayList();
151
- res.forEach((chunk) => {
152
- bytes.append(chunk);
153
- });
154
-
155
- let response: PushResponse | undefined;
156
- try {
157
- response = PushRpc.decode(bytes).response;
158
- } catch (err) {
159
- log.error("Failed to decode push reply", err);
160
- return { recipients, error: SendError.DECODE_FAILED };
161
- }
120
+ let res: Uint8ArrayList[] | undefined;
121
+ try {
122
+ res = await pipe(
123
+ [query.encode()],
124
+ lp.encode,
125
+ stream,
126
+ lp.decode,
127
+ async (source) => await all(source)
128
+ );
129
+ } catch (err) {
130
+ log.error("Failed to send waku light push request", err);
131
+ return {
132
+ success: null,
133
+ failure: {
134
+ error: ProtocolError.GENERIC_FAIL,
135
+ peerId: peer.id
136
+ }
137
+ };
138
+ }
162
139
 
163
- if (!response) {
164
- log.error("Remote peer fault: No response in PushRPC");
165
- return { recipients, error: SendError.REMOTE_PEER_FAULT };
166
- }
140
+ const bytes = new Uint8ArrayList();
141
+ res.forEach((chunk) => {
142
+ bytes.append(chunk);
143
+ });
167
144
 
168
- if (!response.isSuccess) {
169
- log.error("Remote peer rejected the message: ", response.info);
170
- return { recipients, error: SendError.REMOTE_PEER_REJECTED };
171
- }
145
+ let response: PushResponse | undefined;
146
+ try {
147
+ response = PushRpc.decode(bytes).response;
148
+ } catch (err) {
149
+ log.error("Failed to decode push reply", err);
150
+ return {
151
+ success: null,
152
+ failure: {
153
+ error: ProtocolError.DECODE_FAILED,
154
+ peerId: peer.id
155
+ }
156
+ };
157
+ }
172
158
 
173
- recipients.some((recipient) => recipient.equals(peer.id)) ||
174
- recipients.push(peer.id);
159
+ if (!response) {
160
+ log.error("Remote peer fault: No response in PushRPC");
161
+ return {
162
+ success: null,
163
+ failure: {
164
+ error: ProtocolError.REMOTE_PEER_FAULT,
165
+ peerId: peer.id
166
+ }
167
+ };
168
+ }
175
169
 
176
- return { recipients };
177
- });
170
+ if (!response.isSuccess) {
171
+ log.error("Remote peer rejected the message: ", response.info);
172
+ return {
173
+ success: null,
174
+ failure: {
175
+ error: ProtocolError.REMOTE_PEER_REJECTED,
176
+ peerId: peer.id
177
+ }
178
+ };
179
+ }
178
180
 
179
- const results = await Promise.allSettled(promises);
180
- const errors = results
181
- .filter(
182
- (
183
- result
184
- ): result is PromiseFulfilledResult<{
185
- recipients: PeerId[];
186
- error: SendError | undefined;
187
- }> => result.status === "fulfilled"
188
- )
189
- .map((result) => result.value.error)
190
- .filter((error) => error !== undefined) as SendError[];
191
-
192
- return {
193
- recipients,
194
- errors
195
- };
181
+ return { success: peer.id, failure: null };
196
182
  }
197
183
  }
198
-
199
- export function wakuLightPush(
200
- init: Partial<ProtocolCreateOptions> = {}
201
- ): (libp2p: Libp2p) => ILightPush {
202
- return (libp2p: Libp2p) => new LightPush(libp2p, init);
203
- }
@@ -1,14 +1,15 @@
1
- import type { PeerId } from "@libp2p/interface/peer-id";
2
- import { IncomingStreamData } from "@libp2p/interface/stream-handler";
3
- import { encodeRelayShard } from "@waku/enr";
4
- import type {
5
- IMetadata,
6
- Libp2pComponents,
7
- ShardInfo,
8
- ShardingParams
1
+ import type { PeerId } from "@libp2p/interface";
2
+ import { IncomingStreamData } from "@libp2p/interface";
3
+ import {
4
+ type IMetadata,
5
+ type Libp2pComponents,
6
+ type PeerIdStr,
7
+ ProtocolError,
8
+ QueryResult,
9
+ type ShardInfo
9
10
  } from "@waku/interfaces";
10
11
  import { proto_metadata } from "@waku/proto";
11
- import { Logger } from "@waku/utils";
12
+ import { encodeRelayShard, Logger, shardInfoToPubsubTopics } from "@waku/utils";
12
13
  import all from "it-all";
13
14
  import * as lp from "it-length-prefixed";
14
15
  import { pipe } from "it-pipe";
@@ -20,13 +21,21 @@ const log = new Logger("metadata");
20
21
 
21
22
  export const MetadataCodec = "/vac/waku/metadata/1.0.0";
22
23
 
23
- class Metadata extends BaseProtocol {
24
- private readonly shardInfo: ShardingParams;
24
+ class Metadata extends BaseProtocol implements IMetadata {
25
25
  private libp2pComponents: Libp2pComponents;
26
- constructor(shardInfo: ShardingParams, libp2p: Libp2pComponents) {
27
- super(MetadataCodec, libp2p.components);
26
+ handshakesConfirmed: Map<PeerIdStr, ShardInfo> = new Map();
27
+
28
+ constructor(
29
+ public shardInfo: ShardInfo,
30
+ libp2p: Libp2pComponents
31
+ ) {
32
+ super(
33
+ MetadataCodec,
34
+ libp2p.components,
35
+ log,
36
+ shardInfoToPubsubTopics(shardInfo)
37
+ );
28
38
  this.libp2pComponents = libp2p;
29
- this.shardInfo = shardInfo;
30
39
  void libp2p.registrar.handle(MetadataCodec, (streamData) => {
31
40
  void this.onRequest(streamData);
32
41
  });
@@ -50,15 +59,13 @@ class Metadata extends BaseProtocol {
50
59
  async (source) => await all(source)
51
60
  );
52
61
 
53
- const remoteShardInfoResponse =
54
- this.decodeMetadataResponse(encodedResponse);
62
+ const { error, shardInfo } = this.decodeMetadataResponse(encodedResponse);
63
+
64
+ if (error) {
65
+ return;
66
+ }
55
67
 
56
- // add or update the shardInfo to peer store
57
- await this.libp2pComponents.peerStore.merge(connection.remotePeer, {
58
- metadata: {
59
- shardInfo: encodeRelayShard(remoteShardInfoResponse)
60
- }
61
- });
68
+ await this.savePeerShardInfo(connection.remotePeer, shardInfo);
62
69
  } catch (error) {
63
70
  log.error("Error handling metadata request", error);
64
71
  }
@@ -67,10 +74,16 @@ class Metadata extends BaseProtocol {
67
74
  /**
68
75
  * Make a metadata query to a peer
69
76
  */
70
- async query(peerId: PeerId): Promise<ShardInfo> {
77
+ async query(peerId: PeerId): Promise<QueryResult> {
71
78
  const request = proto_metadata.WakuMetadataRequest.encode(this.shardInfo);
72
79
 
73
- const peer = await this.getPeer(peerId);
80
+ const peer = await this.peerStore.get(peerId);
81
+ if (!peer) {
82
+ return {
83
+ shardInfo: null,
84
+ error: ProtocolError.NO_PEER_AVAILABLE
85
+ };
86
+ }
74
87
 
75
88
  const stream = await this.getStream(peer);
76
89
 
@@ -82,12 +95,38 @@ class Metadata extends BaseProtocol {
82
95
  async (source) => await all(source)
83
96
  );
84
97
 
85
- const decodedResponse = this.decodeMetadataResponse(encodedResponse);
98
+ const { error, shardInfo } = this.decodeMetadataResponse(encodedResponse);
99
+
100
+ if (error) {
101
+ return {
102
+ shardInfo: null,
103
+ error
104
+ };
105
+ }
106
+
107
+ await this.savePeerShardInfo(peerId, shardInfo);
86
108
 
87
- return decodedResponse;
109
+ return {
110
+ shardInfo,
111
+ error: null
112
+ };
88
113
  }
89
114
 
90
- private decodeMetadataResponse(encodedResponse: Uint8ArrayList[]): ShardInfo {
115
+ public async confirmOrAttemptHandshake(peerId: PeerId): Promise<QueryResult> {
116
+ const shardInfo = this.handshakesConfirmed.get(peerId.toString());
117
+ if (shardInfo) {
118
+ return {
119
+ shardInfo,
120
+ error: null
121
+ };
122
+ }
123
+
124
+ return await this.query(peerId);
125
+ }
126
+
127
+ private decodeMetadataResponse(
128
+ encodedResponse: Uint8ArrayList[]
129
+ ): QueryResult {
91
130
  const bytes = new Uint8ArrayList();
92
131
 
93
132
  encodedResponse.forEach((chunk) => {
@@ -97,14 +136,37 @@ class Metadata extends BaseProtocol {
97
136
  bytes
98
137
  ) as ShardInfo;
99
138
 
100
- if (!response) log.error("Error decoding metadata response");
139
+ if (!response) {
140
+ log.error("Error decoding metadata response");
141
+ return {
142
+ shardInfo: null,
143
+ error: ProtocolError.DECODE_FAILED
144
+ };
145
+ }
146
+
147
+ return {
148
+ shardInfo: response,
149
+ error: null
150
+ };
151
+ }
152
+
153
+ private async savePeerShardInfo(
154
+ peerId: PeerId,
155
+ shardInfo: ShardInfo
156
+ ): Promise<void> {
157
+ // add or update the shardInfo to peer store
158
+ await this.libp2pComponents.peerStore.merge(peerId, {
159
+ metadata: {
160
+ shardInfo: encodeRelayShard(shardInfo)
161
+ }
162
+ });
101
163
 
102
- return response;
164
+ this.handshakesConfirmed.set(peerId.toString(), shardInfo);
103
165
  }
104
166
  }
105
167
 
106
168
  export function wakuMetadata(
107
- shardInfo: ShardingParams
169
+ shardInfo: ShardInfo
108
170
  ): (components: Libp2pComponents) => IMetadata {
109
171
  return (components: Libp2pComponents) => new Metadata(shardInfo, components);
110
172
  }
@@ -1,4 +1,4 @@
1
- import type { Stream } from "@libp2p/interface/connection";
1
+ import type { Stream } from "@libp2p/interface";
2
2
  import { sha256 } from "@noble/hashes/sha256";
3
3
  import {
4
4
  Cursor,
@@ -6,8 +6,7 @@ import {
6
6
  IDecoder,
7
7
  IStore,
8
8
  Libp2p,
9
- ProtocolCreateOptions,
10
- PubsubTopic
9
+ ProtocolCreateOptions
11
10
  } from "@waku/interfaces";
12
11
  import { proto_store as proto } from "@waku/proto";
13
12
  import { ensurePubsubTopicIsConfigured, isDefined } from "@waku/utils";
@@ -74,12 +73,10 @@ export interface QueryOptions {
74
73
  * The Waku Store protocol can be used to retrieved historical messages.
75
74
  */
76
75
  class Store extends BaseProtocol implements IStore {
77
- private readonly pubsubTopics: PubsubTopic[];
78
76
  private readonly NUM_PEERS_PROTOCOL = 1;
79
77
 
80
78
  constructor(libp2p: Libp2p, options?: ProtocolCreateOptions) {
81
- super(StoreCodec, libp2p.components);
82
- this.pubsubTopics = this.initializePubsubTopic(options);
79
+ super(StoreCodec, libp2p.components, log, options!.pubsubTopics!, options);
83
80
  }
84
81
 
85
82
  /**
@@ -1,6 +1,5 @@
1
- import type { PeerUpdate } from "@libp2p/interface";
2
- import type { Stream } from "@libp2p/interface/connection";
3
- import { Peer } from "@libp2p/interface/peer-store";
1
+ import type { PeerUpdate, Stream } from "@libp2p/interface";
2
+ import { Peer } from "@libp2p/interface";
4
3
  import { Libp2p } from "@waku/interfaces";
5
4
  import { Logger } from "@waku/utils";
6
5
  import { selectConnection } from "@waku/utils/libp2p";
@@ -1,15 +1,20 @@
1
1
  import type { IdentifyResult } from "@libp2p/interface";
2
- import type { IBaseProtocol, IRelay, Waku } from "@waku/interfaces";
2
+ import type {
3
+ IBaseProtocolCore,
4
+ IMetadata,
5
+ IRelay,
6
+ Waku
7
+ } from "@waku/interfaces";
3
8
  import { Protocols } from "@waku/interfaces";
4
9
  import { Logger } from "@waku/utils";
5
10
  import { pEvent } from "p-event";
6
-
7
11
  const log = new Logger("wait-for-remote-peer");
8
12
 
13
+ //TODO: move this function within the Waku class: https://github.com/waku-org/js-waku/issues/1761
9
14
  /**
10
15
  * Wait for a remote peer to be ready given the passed protocols.
11
16
  * Must be used after attempting to connect to nodes, using
12
- * {@link @waku/core!WakuNode.dial} or a bootstrap method with
17
+ * {@link @waku/sdk!WakuNode.dial} or a bootstrap method with
13
18
  * {@link @waku/sdk!createLightNode}.
14
19
  *
15
20
  * If the passed protocols is a GossipSub protocol, then it resolves only once
@@ -45,19 +50,28 @@ export async function waitForRemotePeer(
45
50
  if (protocols.includes(Protocols.Store)) {
46
51
  if (!waku.store)
47
52
  throw new Error("Cannot wait for Store peer: protocol not mounted");
48
- promises.push(waitForConnectedPeer(waku.store));
53
+ promises.push(
54
+ waitForConnectedPeer(waku.store, waku.libp2p.services.metadata)
55
+ );
49
56
  }
50
57
 
51
58
  if (protocols.includes(Protocols.LightPush)) {
52
59
  if (!waku.lightPush)
53
60
  throw new Error("Cannot wait for LightPush peer: protocol not mounted");
54
- promises.push(waitForConnectedPeer(waku.lightPush));
61
+ promises.push(
62
+ waitForConnectedPeer(
63
+ waku.lightPush.protocol,
64
+ waku.libp2p.services.metadata
65
+ )
66
+ );
55
67
  }
56
68
 
57
69
  if (protocols.includes(Protocols.Filter)) {
58
70
  if (!waku.filter)
59
71
  throw new Error("Cannot wait for Filter peer: protocol not mounted");
60
- promises.push(waitForConnectedPeer(waku.filter));
72
+ promises.push(
73
+ waitForConnectedPeer(waku.filter, waku.libp2p.services.metadata)
74
+ );
61
75
  }
62
76
 
63
77
  if (timeoutMs) {
@@ -71,23 +85,65 @@ export async function waitForRemotePeer(
71
85
  }
72
86
  }
73
87
 
88
+ //TODO: move this function within protocol SDK class: https://github.com/waku-org/js-waku/issues/1761
74
89
  /**
75
90
  * Wait for a peer with the given protocol to be connected.
91
+ * If sharding is enabled on the node, it will also wait for the peer to be confirmed by the metadata service.
76
92
  */
77
- async function waitForConnectedPeer(protocol: IBaseProtocol): Promise<void> {
93
+ async function waitForConnectedPeer(
94
+ protocol: IBaseProtocolCore,
95
+ metadataService?: IMetadata
96
+ ): Promise<void> {
78
97
  const codec = protocol.multicodec;
79
- const peers = await protocol.peers();
98
+ const peers = await protocol.connectedPeers();
80
99
 
81
100
  if (peers.length) {
82
- log.info(`${codec} peer found: `, peers[0].id.toString());
83
- return;
101
+ if (!metadataService) {
102
+ log.info(`${codec} peer found: `, peers[0].id.toString());
103
+ return;
104
+ }
105
+
106
+ // once a peer is connected, we need to confirm the metadata handshake with at least one of those peers if sharding is enabled
107
+ try {
108
+ await Promise.any(
109
+ peers.map((peer) => metadataService.confirmOrAttemptHandshake(peer.id))
110
+ );
111
+ return;
112
+ } catch (e) {
113
+ if ((e as any).code === "ERR_CONNECTION_BEING_CLOSED")
114
+ log.error(
115
+ `Connection with the peer was closed and possibly because it's on a different shard. Error: ${e}`
116
+ );
117
+
118
+ log.error(`Error waiting for handshake confirmation: ${e}`);
119
+ }
84
120
  }
85
121
 
122
+ log.info(`Waiting for ${codec} peer`);
123
+
124
+ // else we'll just wait for the next peer to connect
86
125
  await new Promise<void>((resolve) => {
87
126
  const cb = (evt: CustomEvent<IdentifyResult>): void => {
88
127
  if (evt.detail?.protocols?.includes(codec)) {
89
- protocol.removeLibp2pEventListener("peer:identify", cb);
90
- resolve();
128
+ if (metadataService) {
129
+ metadataService
130
+ .confirmOrAttemptHandshake(evt.detail.peerId)
131
+ .then(() => {
132
+ protocol.removeLibp2pEventListener("peer:identify", cb);
133
+ resolve();
134
+ })
135
+ .catch((e) => {
136
+ if (e.code === "ERR_CONNECTION_BEING_CLOSED")
137
+ log.error(
138
+ `Connection with the peer was closed and possibly because it's on a different shard. Error: ${e}`
139
+ );
140
+
141
+ log.error(`Error waiting for handshake confirmation: ${e}`);
142
+ });
143
+ } else {
144
+ protocol.removeLibp2pEventListener("peer:identify", cb);
145
+ resolve();
146
+ }
91
147
  }
92
148
  };
93
149
  protocol.addLibp2pEventListener("peer:identify", cb);