1
+ import type { PeerStore } from "@libp2p/interface/peer-store" ;
2
+ import type { Peer } from "@libp2p/interface/peer-store" ;
3
+ import { createSecp256k1PeerId } from "@libp2p/peer-id-factory" ;
1
4
import {
2
5
createDecoder ,
3
6
createEncoder ,
@@ -9,11 +12,16 @@ import { Protocols } from "@waku/interfaces";
9
12
import { createLightNode } from "@waku/sdk" ;
10
13
import { toAsyncIterator } from "@waku/utils" ;
11
14
import { bytesToUtf8 , utf8ToBytes } from "@waku/utils/bytes" ;
12
- import { expect } from "chai" ;
15
+ import { selectPeerForProtocol } from "@waku/utils/libp2p" ;
16
+ import chai , { expect } from "chai" ;
17
+ import chaiAsPromised from "chai-as-promised" ;
18
+ import sinon from "sinon" ;
13
19
14
- import { makeLogFileName , NOISE_KEY_1 } from "../src/index.js" ;
20
+ import { delay , makeLogFileName , NOISE_KEY_1 } from "../src/index.js" ;
15
21
import { NimGoNode } from "../src/node/node.js" ;
16
22
23
+ chai . use ( chaiAsPromised ) ;
24
+
17
25
const TestContentTopic = "/test/1/waku-filter" ;
18
26
const TestEncoder = createEncoder ( { contentTopic : TestContentTopic } ) ;
19
27
const TestDecoder = createDecoder ( TestContentTopic ) ;
@@ -106,3 +114,148 @@ describe("Util: toAsyncIterator: Filter", () => {
106
114
expect ( result . done ) . to . eq ( true ) ;
107
115
} ) ;
108
116
} ) ;
117
+
118
+ const TestCodec = "test/1" ;
119
+
120
+ describe ( "selectPeerForProtocol" , ( ) => {
121
+ let peerStore : PeerStore ;
122
+ const protocols = [ TestCodec ] ;
123
+
124
+ let lowPingPeer : Peer ,
125
+ midPingPeer : Peer ,
126
+ highPingPeer : Peer ,
127
+ differentCodecPeer : Peer ,
128
+ anotherDifferentCodecPeer : Peer ;
129
+
130
+ beforeEach ( async function ( ) {
131
+ this . timeout ( 10000 ) ;
132
+ const waku = await createLightNode ( ) ;
133
+ await waku . start ( ) ;
134
+ await delay ( 3000 ) ;
135
+ peerStore = waku . libp2p . peerStore ;
136
+
137
+ const [
138
+ lowPingPeerId ,
139
+ midPingPeerId ,
140
+ highPingPeerId ,
141
+ differentCodecPeerId ,
142
+ anotherDifferentCodecPeerId
143
+ ] = await Promise . all ( [
144
+ createSecp256k1PeerId ( ) ,
145
+ createSecp256k1PeerId ( ) ,
146
+ createSecp256k1PeerId ( ) ,
147
+ createSecp256k1PeerId ( ) ,
148
+ createSecp256k1PeerId ( )
149
+ ] ) ;
150
+
151
+ lowPingPeer = {
152
+ id : lowPingPeerId ,
153
+ protocols : [ TestCodec ] ,
154
+ metadata : new Map ( ) . set ( "ping" , utf8ToBytes ( "50" ) )
155
+ } as Peer ;
156
+
157
+ midPingPeer = {
158
+ id : midPingPeerId ,
159
+ protocols : [ TestCodec ] ,
160
+ metadata : new Map ( ) . set ( "ping" , utf8ToBytes ( "100" ) )
161
+ } as Peer ;
162
+
163
+ highPingPeer = {
164
+ id : highPingPeerId ,
165
+ protocols : [ TestCodec ] ,
166
+ metadata : new Map ( ) . set ( "ping" , utf8ToBytes ( "500" ) )
167
+ } as Peer ;
168
+
169
+ differentCodecPeer = {
170
+ id : differentCodecPeerId ,
171
+ protocols : [ "DifferentCodec" ]
172
+ } as Peer ;
173
+
174
+ anotherDifferentCodecPeer = {
175
+ id : anotherDifferentCodecPeerId ,
176
+ protocols : [ "AnotherDifferentCodec" ]
177
+ } as Peer ;
178
+ } ) ;
179
+
180
+ afterEach ( ( ) => {
181
+ sinon . restore ( ) ;
182
+ } ) ;
183
+
184
+ it ( "should return the peer with the lowest ping" , async function ( ) {
185
+ const mockPeers = [ highPingPeer , lowPingPeer , midPingPeer ] ;
186
+
187
+ sinon . stub ( peerStore , "get" ) . callsFake ( async ( peerId ) => {
188
+ return mockPeers . find ( ( peer ) => peer . id . equals ( peerId ) ) ! ;
189
+ } ) ;
190
+
191
+ sinon . stub ( peerStore , "forEach" ) . callsFake ( async ( callback ) => {
192
+ for ( const peer of mockPeers ) {
193
+ callback ( peer ) ;
194
+ }
195
+ } ) ;
196
+
197
+ const result = await selectPeerForProtocol ( peerStore , protocols ) ;
198
+
199
+ expect ( result . peer ) . to . deep . equal ( lowPingPeer ) ;
200
+ expect ( result . protocol ) . to . equal ( TestCodec ) ;
201
+ } ) ;
202
+
203
+ it ( "should return the peer with the provided peerId" , async function ( ) {
204
+ const targetPeer = await createSecp256k1PeerId ( ) ;
205
+ const mockPeer = { id : targetPeer , protocols : [ TestCodec ] } as Peer ;
206
+ sinon . stub ( peerStore , "get" ) . withArgs ( targetPeer ) . resolves ( mockPeer ) ;
207
+
208
+ const result = await selectPeerForProtocol (
209
+ peerStore ,
210
+ protocols ,
211
+ targetPeer
212
+ ) ;
213
+ expect ( result . peer ) . to . deep . equal ( mockPeer ) ;
214
+ } ) ;
215
+
216
+ it ( "should return a random peer when all peers have the same latency" , async function ( ) {
217
+ const mockPeers = [ highPingPeer , highPingPeer , highPingPeer ] ;
218
+
219
+ sinon . stub ( peerStore , "get" ) . callsFake ( async ( peerId ) => {
220
+ return mockPeers . find ( ( peer ) => peer . id . equals ( peerId ) ) ! ;
221
+ } ) ;
222
+
223
+ sinon . stub ( peerStore , "forEach" ) . callsFake ( async ( callback ) => {
224
+ for ( const peer of mockPeers ) {
225
+ callback ( peer ) ;
226
+ }
227
+ } ) ;
228
+
229
+ const result = await selectPeerForProtocol ( peerStore , protocols ) ;
230
+
231
+ expect ( mockPeers ) . to . deep . include ( result . peer ) ;
232
+ } ) ;
233
+
234
+ it ( "should throw an error when no peer matches the given protocols" , async function ( ) {
235
+ const mockPeers = [ differentCodecPeer , anotherDifferentCodecPeer ] ;
236
+
237
+ sinon . stub ( peerStore , "forEach" ) . callsFake ( async ( callback ) => {
238
+ for ( const peer of mockPeers ) {
239
+ callback ( peer ) ;
240
+ }
241
+ } ) ;
242
+
243
+ await expect (
244
+ selectPeerForProtocol ( peerStore , protocols )
245
+ ) . to . be . rejectedWith (
246
+ `Failed to find known peer that registers protocols: ${ protocols } `
247
+ ) ;
248
+ } ) ;
249
+
250
+ it ( "should throw an error when the selected peer does not register the required protocols" , async function ( ) {
251
+ const targetPeer = await createSecp256k1PeerId ( ) ;
252
+ const mockPeer = { id : targetPeer , protocols : [ "DifferentCodec" ] } as Peer ;
253
+ sinon . stub ( peerStore , "get" ) . withArgs ( targetPeer ) . resolves ( mockPeer ) ;
254
+
255
+ await expect (
256
+ selectPeerForProtocol ( peerStore , protocols , targetPeer )
257
+ ) . to . be . rejectedWith (
258
+ `Peer does not register required protocols (${ targetPeer . toString ( ) } ): ${ protocols } `
259
+ ) ;
260
+ } ) ;
261
+ } ) ;
0 commit comments