mirror of https://github.com/status-im/nim-eth.git
Add resolve proc + test
This commit is contained in:
parent
d3c9ccea67
commit
59ba3704d6
|
@ -61,7 +61,7 @@ proc addNode*(d: Protocol, enr: EnrUri) =
|
||||||
doAssert(res)
|
doAssert(res)
|
||||||
d.addNode newNode(r)
|
d.addNode newNode(r)
|
||||||
|
|
||||||
proc getNode*(d: Protocol, id: NodeId): Node =
|
proc getNode*(d: Protocol, id: NodeId): Option[Node] =
|
||||||
d.routingTable.getNode(id)
|
d.routingTable.getNode(id)
|
||||||
|
|
||||||
proc randomNodes*(d: Protocol, count: int): seq[Node] =
|
proc randomNodes*(d: Protocol, count: int): seq[Node] =
|
||||||
|
@ -213,9 +213,7 @@ proc receive*(d: Protocol, a: Address, msg: openArray[byte]) {.gcsafe,
|
||||||
var packet: Packet
|
var packet: Packet
|
||||||
let decoded = d.codec.decodeEncrypted(sender, a, msg, authTag, node, packet)
|
let decoded = d.codec.decodeEncrypted(sender, a, msg, authTag, node, packet)
|
||||||
if decoded == DecodeStatus.Success:
|
if decoded == DecodeStatus.Success:
|
||||||
if node.isNil:
|
if not node.isNil:
|
||||||
node = d.routingTable.getNode(sender)
|
|
||||||
else:
|
|
||||||
# Not filling table with nodes without correct IP in the ENR
|
# Not filling table with nodes without correct IP in the ENR
|
||||||
if a.ip == node.address.ip:
|
if a.ip == node.address.ip:
|
||||||
debug "Adding new node to routing table", node = $node,
|
debug "Adding new node to routing table", node = $node,
|
||||||
|
@ -232,7 +230,7 @@ proc receive*(d: Protocol, a: Address, msg: openArray[byte]) {.gcsafe,
|
||||||
if d.awaitedPackets.take((sender, packet.reqId), waiter):
|
if d.awaitedPackets.take((sender, packet.reqId), waiter):
|
||||||
waiter.complete(packet.some)
|
waiter.complete(packet.some)
|
||||||
else:
|
else:
|
||||||
debug "TODO: handle packet: ", packet = packet.kind, origin = $node
|
debug "TODO: handle packet: ", packet = packet.kind, origin = a
|
||||||
elif decoded == DecodeStatus.DecryptError:
|
elif decoded == DecodeStatus.DecryptError:
|
||||||
debug "Could not decrypt packet, respond with whoareyou",
|
debug "Could not decrypt packet, respond with whoareyou",
|
||||||
localNode = $d.localNode, address = a
|
localNode = $d.localNode, address = a
|
||||||
|
@ -418,6 +416,31 @@ proc lookupRandom*(d: Protocol): Future[seq[Node]]
|
||||||
raise newException(RandomSourceDepleted, "Could not randomize bytes")
|
raise newException(RandomSourceDepleted, "Could not randomize bytes")
|
||||||
d.lookup(id)
|
d.lookup(id)
|
||||||
|
|
||||||
|
proc resolve*(d: Protocol, id: NodeId): Future[Option[Node]] {.async.} =
|
||||||
|
## Resolve a `Node` based on provided `NodeId`.
|
||||||
|
##
|
||||||
|
## This will first look in the own DHT. If the node is known, it will try to
|
||||||
|
## contact if for newer information. If node is not known or it does not
|
||||||
|
## reply, a lookup is done to see if it can find a (newer) record of the node
|
||||||
|
## on the network.
|
||||||
|
|
||||||
|
let node = d.getNode(id)
|
||||||
|
if node.isSome():
|
||||||
|
let request = await d.findNode(node.get(), 0)
|
||||||
|
|
||||||
|
if request.len > 0:
|
||||||
|
return some(request[0])
|
||||||
|
|
||||||
|
let discovered = await d.lookup(id)
|
||||||
|
for n in discovered:
|
||||||
|
if n.id == id:
|
||||||
|
# TODO: Not getting any new seqNum here as in a lookup nodes in table with
|
||||||
|
# new seqNum don't get replaced.
|
||||||
|
if node.isSome() and node.get().record.seqNum >= n.record.seqNum:
|
||||||
|
return node
|
||||||
|
else:
|
||||||
|
return some(n)
|
||||||
|
|
||||||
proc revalidateNode*(d: Protocol, n: Node)
|
proc revalidateNode*(d: Protocol, n: Node)
|
||||||
{.async, raises:[Defect, Exception].} = # TODO: Exception
|
{.async, raises:[Defect, Exception].} = # TODO: Exception
|
||||||
trace "Ping to revalidate node", node = $n
|
trace "Ping to revalidate node", node = $n
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import
|
import
|
||||||
std/[algorithm, times, sequtils, bitops, random, sets], stint, chronicles,
|
std/[algorithm, times, sequtils, bitops, random, sets, options],
|
||||||
|
stint, chronicles,
|
||||||
types, node
|
types, node
|
||||||
|
|
||||||
type
|
type
|
||||||
|
@ -174,11 +175,11 @@ proc addNode*(r: var RoutingTable, n: Node): Node =
|
||||||
# Nothing added, ping evictionCandidate
|
# Nothing added, ping evictionCandidate
|
||||||
return evictionCandidate
|
return evictionCandidate
|
||||||
|
|
||||||
proc getNode*(r: RoutingTable, id: NodeId): Node =
|
proc getNode*(r: RoutingTable, id: NodeId): Option[Node] =
|
||||||
let b = r.bucketForNode(id)
|
let b = r.bucketForNode(id)
|
||||||
for n in b.nodes:
|
for n in b.nodes:
|
||||||
if n.id == id:
|
if n.id == id:
|
||||||
return n
|
return some(n)
|
||||||
|
|
||||||
proc contains*(r: RoutingTable, n: Node): bool = n in r.bucketForNode(n.id)
|
proc contains*(r: RoutingTable, n: Node): bool = n in r.bucketForNode(n.id)
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,9 @@ suite "Discovery v5 Tests":
|
||||||
for i in 0..<1000:
|
for i in 0..<1000:
|
||||||
node.addNode(generateNode())
|
node.addNode(generateNode())
|
||||||
|
|
||||||
check node.getNode(targetNode.id) == targetNode
|
let n = node.getNode(targetNode.id)
|
||||||
|
require n.isSome()
|
||||||
|
check n.get() == targetNode
|
||||||
|
|
||||||
await node.closeWait()
|
await node.closeWait()
|
||||||
|
|
||||||
|
@ -82,8 +84,10 @@ suite "Discovery v5 Tests":
|
||||||
await node1.revalidateNode(bootnode.localNode)
|
await node1.revalidateNode(bootnode.localNode)
|
||||||
await node1.revalidateNode(node2.localNode)
|
await node1.revalidateNode(node2.localNode)
|
||||||
|
|
||||||
check node1.getNode(bootnode.localNode.id) == bootnode.localNode
|
let n = node1.getNode(bootnode.localNode.id)
|
||||||
check node1.getNode(node2.localNode.id) == nil
|
require n.isSome()
|
||||||
|
check n.get() == bootnode.localNode
|
||||||
|
check node1.getNode(node2.localNode.id).isNone()
|
||||||
|
|
||||||
await node1.closeWait()
|
await node1.closeWait()
|
||||||
|
|
||||||
|
@ -310,3 +314,66 @@ suite "Discovery v5 Tests":
|
||||||
|
|
||||||
for node in nodes:
|
for node in nodes:
|
||||||
await node.closeWait()
|
await node.closeWait()
|
||||||
|
|
||||||
|
asyncTest "Resolve target":
|
||||||
|
let
|
||||||
|
mainNode = initDiscoveryNode(PrivateKey.random()[], localAddress(20301))
|
||||||
|
lookupNode = initDiscoveryNode(PrivateKey.random()[], localAddress(20302))
|
||||||
|
targetKey = PrivateKey.random()[]
|
||||||
|
targetAddress = localAddress(20303)
|
||||||
|
targetNode = initDiscoveryNode(targetKey, targetAddress)
|
||||||
|
targetId = targetNode.localNode.id
|
||||||
|
|
||||||
|
var targetSeqNum = targetNode.localNode.record.seqNum
|
||||||
|
|
||||||
|
# Populate DHT with target through a ping. Next, close target and see
|
||||||
|
# if resolve works (only local lookup)
|
||||||
|
block:
|
||||||
|
let pong = await targetNode.ping(mainNode.localNode)
|
||||||
|
require pong.isSome()
|
||||||
|
await targetNode.closeWait()
|
||||||
|
let n = await mainNode.resolve(targetId)
|
||||||
|
require n.isSome()
|
||||||
|
check:
|
||||||
|
n.get().id == targetId
|
||||||
|
n.get().record.seqNum == targetSeqNum
|
||||||
|
|
||||||
|
# Bring target back online, update seqNum in ENR, check if we get the
|
||||||
|
# updated ENR.
|
||||||
|
block:
|
||||||
|
# TODO: need to add some logic to update ENRs properly
|
||||||
|
targetSeqNum.inc()
|
||||||
|
let r = enr.Record.init(targetSeqNum, targetKey,
|
||||||
|
some(targetAddress.ip), targetAddress.tcpPort, targetAddress.udpPort)
|
||||||
|
targetNode.localNode.record = r
|
||||||
|
targetNode.open()
|
||||||
|
let n = await mainNode.resolve(targetId)
|
||||||
|
require n.isSome()
|
||||||
|
check:
|
||||||
|
n.get().id == targetId
|
||||||
|
n.get().record.seqNum == targetSeqNum
|
||||||
|
|
||||||
|
# Update seqNum in ENR again, ping lookupNode to be added in DHT,
|
||||||
|
# close targetNode, resolve should lookup, check if we get updated ENR.
|
||||||
|
block:
|
||||||
|
targetSeqNum.inc()
|
||||||
|
let r = enr.Record.init(3, targetKey, some(targetAddress.ip),
|
||||||
|
targetAddress.tcpPort, targetAddress.udpPort)
|
||||||
|
targetNode.localNode.record = r
|
||||||
|
let pong = await targetNode.ping(lookupNode.localNode)
|
||||||
|
require pong.isSome()
|
||||||
|
|
||||||
|
await targetNode.closeWait()
|
||||||
|
# TODO: This step should eventually not be needed and ENRs with new seqNum
|
||||||
|
# should just get updated in the lookup.
|
||||||
|
await mainNode.revalidateNode(targetNode.localNode)
|
||||||
|
|
||||||
|
mainNode.addNode(lookupNode.localNode.record)
|
||||||
|
let n = await mainNode.resolve(targetId)
|
||||||
|
require n.isSome()
|
||||||
|
check:
|
||||||
|
n.get().id == targetId
|
||||||
|
n.get().record.seqNum == targetSeqNum
|
||||||
|
|
||||||
|
await mainNode.closeWait()
|
||||||
|
await lookupNode.closeWait()
|
||||||
|
|
Loading…
Reference in New Issue