Add resolve proc + test

This commit is contained in:
kdeme 2020-04-20 13:50:22 +02:00
parent d3c9ccea67
commit 59ba3704d6
3 changed files with 102 additions and 11 deletions

View File

@ -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

View File

@ -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)

View File

@ -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()