@@ -221,10 +221,11 @@ suite "KadDHT Find":
221221 kads[0 ].hasKey (kads[2 ].rtable.selfId)
222222
223223 asyncTest " Find node with empty key returns closest peers" :
224- let kads = setupKadSwitches (2 )
224+ let kads = setupKadSwitches (3 )
225225 startAndDeferStop (kads)
226226
227- await connect (kads[0 ], kads[1 ])
227+ # Setup: kads[0] <-> kads[1], kads[0] <-> kads[2]
228+ await connectHub (kads[0 ], kads[1 ..^ 1 ])
228229
229230 # Send FIND_NODE with empty key directly
230231 let emptyKey: Key = @ []
@@ -235,9 +236,9 @@ suite "KadDHT Find":
235236 check:
236237 response.msgType == MessageType .findNode
237238 response.closerPeers.len == 1
238- response.closerPeers[0 ].id.get () == kads[1 ].rtable.selfId
239+ response.closerPeers[0 ].id.get () == kads[2 ].rtable.selfId
239240
240- asyncTest " Find node for own PeerID returns closest peers " :
241+ asyncTest " Find node for own PeerID excludes the requester " :
241242 let kads = setupKadSwitches (3 )
242243 startAndDeferStop (kads)
243244
@@ -252,9 +253,78 @@ suite "KadDHT Find":
252253 let closerPeersIds = response.closerPeers.mapIt (it.id.get ())
253254 check:
254255 response.msgType == MessageType .findNode
255- # kads[0] knows kads[1] and kads[2], should return both as closest peers
256- response.closerPeers.len == 2
257- kads[1 ].rtable.selfId in closerPeersIds
256+ response.closerPeers.len == 1
257+ kads[1 ].rtable.selfId notin closerPeersIds
258+ kads[2 ].rtable.selfId in closerPeersIds
259+
260+ asyncTest " Find node for a known target returns it once" :
261+ let kads = setupKadSwitches (3 )
262+ startAndDeferStop (kads)
263+
264+ await connectHub (kads[0 ], kads[1 ..^ 1 ])
265+
266+ let response = (
267+ await kads[1 ].dispatchFindNode (
268+ kads[0 ].switch.peerInfo.peerId, kads[2 ].rtable.selfId
269+ )
270+ ).value ()
271+
272+ check:
273+ response.closerPeers.len == 1
274+ response.closerPeers[0 ].id.get () == kads[2 ].rtable.selfId
275+
276+ asyncTest " Find node for an unknown target omits it" :
277+ let kads = setupKadSwitches (3 )
278+ startAndDeferStop (kads)
279+
280+ await connectHub (kads[0 ], kads[1 ..^ 1 ])
281+
282+ let unknownTarget = randomPeerId ().toKey ()
283+ let response = (
284+ await kads[1 ].dispatchFindNode (kads[0 ].switch.peerInfo.peerId, unknownTarget)
285+ ).value ()
286+
287+ let closerPeersIds = response.closerPeers.mapIt (it.id.get ())
288+ check:
289+ unknownTarget notin closerPeersIds
290+ kads[2 ].rtable.selfId in closerPeersIds
291+
292+ asyncTest " Find node returns a target known only from the address book" :
293+ let kads = setupKadSwitches (3 )
294+ startAndDeferStop (kads)
295+
296+ await connectHub (kads[0 ], kads[1 ..^ 1 ])
297+
298+ # A client-mode peer is in nobody's routing table, but its addresses are known.
299+ let client = randomPeerId ()
300+ kads[0 ].switch.peerStore[AddressBook ][client] =
301+ @ [MultiAddress .init (" /ip4/127.0.0.1/tcp/9999" ).tryGet ()]
302+
303+ let response = (
304+ await kads[1 ].dispatchFindNode (kads[0 ].switch.peerInfo.peerId, client.toKey ())
305+ ).value ()
306+
307+ check:
308+ not kads[0 ].hasKey (client.toKey ())
309+ response.closerPeers[0 ].id.get () == client.toKey ()
310+
311+ asyncTest " Find node excludes the requester for an unrelated target" :
312+ let kads = setupKadSwitches (3 )
313+ startAndDeferStop (kads)
314+
315+ await connectHub (kads[0 ], kads[1 ..^ 1 ])
316+
317+ # kads[0] knows kads[1] and kads[2], and both fit in a reply, so pre-filter
318+ # kads[1] would get itself back even though the target is unrelated to it.
319+ let response = (
320+ await kads[1 ].dispatchFindNode (
321+ kads[0 ].switch.peerInfo.peerId, randomPeerId ().toKey ()
322+ )
323+ ).value ()
324+
325+ let closerPeersIds = response.closerPeers.mapIt (it.id.get ())
326+ check:
327+ kads[1 ].rtable.selfId notin closerPeersIds
258328 kads[2 ].rtable.selfId in closerPeersIds
259329
260330 asyncTest " Find node with empty routing table returns empty result" :
0 commit comments