diff --git a/codexdht/private/eth/p2p/discoveryv5/protocol.nim b/codexdht/private/eth/p2p/discoveryv5/protocol.nim index 1421cb1..f16e0c0 100644 --- a/codexdht/private/eth/p2p/discoveryv5/protocol.nim +++ b/codexdht/private/eth/p2p/discoveryv5/protocol.nim @@ -180,6 +180,7 @@ type talkProtocols*: Table[seq[byte], TalkProtocol] # TODO: Table is a bit of rng*: ref HmacDrbgContext providers: ProvidersManager + clientMode*: bool TalkProtocolHandler* = proc(p: TalkProtocol, request: seq[byte], fromId: NodeId, fromUdpAddress: Address): seq[byte] {.gcsafe, raises: [Defect].} @@ -340,10 +341,13 @@ proc handleFindNode(d: Protocol, fromId: NodeId, fromAddr: Address, if fn.distances.len == 0: d.sendNodes(fromId, fromAddr, reqId, []) elif fn.distances.contains(0): - # A request for our own record. - # It would be a weird request if there are more distances next to 0 - # requested, so in this case lets just pass only our own. TODO: OK? - d.sendNodes(fromId, fromAddr, reqId, [d.localNode]) + if d.clientMode: + d.sendNodes(fromId, fromAddr, reqId, []) + else: + # A request for our own record. + # It would be a weird request if there are more distances next to 0 + # requested, so in this case lets just pass only our own. TODO: OK? + d.sendNodes(fromId, fromAddr, reqId, [d.localNode]) else: # TODO: Still deduplicate also? if fn.distances.all(proc (x: uint16): bool = return x <= 256): @@ -731,7 +735,7 @@ proc addProvider*( var res = await d.lookup(cId) # TODO: lookup is specified as not returning local, even if that is the closest. Is this OK? - if res.len == 0: + if res.len == 0 and not d.clientMode: res.add(d.localNode) for toNode in res: if toNode != d.localNode: diff --git a/tests/discv5/test_discoveryv5.nim b/tests/discv5/test_discoveryv5.nim index 375dc93..67b6698 100644 --- a/tests/discv5/test_discoveryv5.nim +++ b/tests/discv5/test_discoveryv5.nim @@ -777,3 +777,36 @@ suite "Discovery v5 Tests": await node1.closeWait() await node2.closeWait() + + test "Client mode: findNode(distance=0) returns empty": + # In client mode, the node should not advertise itself when asked for its + # own record (distance=0), so it does not appear in other nodes' routing tables. + let + clientNode = initDiscoveryNode(rng, PrivateKey.example(rng), localAddress(20310)) + serverNode = initDiscoveryNode(rng, PrivateKey.example(rng), localAddress(20311)) + + clientNode.clientMode = true + + let response = await discv5_protocol.findNode(serverNode, clientNode.localNode, @[0'u16]) + + check: + response.isOk() + response[].len == 0 + + await clientNode.closeWait() + await serverNode.closeWait() + + test "Server mode: findNode(distance=0) returns own record": + let + node1 = initDiscoveryNode(rng, PrivateKey.example(rng), localAddress(20312)) + node2 = initDiscoveryNode(rng, PrivateKey.example(rng), localAddress(20313)) + + let response = await discv5_protocol.findNode(node1, node2.localNode, @[0'u16]) + + check: + response.isOk() + response[].len == 1 + response[][0].id == node2.localNode.id + + await node1.closeWait() + await node2.closeWait()