mirror of https://github.com/status-im/nim-eth.git
Log distance to uint16 and add public neighbours calls (#371)
* Use uint16 instead of uint32 for discv5 log distance * Make neighboursAtDistances and neighbours calls available
This commit is contained in:
parent
41127eaee8
commit
79911ed5d8
|
@ -79,7 +79,7 @@ type
|
|||
distance* {.
|
||||
defaultValue: 255
|
||||
desc: "Distance parameter for the findNode message"
|
||||
name: "distance" .}: uint32
|
||||
name: "distance" .}: uint16
|
||||
# TODO: Order here matters as else the help message does not show all the
|
||||
# information, see: https://github.com/status-im/nim-confutils/issues/15
|
||||
findNodeTarget* {.
|
||||
|
|
|
@ -47,7 +47,7 @@ type
|
|||
port*: uint16
|
||||
|
||||
FindNodeMessage* = object
|
||||
distances*: seq[uint32]
|
||||
distances*: seq[uint16]
|
||||
|
||||
NodesMessage* = object
|
||||
total*: uint32
|
||||
|
|
|
@ -31,6 +31,8 @@ type
|
|||
|
||||
func toNodeId*(pk: PublicKey): NodeId =
|
||||
## Convert public key to a node identifier.
|
||||
# Keccak256 hash is used as defined in ENR spec for scheme v4:
|
||||
# https://github.com/ethereum/devp2p/blob/master/enr.md#v4-identity-scheme
|
||||
readUintBE[256](keccak256.digest(pk.toRaw()).data)
|
||||
|
||||
func newNode*(r: Record): Result[Node, cstring] =
|
||||
|
|
|
@ -197,9 +197,15 @@ proc randomNodes*(d: Protocol, maxAmount: int,
|
|||
## the nodes selected are filtered by provided `enrField`.
|
||||
d.randomNodes(maxAmount, proc(x: Node): bool = x.record.contains(enrField))
|
||||
|
||||
proc neighbours*(d: Protocol, id: NodeId, k: int = BUCKET_SIZE): seq[Node] =
|
||||
proc neighbours*(d: Protocol, id: NodeId, k: int = BUCKET_SIZE,
|
||||
seenOnly = false): seq[Node] =
|
||||
## Return up to k neighbours (closest node ids) of the given node id.
|
||||
d.routingTable.neighbours(id, k)
|
||||
d.routingTable.neighbours(id, k, seenOnly)
|
||||
|
||||
proc neighboursAtDistances*(d: Protocol, distances: seq[uint16],
|
||||
k: int = BUCKET_SIZE, seenOnly = false): seq[Node] =
|
||||
## Return up to k neighbours (closest node ids) at given distances.
|
||||
d.routingTable.neighboursAtDistances(distances, k, seenOnly)
|
||||
|
||||
proc nodesDiscovered*(d: Protocol): int = d.routingTable.len
|
||||
|
||||
|
@ -293,7 +299,7 @@ proc handleFindNode(d: Protocol, fromId: NodeId, fromAddr: Address,
|
|||
d.sendNodes(fromId, fromAddr, reqId, [d.localNode])
|
||||
else:
|
||||
# TODO: Still deduplicate also?
|
||||
if fn.distances.all(proc (x: uint32): bool = return x <= 256):
|
||||
if fn.distances.all(proc (x: uint16): bool = return x <= 256):
|
||||
d.sendNodes(fromId, fromAddr, reqId,
|
||||
d.routingTable.neighboursAtDistances(fn.distances, seenOnly = true))
|
||||
else:
|
||||
|
@ -491,7 +497,7 @@ proc waitMessage(d: Protocol, fromNode: Node, reqId: RequestId):
|
|||
d.awaitedMessages[key] = result
|
||||
|
||||
proc verifyNodesRecords*(enrs: openarray[Record], fromNode: Node,
|
||||
distances: varargs[uint32]): seq[Node] =
|
||||
distances: varargs[uint16]): seq[Node] =
|
||||
## Verify and convert ENRs to a sequence of nodes. Only ENRs that pass
|
||||
## verification will be added. ENRs are verified for duplicates, invalid
|
||||
## addresses and invalid distances.
|
||||
|
@ -609,7 +615,7 @@ proc ping*(d: Protocol, toNode: Node):
|
|||
discovery_message_requests_outgoing.inc(labelValues = ["no_response"])
|
||||
return err("Pong message not received in time")
|
||||
|
||||
proc findNode*(d: Protocol, toNode: Node, distances: seq[uint32]):
|
||||
proc findNode*(d: Protocol, toNode: Node, distances: seq[uint16]):
|
||||
Future[DiscResult[seq[Node]]] {.async.} =
|
||||
## Send a discovery findNode message.
|
||||
##
|
||||
|
@ -648,14 +654,14 @@ proc talkreq*(d: Protocol, toNode: Node, protocol, request: seq[byte]):
|
|||
discovery_message_requests_outgoing.inc(labelValues = ["no_response"])
|
||||
return err("Talk response message not received in time")
|
||||
|
||||
proc lookupDistances(target, dest: NodeId): seq[uint32] =
|
||||
proc lookupDistances(target, dest: NodeId): seq[uint16] =
|
||||
let td = logDist(target, dest)
|
||||
result.add(td)
|
||||
var i = 1'u32
|
||||
var i = 1'u16
|
||||
while result.len < lookupRequestLimit:
|
||||
if td + i < 256:
|
||||
result.add(td + i)
|
||||
if td - i > 0'u32:
|
||||
if td - i > 0'u16:
|
||||
result.add(td - i)
|
||||
inc i
|
||||
|
||||
|
@ -804,7 +810,7 @@ proc resolve*(d: Protocol, id: NodeId): Future[Option[Node]] {.async.} =
|
|||
|
||||
let node = d.getNode(id)
|
||||
if node.isSome():
|
||||
let request = await d.findNode(node.get(), @[0'u32])
|
||||
let request = await d.findNode(node.get(), @[0'u16])
|
||||
|
||||
# TODO: Handle failures better. E.g. stop on different failures than timeout
|
||||
if request.isOk() and request[].len > 0:
|
||||
|
@ -853,7 +859,7 @@ proc revalidateNode*(d: Protocol, n: Node) {.async.} =
|
|||
let res = pong.get()
|
||||
if res.enrSeq > n.record.seqNum:
|
||||
# Request new ENR
|
||||
let nodes = await d.findNode(n, @[0'u32])
|
||||
let nodes = await d.findNode(n, @[0'u16])
|
||||
if nodes.isOk() and nodes[].len > 0:
|
||||
discard d.addNode(nodes[][0])
|
||||
|
||||
|
|
|
@ -98,7 +98,7 @@ proc distanceTo*(n: Node, id: NodeId): UInt256 =
|
|||
## Calculate the distance to a NodeId.
|
||||
n.id xor id
|
||||
|
||||
proc logDist*(a, b: NodeId): uint32 =
|
||||
proc logDist*(a, b: NodeId): uint16 =
|
||||
## Calculate the logarithmic distance between two `NodeId`s.
|
||||
##
|
||||
## According the specification, this is the log base 2 of the distance. But it
|
||||
|
@ -115,7 +115,7 @@ proc logDist*(a, b: NodeId): uint32 =
|
|||
else:
|
||||
lz += bitops.countLeadingZeroBits(x)
|
||||
break
|
||||
return uint32(a.len * 8 - lz)
|
||||
return uint16(a.len * 8 - lz)
|
||||
|
||||
proc newKBucket(istart, iend: NodeId, bucketIpLimit: uint): KBucket =
|
||||
result.new()
|
||||
|
@ -421,7 +421,7 @@ proc neighbours*(r: RoutingTable, id: NodeId, k: int = BUCKET_SIZE,
|
|||
if result.len > k:
|
||||
result.setLen(k)
|
||||
|
||||
proc idAtDistance*(id: NodeId, dist: uint32): NodeId =
|
||||
proc idAtDistance*(id: NodeId, dist: uint16): NodeId =
|
||||
## Calculate the "lowest" `NodeId` for given logarithmic distance.
|
||||
## A logarithmic distance obviously covers a whole range of distances and thus
|
||||
## potential `NodeId`s.
|
||||
|
@ -429,7 +429,7 @@ 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,
|
||||
proc neighboursAtDistance*(r: RoutingTable, distance: uint16,
|
||||
k: int = BUCKET_SIZE, seenOnly = false): seq[Node] =
|
||||
## Return up to k neighbours at given logarithmic distance.
|
||||
result = r.neighbours(idAtDistance(r.thisNode.id, distance), k, seenOnly)
|
||||
|
@ -437,7 +437,7 @@ proc neighboursAtDistance*(r: RoutingTable, distance: uint32,
|
|||
# that are exactly the requested distance.
|
||||
keepIf(result, proc(n: Node): bool = logDist(n.id, r.thisNode.id) == distance)
|
||||
|
||||
proc neighboursAtDistances*(r: RoutingTable, distances: seq[uint32],
|
||||
proc neighboursAtDistances*(r: RoutingTable, distances: seq[uint16],
|
||||
k: int = BUCKET_SIZE, seenOnly = false): seq[Node] =
|
||||
## Return up to k neighbours at given logarithmic distances.
|
||||
# TODO: This will currently return nodes with neighbouring distances on the
|
||||
|
|
|
@ -62,19 +62,19 @@ procSuite "Discovery v5 Tests":
|
|||
const
|
||||
targetId = "0x0000"
|
||||
testValues = [
|
||||
("0x0001", 1'u32),
|
||||
("0x0002", 2'u32),
|
||||
("0x0003", 2'u32),
|
||||
("0x0004", 3'u32),
|
||||
("0x0007", 3'u32),
|
||||
("0x0008", 4'u32),
|
||||
("0x000f", 4'u32),
|
||||
("0x0080", 8'u32),
|
||||
("0x00ff", 8'u32),
|
||||
("0x0100", 9'u32),
|
||||
("0x01ff", 9'u32),
|
||||
("0x8000", 16'u32),
|
||||
("0xffff", 16'u32)
|
||||
("0x0001", 1'u16),
|
||||
("0x0002", 2'u16),
|
||||
("0x0003", 2'u16),
|
||||
("0x0004", 3'u16),
|
||||
("0x0007", 3'u16),
|
||||
("0x0008", 4'u16),
|
||||
("0x000f", 4'u16),
|
||||
("0x0080", 8'u16),
|
||||
("0x00ff", 8'u16),
|
||||
("0x0100", 9'u16),
|
||||
("0x01ff", 9'u16),
|
||||
("0x8000", 16'u16),
|
||||
("0xffff", 16'u16)
|
||||
]
|
||||
|
||||
for (id, d) in testValues:
|
||||
|
@ -84,12 +84,12 @@ procSuite "Discovery v5 Tests":
|
|||
const
|
||||
targetKey = "5d485bdcbe9bc89314a10ae9231e429d33853e3a8fa2af39f5f827370a2e4185e344ace5d16237491dad41f278f1d3785210d29ace76cd627b9147ee340b1125"
|
||||
testValues = [
|
||||
("29738ba0c1a4397d6a65f292eee07f02df8e58d41594ba2be3cf84ce0fc58169", 251'u32),
|
||||
("1c9b1cafbec00848d2c174b858219914b42a7d5c9359b1ca03fd650e8239ae94", 252'u32),
|
||||
("2d0511ae9bf590166597eeab86b6f27b1ab761761eaea8965487b162f8703847", 253'u32),
|
||||
("dec742079ec00ff4ec1284d7905bc3de2366f67a0769431fd16f80fd68c58a7c", 254'u32),
|
||||
("da8645f90826e57228d9ea72aff84500060ad111a5d62e4af831ed8e4b5acfb8", 255'u32),
|
||||
("8c5b422155d33ea8e9d46f71d1ad3e7b24cb40051413ffa1a81cff613d243ba9", 256'u32)
|
||||
("29738ba0c1a4397d6a65f292eee07f02df8e58d41594ba2be3cf84ce0fc58169", 251'u16),
|
||||
("1c9b1cafbec00848d2c174b858219914b42a7d5c9359b1ca03fd650e8239ae94", 252'u16),
|
||||
("2d0511ae9bf590166597eeab86b6f27b1ab761761eaea8965487b162f8703847", 253'u16),
|
||||
("dec742079ec00ff4ec1284d7905bc3de2366f67a0769431fd16f80fd68c58a7c", 254'u16),
|
||||
("da8645f90826e57228d9ea72aff84500060ad111a5d62e4af831ed8e4b5acfb8", 255'u16),
|
||||
("8c5b422155d33ea8e9d46f71d1ad3e7b24cb40051413ffa1a81cff613d243ba9", 256'u16)
|
||||
]
|
||||
|
||||
let targetId = toNodeId(PublicKey.fromHex(targetKey)[])
|
||||
|
@ -102,13 +102,13 @@ procSuite "Discovery v5 Tests":
|
|||
const
|
||||
targetId = "0x0000"
|
||||
testValues = [ # possible id in that distance range
|
||||
("0x0001", 1'u32),
|
||||
("0x0002", 2'u32),
|
||||
("0x0004", 3'u32),
|
||||
("0x0008", 4'u32),
|
||||
("0x0080", 8'u32),
|
||||
("0x0100", 9'u32),
|
||||
("0x8000", 16'u32)
|
||||
("0x0001", 1'u16),
|
||||
("0x0002", 2'u16),
|
||||
("0x0004", 3'u16),
|
||||
("0x0008", 4'u16),
|
||||
("0x0080", 8'u16),
|
||||
("0x0100", 9'u16),
|
||||
("0x8000", 16'u16)
|
||||
]
|
||||
|
||||
for (id, d) in testValues:
|
||||
|
@ -118,12 +118,12 @@ procSuite "Discovery v5 Tests":
|
|||
const
|
||||
targetKey = "5d485bdcbe9bc89314a10ae9231e429d33853e3a8fa2af39f5f827370a2e4185e344ace5d16237491dad41f278f1d3785210d29ace76cd627b9147ee340b1125"
|
||||
testValues = [ # possible id in that distance range
|
||||
("9e5b34809116e3790b2258a45e7ef03b11af786503fb1a6d4b4a8ca021ad653c", 251'u32),
|
||||
("925b34809116e3790b2258a45e7ef03b11af786503fb1a6d4b4a8ca021ad653c", 252'u32),
|
||||
("8a5b34809116e3790b2258a45e7ef03b11af786503fb1a6d4b4a8ca021ad653c", 253'u32),
|
||||
("ba5b34809116e3790b2258a45e7ef03b11af786503fb1a6d4b4a8ca021ad653c", 254'u32),
|
||||
("da5b34809116e3790b2258a45e7ef03b11af786503fb1a6d4b4a8ca021ad653c", 255'u32),
|
||||
("1a5b34809116e3790b2258a45e7ef03b11af786503fb1a6d4b4a8ca021ad653c", 256'u32)
|
||||
("9e5b34809116e3790b2258a45e7ef03b11af786503fb1a6d4b4a8ca021ad653c", 251'u16),
|
||||
("925b34809116e3790b2258a45e7ef03b11af786503fb1a6d4b4a8ca021ad653c", 252'u16),
|
||||
("8a5b34809116e3790b2258a45e7ef03b11af786503fb1a6d4b4a8ca021ad653c", 253'u16),
|
||||
("ba5b34809116e3790b2258a45e7ef03b11af786503fb1a6d4b4a8ca021ad653c", 254'u16),
|
||||
("da5b34809116e3790b2258a45e7ef03b11af786503fb1a6d4b4a8ca021ad653c", 255'u16),
|
||||
("1a5b34809116e3790b2258a45e7ef03b11af786503fb1a6d4b4a8ca021ad653c", 256'u16)
|
||||
]
|
||||
|
||||
let targetId = toNodeId(PublicKey.fromHex(targetKey)[])
|
||||
|
@ -132,7 +132,7 @@ procSuite "Discovery v5 Tests":
|
|||
check idAtDistance(targetId, d) == parse(id, UInt256, 16)
|
||||
|
||||
asyncTest "FindNode Test":
|
||||
const dist = 253'u32
|
||||
const dist = 253'u16
|
||||
let
|
||||
mainNodeKey = PrivateKey.fromHex(
|
||||
"a2b50376a79b1a8c8a3296485572bdfbf54708bb46d3c25d73d2723aaaf6a617")[]
|
||||
|
@ -152,7 +152,7 @@ procSuite "Discovery v5 Tests":
|
|||
|
||||
# Get ENR of the node itself
|
||||
var discovered =
|
||||
await findNode(testNode, mainNode.localNode, @[0'u32])
|
||||
await findNode(testNode, mainNode.localNode, @[0'u16])
|
||||
check:
|
||||
discovered.isOk
|
||||
discovered[].len == 1
|
||||
|
@ -167,14 +167,14 @@ procSuite "Discovery v5 Tests":
|
|||
|
||||
# Too high logarithmic distance, should return no nodes.
|
||||
discovered =
|
||||
await findNode(testNode, mainNode.localNode, @[4294967295'u32])
|
||||
await findNode(testNode, mainNode.localNode, @[high(uint16)])
|
||||
check:
|
||||
discovered.isOk
|
||||
discovered[].len == 0
|
||||
|
||||
# Logarithmic distance of 256 should only return the testNode
|
||||
discovered =
|
||||
await findNode(testNode, mainNode.localNode, @[256'u32])
|
||||
await findNode(testNode, mainNode.localNode, @[256'u16])
|
||||
check:
|
||||
discovered.isOk
|
||||
discovered[].len == 1
|
||||
|
@ -182,7 +182,7 @@ procSuite "Discovery v5 Tests":
|
|||
|
||||
# Empty bucket
|
||||
discovered =
|
||||
await findNode(testNode, mainNode.localNode, @[254'u32])
|
||||
await findNode(testNode, mainNode.localNode, @[254'u16])
|
||||
check discovered.isOk
|
||||
check discovered[].len == 0
|
||||
|
||||
|
@ -297,7 +297,7 @@ procSuite "Discovery v5 Tests":
|
|||
# Request the target ENR and manually add it to the routing table.
|
||||
# Ping for handshake based ENR passing will not work as our previous
|
||||
# session will still be in the LRU cache.
|
||||
let nodes = await mainNode.findNode(targetNode.localNode, @[0'u32])
|
||||
let nodes = await mainNode.findNode(targetNode.localNode, @[0'u16])
|
||||
check:
|
||||
nodes.isOk()
|
||||
nodes[].len == 1
|
||||
|
@ -524,7 +524,7 @@ procSuite "Discovery v5 Tests":
|
|||
1, pk, some(ValidIpAddress.init("12.13.14.15")),
|
||||
some(port), some(port))[]
|
||||
records = [recordInvalidDistance]
|
||||
test = verifyNodesRecords(records, fromNode, 0'u32)
|
||||
test = verifyNodesRecords(records, fromNode, 0'u16)
|
||||
check test.len == 0
|
||||
|
||||
asyncTest "Handshake cleanup: different ids":
|
||||
|
|
|
@ -51,7 +51,7 @@ suite "Discovery v5.1 Protocol Message Encodings":
|
|||
|
||||
test "FindNode Request":
|
||||
let
|
||||
distances = @[0x0100'u32]
|
||||
distances = @[0x0100'u16]
|
||||
fn = FindNodeMessage(distances: distances)
|
||||
reqId = RequestId(id: @[1.byte])
|
||||
|
||||
|
|
Loading…
Reference in New Issue