discv5: Pass bootstrap nodes and add deletion of nodes

This commit is contained in:
kdeme 2020-03-13 17:48:03 +01:00 committed by zah
parent 2b7a25175b
commit 267a06dbe6
4 changed files with 55 additions and 30 deletions

View File

@ -241,6 +241,9 @@ proc decodeAuthResp(c: Codec, fromId: NodeId, head: AuthHeader,
# 2. Should verify ENR and check for correct id in case an ENR is included
# 3. Should verify id nonce signature
# More TODO:
# This will also not work if ENR does not contain an IP address or if the
# IP address is out of date and doesn't match current UDP end point
newNode = newNode(authResp.record)
return true

View File

@ -44,6 +44,10 @@ proc newNode*(r: Record): Node =
result = newNode(initENode(pk, a))
result.record = r
proc newNodes*(records: openarray[Record]): seq[Node] =
for record in records:
result.add(newNode(record))
proc hash*(n: Node): hashes.Hash = hash(n.node.pubkey.data)
proc `==`*(a, b: Node): bool = (a.isNil and b.isNil) or (not a.isNil and not b.isNil and a.node.pubkey == b.node.pubkey)

View File

@ -38,11 +38,32 @@ type
awaitedPackets: Table[(Node, RequestId), Future[Option[Packet]]]
lookupLoop: Future[void]
revalidateLoop: Future[void]
bootstrapNodes: seq[Node]
PendingRequest = object
node: Node
packet: seq[byte]
proc addNode*(d: Protocol, node: Node) =
discard d.routingTable.addNode(node)
template addNode*(d: Protocol, enode: ENode) =
addNode d, newNode(enode)
template addNode*(d: Protocol, r: Record) =
addNode d, newNode(r)
proc addNode*(d: Protocol, enr: EnrUri) =
var r: Record
let res = r.fromUri(enr)
doAssert(res)
d.addNode newNode(r)
proc randomNodes*(k: Protocol, count: int): seq[Node] =
k.routingTable.randomNodes(count)
proc nodesDiscovered*(k: Protocol): int {.inline.} = k.routingTable.len
proc whoareyouMagic(toNode: NodeId): array[magicSize, byte] =
const prefix = "WHOAREYOU"
var data: array[prefix.len + sizeof(toNode), byte]
@ -51,7 +72,8 @@ proc whoareyouMagic(toNode: NodeId): array[magicSize, byte] =
sha256.digest(data).data
proc newProtocol*(privKey: PrivateKey, db: Database,
ip: IpAddress, tcpPort, udpPort: Port): Protocol =
ip: IpAddress, tcpPort, udpPort: Port,
bootstrapRecords: openarray[Record] = []): Protocol =
let
a = Address(ip: ip, tcpPort: tcpPort, udpPort: udpPort)
enode = initENode(privKey.getPublicKey(), a)
@ -64,7 +86,8 @@ proc newProtocol*(privKey: PrivateKey, db: Database,
localNode: node,
whoareyouMagic: whoareyouMagic(node.id),
idHash: sha256.digest(node.id.toByteArrayBE).data,
codec: Codec(localNode: node, privKey: privKey, db: db))
codec: Codec(localNode: node, privKey: privKey, db: db),
bootstrapNodes: newNodes(bootstrapRecords))
result.routingTable.init(node)
@ -355,6 +378,7 @@ proc ping(p: Protocol, toNode: Node): RequestId =
proc revalidateNode(p: Protocol, n: Node)
{.async, raises:[Defect, Exception].} = # TODO: Exception
trace "Ping to revalidate node", node = $n
let reqId = p.ping(n)
let resp = await p.waitPacket(n, reqId)
@ -367,8 +391,15 @@ proc revalidateNode(p: Protocol, n: Node)
p.routingTable.setJustSeen(n)
trace "Revalidated node", node = $n
else:
if false: # TODO: if not bootnode:
# For now we never remove bootstrap nodes. It might make sense to actually
# do so and to retry them only in case we drop to a really low amount of
# peers in the DHT
if n notin p.bootstrapNodes:
trace "Revalidation of node failed, removing node", node = $n
p.routingTable.removeNode(n)
# TODO: Do we delete the shared secrets here?
# And if so, the current way they are stored, we might not have the key
# (specifically if the ENR does not have the correct address)
proc revalidateLoop(p: Protocol) {.async.} =
try:
@ -389,8 +420,12 @@ proc lookupLoop(d: Protocol) {.async.} =
## TODO: Same story as for `revalidateLoop`
try:
while true:
let nodes = await d.lookupRandom()
trace "Discovered nodes", nodes = $nodes
# lookup self (neighbour nodes)
var nodes = await d.lookup(d.localNode.id)
trace "Discovered nodes in self lookup", nodes = $nodes
nodes = await d.lookupRandom()
trace "Discovered nodes in random lookup", nodes = $nodes
await sleepAsync(lookupInterval)
except CancelledError:
trace "lookupLoop canceled"
@ -401,6 +436,10 @@ proc open*(d: Protocol) =
# TODO allow binding to specific IP / IPv6 / etc
let ta = initTAddress(IPv4_any(), d.localNode.node.address.udpPort)
d.transp = newDatagramTransport(processClient, udata = d, local = ta)
for node in d.bootstrapNodes:
d.addNode(node)
# Might want to move these to a separate proc if this turns out to be needed.
d.lookupLoop = lookupLoop(d)
d.revalidateLoop = revalidateLoop(d)
@ -425,26 +464,6 @@ proc closeWait*(d: Protocol) {.async.} =
d.lookupLoop.cancelAndWait()])
await d.transp.closeWait()
proc addNode*(d: Protocol, node: Node) =
discard d.routingTable.addNode(node)
template addNode*(d: Protocol, enode: ENode) =
addNode d, newNode(enode)
template addNode*(d: Protocol, r: Record) =
addNode d, newNode(r)
proc addNode*(d: Protocol, enr: EnrUri) =
var r: Record
let res = r.fromUri(enr)
doAssert(res)
d.addNode newNode(r)
proc randomNodes*(k: Protocol, count: int): seq[Node] =
k.routingTable.randomNodes(count)
proc nodesDiscovered*(k: Protocol): int {.inline.} = k.routingTable.len
when isMainModule:
import discovery_db
import eth/trie/db

View File

@ -6,14 +6,13 @@ import
./p2p_test_helper
proc initDiscoveryNode*(privKey: PrivateKey, address: Address,
bootnodes: seq[Record]): discv5_protocol.Protocol =
bootstrapRecords: seq[Record]):
discv5_protocol.Protocol =
var db = DiscoveryDB.init(newMemoryDB())
result = newProtocol(privKey, db,
parseIpAddress("127.0.0.1"),
address.tcpPort, address.udpPort)
for node in bootnodes:
result.addNode(node)
address.tcpPort, address.udpPort,
bootstrapRecords)
result.open()