mirror of https://github.com/status-im/nim-eth.git
discv5: Pass bootstrap nodes and add deletion of nodes
This commit is contained in:
parent
2b7a25175b
commit
267a06dbe6
|
@ -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
|
# 2. Should verify ENR and check for correct id in case an ENR is included
|
||||||
# 3. Should verify id nonce signature
|
# 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)
|
newNode = newNode(authResp.record)
|
||||||
return true
|
return true
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,10 @@ proc newNode*(r: Record): Node =
|
||||||
result = newNode(initENode(pk, a))
|
result = newNode(initENode(pk, a))
|
||||||
result.record = r
|
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 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)
|
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)
|
||||||
|
|
||||||
|
|
|
@ -38,11 +38,32 @@ type
|
||||||
awaitedPackets: Table[(Node, RequestId), Future[Option[Packet]]]
|
awaitedPackets: Table[(Node, RequestId), Future[Option[Packet]]]
|
||||||
lookupLoop: Future[void]
|
lookupLoop: Future[void]
|
||||||
revalidateLoop: Future[void]
|
revalidateLoop: Future[void]
|
||||||
|
bootstrapNodes: seq[Node]
|
||||||
|
|
||||||
PendingRequest = object
|
PendingRequest = object
|
||||||
node: Node
|
node: Node
|
||||||
packet: seq[byte]
|
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] =
|
proc whoareyouMagic(toNode: NodeId): array[magicSize, byte] =
|
||||||
const prefix = "WHOAREYOU"
|
const prefix = "WHOAREYOU"
|
||||||
var data: array[prefix.len + sizeof(toNode), byte]
|
var data: array[prefix.len + sizeof(toNode), byte]
|
||||||
|
@ -51,7 +72,8 @@ proc whoareyouMagic(toNode: NodeId): array[magicSize, byte] =
|
||||||
sha256.digest(data).data
|
sha256.digest(data).data
|
||||||
|
|
||||||
proc newProtocol*(privKey: PrivateKey, db: Database,
|
proc newProtocol*(privKey: PrivateKey, db: Database,
|
||||||
ip: IpAddress, tcpPort, udpPort: Port): Protocol =
|
ip: IpAddress, tcpPort, udpPort: Port,
|
||||||
|
bootstrapRecords: openarray[Record] = []): Protocol =
|
||||||
let
|
let
|
||||||
a = Address(ip: ip, tcpPort: tcpPort, udpPort: udpPort)
|
a = Address(ip: ip, tcpPort: tcpPort, udpPort: udpPort)
|
||||||
enode = initENode(privKey.getPublicKey(), a)
|
enode = initENode(privKey.getPublicKey(), a)
|
||||||
|
@ -64,7 +86,8 @@ proc newProtocol*(privKey: PrivateKey, db: Database,
|
||||||
localNode: node,
|
localNode: node,
|
||||||
whoareyouMagic: whoareyouMagic(node.id),
|
whoareyouMagic: whoareyouMagic(node.id),
|
||||||
idHash: sha256.digest(node.id.toByteArrayBE).data,
|
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)
|
result.routingTable.init(node)
|
||||||
|
|
||||||
|
@ -355,6 +378,7 @@ proc ping(p: Protocol, toNode: Node): RequestId =
|
||||||
|
|
||||||
proc revalidateNode(p: Protocol, n: Node)
|
proc revalidateNode(p: Protocol, n: Node)
|
||||||
{.async, raises:[Defect, Exception].} = # TODO: Exception
|
{.async, raises:[Defect, Exception].} = # TODO: Exception
|
||||||
|
trace "Ping to revalidate node", node = $n
|
||||||
let reqId = p.ping(n)
|
let reqId = p.ping(n)
|
||||||
|
|
||||||
let resp = await p.waitPacket(n, reqId)
|
let resp = await p.waitPacket(n, reqId)
|
||||||
|
@ -367,8 +391,15 @@ proc revalidateNode(p: Protocol, n: Node)
|
||||||
p.routingTable.setJustSeen(n)
|
p.routingTable.setJustSeen(n)
|
||||||
trace "Revalidated node", node = $n
|
trace "Revalidated node", node = $n
|
||||||
else:
|
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)
|
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.} =
|
proc revalidateLoop(p: Protocol) {.async.} =
|
||||||
try:
|
try:
|
||||||
|
@ -389,8 +420,12 @@ proc lookupLoop(d: Protocol) {.async.} =
|
||||||
## TODO: Same story as for `revalidateLoop`
|
## TODO: Same story as for `revalidateLoop`
|
||||||
try:
|
try:
|
||||||
while true:
|
while true:
|
||||||
let nodes = await d.lookupRandom()
|
# lookup self (neighbour nodes)
|
||||||
trace "Discovered nodes", nodes = $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)
|
await sleepAsync(lookupInterval)
|
||||||
except CancelledError:
|
except CancelledError:
|
||||||
trace "lookupLoop canceled"
|
trace "lookupLoop canceled"
|
||||||
|
@ -401,6 +436,10 @@ proc open*(d: Protocol) =
|
||||||
# TODO allow binding to specific IP / IPv6 / etc
|
# TODO allow binding to specific IP / IPv6 / etc
|
||||||
let ta = initTAddress(IPv4_any(), d.localNode.node.address.udpPort)
|
let ta = initTAddress(IPv4_any(), d.localNode.node.address.udpPort)
|
||||||
d.transp = newDatagramTransport(processClient, udata = d, local = ta)
|
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.
|
# Might want to move these to a separate proc if this turns out to be needed.
|
||||||
d.lookupLoop = lookupLoop(d)
|
d.lookupLoop = lookupLoop(d)
|
||||||
d.revalidateLoop = revalidateLoop(d)
|
d.revalidateLoop = revalidateLoop(d)
|
||||||
|
@ -425,26 +464,6 @@ proc closeWait*(d: Protocol) {.async.} =
|
||||||
d.lookupLoop.cancelAndWait()])
|
d.lookupLoop.cancelAndWait()])
|
||||||
await d.transp.closeWait()
|
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:
|
when isMainModule:
|
||||||
import discovery_db
|
import discovery_db
|
||||||
import eth/trie/db
|
import eth/trie/db
|
||||||
|
|
|
@ -6,14 +6,13 @@ import
|
||||||
./p2p_test_helper
|
./p2p_test_helper
|
||||||
|
|
||||||
proc initDiscoveryNode*(privKey: PrivateKey, address: Address,
|
proc initDiscoveryNode*(privKey: PrivateKey, address: Address,
|
||||||
bootnodes: seq[Record]): discv5_protocol.Protocol =
|
bootstrapRecords: seq[Record]):
|
||||||
|
discv5_protocol.Protocol =
|
||||||
var db = DiscoveryDB.init(newMemoryDB())
|
var db = DiscoveryDB.init(newMemoryDB())
|
||||||
result = newProtocol(privKey, db,
|
result = newProtocol(privKey, db,
|
||||||
parseIpAddress("127.0.0.1"),
|
parseIpAddress("127.0.0.1"),
|
||||||
address.tcpPort, address.udpPort)
|
address.tcpPort, address.udpPort,
|
||||||
|
bootstrapRecords)
|
||||||
for node in bootnodes:
|
|
||||||
result.addNode(node)
|
|
||||||
|
|
||||||
result.open()
|
result.open()
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue