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,125 @@ 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
+ let peerPings : Map < string , number > ;
123
+ const protocols = [ TestCodec ] ;
124
+
125
+ beforeEach ( async function ( ) {
126
+ this . timeout ( 10000 ) ;
127
+ const waku = await createLightNode ( ) ;
128
+ await waku . start ( ) ;
129
+ await delay ( 3000 ) ;
130
+ peerStore = waku . libp2p . peerStore ;
131
+ peerPings = new Map ( ) ;
132
+ } ) ;
133
+
134
+ afterEach ( ( ) => {
135
+ sinon . restore ( ) ;
136
+ } ) ;
137
+
138
+ it ( "should return the peer with the lowest ping" , async function ( ) {
139
+ const peer1 = await createSecp256k1PeerId ( ) ;
140
+ const peer2 = await createSecp256k1PeerId ( ) ;
141
+ const peer3 = await createSecp256k1PeerId ( ) ;
142
+
143
+ const mockPeers = [
144
+ { id : peer1 , protocols : [ TestCodec ] } ,
145
+ { id : peer2 , protocols : [ TestCodec ] } ,
146
+ { id : peer3 , protocols : [ TestCodec ] }
147
+ ] as Peer [ ] ;
148
+
149
+ sinon . stub ( peerStore , "forEach" ) . callsFake ( async ( callback ) => {
150
+ for ( const peer of mockPeers ) {
151
+ callback ( peer ) ;
152
+ }
153
+ } ) ;
154
+
155
+ peerPings . set ( peer1 . toString ( ) , 500 ) ;
156
+ peerPings . set ( peer2 . toString ( ) , 1000 ) ;
157
+ peerPings . set ( peer3 . toString ( ) , 100 ) ;
158
+
159
+ const result = await selectPeerForProtocol ( peerStore , peerPings , protocols ) ;
160
+
161
+ expect ( result . peer ) . to . deep . equal ( mockPeers [ 2 ] ) ;
162
+ expect ( result . protocol ) . to . equal ( TestCodec ) ;
163
+ } ) ;
164
+
165
+ it ( "should return the peer with the provided peerId" , async function ( ) {
166
+ const targetPeer = await createSecp256k1PeerId ( ) ;
167
+ const mockPeer = { id : targetPeer , protocols : [ TestCodec ] } as Peer ;
168
+ sinon . stub ( peerStore , "get" ) . withArgs ( targetPeer ) . resolves ( mockPeer ) ;
169
+
170
+ const result = await selectPeerForProtocol (
171
+ peerStore ,
172
+ peerPings ,
173
+ protocols ,
174
+ targetPeer
175
+ ) ;
176
+ expect ( result . peer ) . to . deep . equal ( mockPeer ) ;
177
+ } ) ;
178
+
179
+ it ( "should return a random peer when all peers have the same latency" , async function ( ) {
180
+ const peer1 = await createSecp256k1PeerId ( ) ;
181
+ const peer2 = await createSecp256k1PeerId ( ) ;
182
+ const peer3 = await createSecp256k1PeerId ( ) ;
183
+
184
+ const mockPeers = [
185
+ { id : peer1 , protocols : [ TestCodec ] } ,
186
+ { id : peer2 , protocols : [ TestCodec ] } ,
187
+ { id : peer3 , protocols : [ TestCodec ] }
188
+ ] as Peer [ ] ;
189
+
190
+ sinon . stub ( peerStore , "forEach" ) . callsFake ( async ( callback ) => {
191
+ for ( const peer of mockPeers ) {
192
+ callback ( peer ) ;
193
+ }
194
+ } ) ;
195
+
196
+ peerPings . set ( peer1 . toString ( ) , 500 ) ;
197
+ peerPings . set ( peer2 . toString ( ) , 500 ) ;
198
+ peerPings . set ( peer3 . toString ( ) , 500 ) ;
199
+
200
+ const result = await selectPeerForProtocol ( peerStore , peerPings , protocols ) ;
201
+
202
+ expect ( mockPeers ) . to . deep . include ( result . peer ) ;
203
+ } ) ;
204
+
205
+ it ( "should throw an error when no peer matches the given protocols" , async function ( ) {
206
+ const mockPeers = [
207
+ { id : await createSecp256k1PeerId ( ) , protocols : [ "DifferentCodec" ] } ,
208
+ {
209
+ id : await createSecp256k1PeerId ( ) ,
210
+ protocols : [ "AnotherDifferentCodec" ]
211
+ }
212
+ ] as Peer [ ] ;
213
+
214
+ sinon . stub ( peerStore , "forEach" ) . callsFake ( async ( callback ) => {
215
+ for ( const peer of mockPeers ) {
216
+ callback ( peer ) ;
217
+ }
218
+ } ) ;
219
+
220
+ await expect (
221
+ selectPeerForProtocol ( peerStore , peerPings , protocols )
222
+ ) . to . be . rejectedWith (
223
+ `Failed to find known peer that registers protocols: ${ protocols } `
224
+ ) ;
225
+ } ) ;
226
+
227
+ it ( "should throw an error when the selected peer does not register the required protocols" , async function ( ) {
228
+ const targetPeer = await createSecp256k1PeerId ( ) ;
229
+ const mockPeer = { id : targetPeer , protocols : [ "DifferentCodec" ] } as Peer ;
230
+ sinon . stub ( peerStore , "get" ) . withArgs ( targetPeer ) . resolves ( mockPeer ) ;
231
+
232
+ await expect (
233
+ selectPeerForProtocol ( peerStore , peerPings , protocols , targetPeer )
234
+ ) . to . be . rejectedWith (
235
+ `Peer does not register required protocols (${ targetPeer . toString ( ) } ): ${ protocols } `
236
+ ) ;
237
+ } ) ;
238
+ } ) ;
0 commit comments