mirror of https://github.com/status-im/nim-eth.git
Fix FindNode to return nodes with specific distance + tests
This commit is contained in:
parent
5bb6ee6451
commit
d3c9ccea67
|
@ -191,12 +191,15 @@ proc notFullBuckets(r: RoutingTable): seq[KBucket] =
|
|||
proc neighbours*(r: RoutingTable, id: NodeId, k: int = BUCKET_SIZE): seq[Node] =
|
||||
## Return up to k neighbours of the given node.
|
||||
result = newSeqOfCap[Node](k * 2)
|
||||
for bucket in r.bucketsByDistanceTo(id):
|
||||
for n in bucket.nodesByDistanceTo(id):
|
||||
result.add(n)
|
||||
if result.len == k * 2:
|
||||
break
|
||||
block addNodes:
|
||||
for bucket in r.bucketsByDistanceTo(id):
|
||||
for n in bucket.nodesByDistanceTo(id):
|
||||
result.add(n)
|
||||
if result.len == k * 2:
|
||||
break addNodes
|
||||
|
||||
# TODO: is this sort still needed? Can we get nodes closer from the "next"
|
||||
# bucket?
|
||||
result = sortedByIt(result, it.distanceTo(id))
|
||||
if result.len > k:
|
||||
result.setLen(k)
|
||||
|
@ -209,9 +212,12 @@ proc idAtDistance*(id: NodeId, dist: uint32): NodeId =
|
|||
# zeroes and xor those` with the id.
|
||||
id xor (1.stuint(256) shl (dist.int - 1))
|
||||
|
||||
proc neighboursAtDistance*(r: RoutingTable, distance: uint32, k: int = BUCKET_SIZE): seq[Node] =
|
||||
# TODO: Filter out nodes with not exact distance here?
|
||||
r.neighbours(idAtDistance(r.thisNode.id, distance), k)
|
||||
proc neighboursAtDistance*(r: RoutingTable, distance: uint32,
|
||||
k: int = BUCKET_SIZE): seq[Node] =
|
||||
result = r.neighbours(idAtDistance(r.thisNode.id, distance), k)
|
||||
# This is a bit silly, first getting closest nodes then to only keep the ones
|
||||
# that are exactly the requested distance.
|
||||
keepIf(result, proc(n: Node): bool = logDist(n.id, r.thisNode.id) == distance)
|
||||
|
||||
proc len*(r: RoutingTable): int =
|
||||
for b in r.buckets: result += b.len
|
||||
|
|
|
@ -32,108 +32,33 @@ proc randomPacket(tag: PacketTag): seq[byte] =
|
|||
result.add(rlp.encode(authTag))
|
||||
result.add(msg)
|
||||
|
||||
proc generateNode(privKey = PrivateKey.random()[], port: int): Node =
|
||||
proc generateNode(privKey = PrivateKey.random()[], port: int = 20302): Node =
|
||||
let port = Port(port)
|
||||
let enr = enr.Record.init(1, privKey, some(parseIpAddress("127.0.0.1")),
|
||||
port, port)
|
||||
result = newNode(enr)
|
||||
|
||||
proc nodeAtDistance(n: Node, d: uint32): Node =
|
||||
while true:
|
||||
let node = generateNode()
|
||||
if logDist(n.id, node.id) == d:
|
||||
return node
|
||||
|
||||
proc nodesAtDistance(n: Node, d: uint32, amount: int): seq[Node] =
|
||||
for i in 0..<amount:
|
||||
result.add(nodeAtDistance(n, d))
|
||||
|
||||
suite "Discovery v5 Tests":
|
||||
asyncTest "Random nodes":
|
||||
let
|
||||
bootNodeKey = PrivateKey.fromHex(
|
||||
"a2b50376a79b1a8c8a3296485572bdfbf54708bb46d3c25d73d2723aaaf6a617")[]
|
||||
bootNode = initDiscoveryNode(bootNodeKey, localAddress(20301))
|
||||
|
||||
let nodeKeys = [
|
||||
PrivateKey.fromHex(
|
||||
"a2b50376a79b1a8c8a3296485572bdfbf54708bb46d3c25d73d2723aaaf6a618")[],
|
||||
PrivateKey.fromHex(
|
||||
"a2b50376a79b1a8c8a3296485572bdfbf54708bb46d3c25d73d2723aaaf6a619")[],
|
||||
PrivateKey.fromHex(
|
||||
"a2b50376a79b1a8c8a3296485572bdfbf54708bb46d3c25d73d2723aaaf6a620")[]
|
||||
]
|
||||
var nodeAddrs = newSeqOfCap[Address](nodeKeys.len)
|
||||
for i in 0 ..< nodeKeys.len: nodeAddrs.add(localAddress(20302 + i))
|
||||
|
||||
var nodes = zip(nodeKeys, nodeAddrs).mapIt(
|
||||
initDiscoveryNode(it[0], it[1], @[bootNode.localNode.record]))
|
||||
nodes.add(bootNode)
|
||||
|
||||
for node in nodes:
|
||||
let discovered = await node.lookupRandom()
|
||||
check discovered.len < nodes.len
|
||||
debug "Lookup from random id", node = node.localNode, discovered
|
||||
|
||||
# Check for each node if the other nodes shows up in the routing table
|
||||
for i in nodes:
|
||||
for j in nodes:
|
||||
if j != i:
|
||||
check(nodeIdInNodes(i.localNode.id, j.randomNodes(nodes.len - 1)))
|
||||
|
||||
for node in nodes:
|
||||
await node.closeWait()
|
||||
|
||||
asyncTest "Lookup targets":
|
||||
const
|
||||
nodeCount = 17
|
||||
|
||||
let bootNode = initDiscoveryNode(PrivateKey.random()[], localAddress(20301))
|
||||
bootNode.start()
|
||||
|
||||
var nodes = newSeqOfCap[discv5_protocol.Protocol](nodeCount)
|
||||
nodes.add(bootNode)
|
||||
for i in 1 ..< nodeCount:
|
||||
nodes.add(initDiscoveryNode(PrivateKey.random()[], localAddress(20301 + i),
|
||||
@[bootNode.localNode.record]))
|
||||
nodes[i].start()
|
||||
|
||||
for i in 0..<nodeCount-1:
|
||||
let target = nodes[i]
|
||||
let discovered = await nodes[nodeCount-1].lookup(target.localNode.id)
|
||||
debug "Lookup result", target = target.localNode, discovered
|
||||
# if lookUp would return ordered on distance we could check discovered[0]
|
||||
check discovered.contains(target.localNode)
|
||||
|
||||
for node in nodes:
|
||||
await node.closeWait()
|
||||
|
||||
asyncTest "FindNode with test table":
|
||||
|
||||
let mainNode = initDiscoveryNode(PrivateKey.random()[], localAddress(20301))
|
||||
|
||||
# Generate 1000 random nodes and add to our main node's routing table
|
||||
for i in 0..<1000:
|
||||
mainNode.addNode(generateNode(port = 20302 + i))
|
||||
|
||||
let
|
||||
neighbours = mainNode.neighbours(mainNode.localNode.id)
|
||||
closest = neighbours[0]
|
||||
closestDistance = logDist(closest.id, mainNode.localNode.id)
|
||||
|
||||
debug "Closest neighbour", closestDistance, id=closest.id.toHex()
|
||||
|
||||
let
|
||||
testNode = initDiscoveryNode(PrivateKey.random()[], localAddress(20302),
|
||||
@[mainNode.localNode.record])
|
||||
discovered = await discv5_protocol.findNode(testNode, mainNode.localNode,
|
||||
closestDistance)
|
||||
|
||||
check closest in discovered
|
||||
|
||||
await mainNode.closeWait()
|
||||
await testNode.closeWait()
|
||||
|
||||
asyncTest "GetNode":
|
||||
# TODO: This could be tested in just a routing table only context
|
||||
let
|
||||
node = initDiscoveryNode(PrivateKey.random()[], localAddress(20302))
|
||||
targetNode = generateNode(port = 20303)
|
||||
targetNode = generateNode()
|
||||
|
||||
node.addNode(targetNode)
|
||||
|
||||
for i in 0..<1000:
|
||||
node.addNode(generateNode(port = 20303 + i))
|
||||
node.addNode(generateNode())
|
||||
|
||||
check node.getNode(targetNode.id) == targetNode
|
||||
|
||||
|
@ -282,3 +207,106 @@ suite "Discovery v5 Tests":
|
|||
|
||||
for (id, d) in testValues:
|
||||
check idAtDistance(targetId, d) == parse(id, UInt256, 16)
|
||||
|
||||
asyncTest "FindNode Test":
|
||||
const dist = 253
|
||||
let
|
||||
mainNodeKey = PrivateKey.fromHex(
|
||||
"a2b50376a79b1a8c8a3296485572bdfbf54708bb46d3c25d73d2723aaaf6a617")[]
|
||||
testNodeKey = PrivateKey.fromHex(
|
||||
"a2b50376a79b1a8c8a3296485572bdfbf54708bb46d3c25d73d2723aaaf6a618")[]
|
||||
mainNode = initDiscoveryNode(mainNodeKey, localAddress(20301))
|
||||
testNode = initDiscoveryNode(testNodeKey, localAddress(20302))
|
||||
# logarithmic distance between mainNode and testNode is 256
|
||||
|
||||
let nodes = nodesAtDistance(mainNode.localNode, dist, 10)
|
||||
for n in nodes:
|
||||
mainNode.addNode(n)
|
||||
|
||||
# Get ENR of the node itself
|
||||
var discovered =
|
||||
await discv5_protocol.findNode(testNode, mainNode.localNode, 0)
|
||||
check:
|
||||
discovered.len == 1
|
||||
discovered[0] == mainNode.localNode
|
||||
|
||||
# Get ENRs of nodes added at provided logarithmic distance
|
||||
discovered =
|
||||
await discv5_protocol.findNode(testNode, mainNode.localNode, dist)
|
||||
check discovered.len == 10
|
||||
for n in nodes:
|
||||
check discovered.contains(n)
|
||||
|
||||
# Too high logarithmic distance, caps at 256
|
||||
discovered =
|
||||
await discv5_protocol.findNode(testNode, mainNode.localNode, 4294967295'u32)
|
||||
check:
|
||||
discovered.len == 1
|
||||
discovered[0] == testNode.localNode
|
||||
|
||||
# Empty bucket
|
||||
discovered =
|
||||
await discv5_protocol.findNode(testNode, mainNode.localNode, 254)
|
||||
check discovered.len == 0
|
||||
|
||||
let moreNodes = nodesAtDistance(mainNode.localNode, dist, 10)
|
||||
for n in moreNodes:
|
||||
mainNode.addNode(n)
|
||||
|
||||
# Full bucket
|
||||
discovered =
|
||||
await discv5_protocol.findNode(testNode, mainNode.localNode, dist)
|
||||
check discovered.len == 16
|
||||
|
||||
await mainNode.closeWait()
|
||||
await testNode.closeWait()
|
||||
|
||||
asyncTest "FindNode with test table":
|
||||
|
||||
let mainNode = initDiscoveryNode(PrivateKey.random()[], localAddress(20301))
|
||||
|
||||
# Generate 1000 random nodes and add to our main node's routing table
|
||||
for i in 0..<1000:
|
||||
mainNode.addNode(generateNode())
|
||||
|
||||
let
|
||||
neighbours = mainNode.neighbours(mainNode.localNode.id)
|
||||
closest = neighbours[0]
|
||||
closestDistance = logDist(closest.id, mainNode.localNode.id)
|
||||
|
||||
debug "Closest neighbour", closestDistance, id=closest.id.toHex()
|
||||
|
||||
let
|
||||
testNode = initDiscoveryNode(PrivateKey.random()[], localAddress(20302),
|
||||
@[mainNode.localNode.record])
|
||||
discovered = await discv5_protocol.findNode(testNode, mainNode.localNode,
|
||||
closestDistance)
|
||||
|
||||
check closest in discovered
|
||||
|
||||
await mainNode.closeWait()
|
||||
await testNode.closeWait()
|
||||
|
||||
asyncTest "Lookup targets":
|
||||
const
|
||||
nodeCount = 17
|
||||
|
||||
let bootNode = initDiscoveryNode(PrivateKey.random()[], localAddress(20301))
|
||||
bootNode.start()
|
||||
|
||||
var nodes = newSeqOfCap[discv5_protocol.Protocol](nodeCount)
|
||||
nodes.add(bootNode)
|
||||
for i in 1 ..< nodeCount:
|
||||
nodes.add(initDiscoveryNode(PrivateKey.random()[], localAddress(20301 + i),
|
||||
@[bootNode.localNode.record]))
|
||||
nodes[i].start()
|
||||
|
||||
for i in 0..<nodeCount-1:
|
||||
let target = nodes[i]
|
||||
let discovered = await nodes[nodeCount-1].lookup(target.localNode.id)
|
||||
debug "Lookup result", target = target.localNode, discovered
|
||||
# if lookUp would return ordered on distance we could check discovered[0]
|
||||
check discovered.contains(target.localNode)
|
||||
|
||||
for node in nodes:
|
||||
await node.closeWait()
|
||||
|
|
Loading…
Reference in New Issue