Add getNode and tests for findNode and getNode

This commit is contained in:
kdeme 2020-03-20 16:38:46 +01:00 committed by zah
parent f46f9f1418
commit 713f2e3bff
5 changed files with 106 additions and 31 deletions

View File

@ -101,15 +101,19 @@ macro initRecord*(seqNum: uint64, pk: PrivateKey, pairs: untyped{nkTableConstr})
proc init*(T: type Record, seqNum: uint64, proc init*(T: type Record, seqNum: uint64,
pk: PrivateKey, pk: PrivateKey,
address: enode.Address): T = address: Option[enode.Address]): T =
let if address.isSome():
isV6 = address.ip.family == IPv6 let
ipField = if isV6: ("ip6", address.ip.address_v6.toField) a = address.get()
else: ("ip", address.ip.address_v4.toField) isV6 = a.ip.family == IPv6
tcpField = ((if isV6: "tcp6" else: "tcp"), address.tcpPort.uint16.toField) ipField = if isV6: ("ip6", a.ip.address_v6.toField)
udpField = ((if isV6: "udp6" else: "udp"), address.udpPort.uint16.toField) else: ("ip", a.ip.address_v4.toField)
tcpField = ((if isV6: "tcp6" else: "tcp"), a.tcpPort.uint16.toField)
udpField = ((if isV6: "udp6" else: "udp"), a.udpPort.uint16.toField)
makeEnrAux(seqNum, pk, [ipField, tcpField, udpField]) makeEnrAux(seqNum, pk, [ipField, tcpField, udpField])
else:
makeEnrAux(seqNum, pk, [])
proc getField(r: Record, name: string, field: var Field): bool = proc getField(r: Record, name: string, field: var Field): bool =
# It might be more correct to do binary search, # It might be more correct to do binary search,

View File

@ -28,19 +28,23 @@ proc newNode*(pk: PublicKey, address: Address): Node =
proc newNode*(r: Record): Node = proc newNode*(r: Record): Node =
# TODO: Handle IPv6 # TODO: Handle IPv6
let var a: Address
ipBytes = r.get("ip", array[4, byte]) try:
udpPort = r.get("udp", uint16) let
ipBytes = r.get("ip", array[4, byte])
udpPort = r.get("udp", uint16)
a = Address(ip: IpAddress(family: IpAddressFamily.IPv4,
address_v4: ipBytes),
udpPort: Port udpPort)
except KeyError:
discard
var pk: PublicKey var pk: PublicKey
if recoverPublicKey(r.get("secp256k1", seq[byte]), pk) != EthKeysStatus.Success: if recoverPublicKey(r.get("secp256k1", seq[byte]), pk) != EthKeysStatus.Success:
warn "Could not recover public key" warn "Could not recover public key"
return return
let a = Address(ip: IpAddress(family: IpAddressFamily.IPv4,
address_v4: ipBytes),
udpPort: Port udpPort)
result = newNode(initENode(pk, a)) result = newNode(initENode(pk, a))
result.record = r result.record = r

View File

@ -59,10 +59,16 @@ proc addNode*(d: Protocol, enr: EnrUri) =
doAssert(res) doAssert(res)
d.addNode newNode(r) d.addNode newNode(r)
proc randomNodes*(k: Protocol, count: int): seq[Node] = proc getNode*(d: Protocol, id: NodeId): Node =
k.routingTable.randomNodes(count) d.routingTable.getNode(id)
proc nodesDiscovered*(k: Protocol): int {.inline.} = k.routingTable.len proc randomNodes*(d: Protocol, count: int): seq[Node] =
d.routingTable.randomNodes(count)
proc neighbours*(d: Protocol, id: NodeId, k: int = BUCKET_SIZE): seq[Node] =
d.routingTable.neighbours(id, k)
proc nodesDiscovered*(d: Protocol): int {.inline.} = d.routingTable.len
proc whoareyouMagic(toNode: NodeId): array[magicSize, byte] = proc whoareyouMagic(toNode: NodeId): array[magicSize, byte] =
const prefix = "WHOAREYOU" const prefix = "WHOAREYOU"
@ -77,7 +83,7 @@ proc newProtocol*(privKey: PrivateKey, db: Database,
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)
enrRec = enr.Record.init(12, privKey, a) enrRec = enr.Record.init(12, privKey, some(a))
node = newNode(enode, enrRec) node = newNode(enode, enrRec)
result = Protocol( result = Protocol(
@ -281,7 +287,7 @@ proc waitNodes(d: Protocol, fromNode: Node, reqId: RequestId): Future[seq[Node]]
else: else:
break break
proc findNode(d: Protocol, toNode: Node, distance: uint32): Future[seq[Node]] {.async.} = proc findNode*(d: Protocol, toNode: Node, distance: uint32): Future[seq[Node]] {.async.} =
let reqId = newRequestId() let reqId = newRequestId()
let packet = encodePacket(FindNodePacket(distance: distance), reqId) let packet = encodePacket(FindNodePacket(distance: distance), reqId)
let (data, nonce) = d.codec.encodeEncrypted(toNode.id, toNode.address, packet, let (data, nonce) = d.codec.encodeEncrypted(toNode.id, toNode.address, packet,

View File

@ -1,5 +1,5 @@
import import
random, unittest, chronos, sequtils, chronicles, tables, stint, random, unittest, chronos, sequtils, chronicles, tables, stint, options,
eth/[keys, rlp], eth/p2p/enode, eth/trie/db, eth/[keys, rlp], eth/p2p/enode, eth/trie/db,
eth/p2p/discoveryv5/[discovery_db, enr, node, types, routing_table, encoding], eth/p2p/discoveryv5/[discovery_db, enr, node, types, routing_table, encoding],
eth/p2p/discoveryv5/protocol as discv5_protocol, eth/p2p/discoveryv5/protocol as discv5_protocol,
@ -32,6 +32,10 @@ proc randomPacket(tag: PacketTag): seq[byte] =
result.add(rlp.encode(authTag)) result.add(rlp.encode(authTag))
result.add(msg) result.add(msg)
proc generateNode(privKey = newPrivateKey()): Node =
let enr = enr.Record.init(1, privKey, none(Address))
result = newNode(enr)
suite "Discovery v5 Tests": suite "Discovery v5 Tests":
asyncTest "Random nodes": asyncTest "Random nodes":
let let
@ -88,6 +92,47 @@ suite "Discovery v5 Tests":
for node in nodes: for node in nodes:
await node.closeWait() await node.closeWait()
asyncTest "FindNode with test table":
let mainNode = initDiscoveryNode(newPrivateKey(), localAddress(20301), @[])
# Generate 1000 random nodes and add to our main node's routing table
for i in 0..<1000:
mainNode.addNode(generateNode())
let
neighbours = mainNode.neighbours(mainNode.localNode.id)
closest = neighbours[0]
closestDistance = logDist(closest.id, mainNode.localNode.id)
debug "Closest neighbour", closestDistance, id=closest.id.toHex()
let
testNode = initDiscoveryNode(newPrivateKey(), localAddress(20302),
@[mainNode.localNode.record])
discovered = await discv5_protocol.findNode(testNode, mainNode.localNode,
closestDistance)
check closest in discovered
await mainNode.closeWait()
await testNode.closeWait()
asyncTest "GetNode":
# TODO: This could be tested in just a routing table only context
let
node = initDiscoveryNode(newPrivateKey(), localAddress(20302), @[])
targetNode = generateNode()
node.addNode(targetNode)
for i in 0..<1000:
node.addNode(generateNode())
check node.getNode(targetNode.id) == targetNode
await node.closeWait()
asyncTest "Handshake cleanup": asyncTest "Handshake cleanup":
let node = initDiscoveryNode(newPrivateKey(), localAddress(20302), @[]) let node = initDiscoveryNode(newPrivateKey(), localAddress(20302), @[])
var tag: PacketTag var tag: PacketTag

View File

@ -35,19 +35,35 @@ suite "ENR":
keys = newKeyPair() keys = newKeyPair()
ip = parseIpAddress("10.20.30.40") ip = parseIpAddress("10.20.30.40")
enodeAddress = Address(ip: ip, tcpPort: Port 9000, udpPort: Port 9000) enodeAddress = Address(ip: ip, tcpPort: Port 9000, udpPort: Port 9000)
enr = Record.init(100, keys.seckey, enodeAddress) enr = Record.init(100, keys.seckey, some(enodeAddress))
typedEnr = get enr.toTypedRecord typedEnr = get enr.toTypedRecord()
check: check:
typedEnr.secp256k1.isSome typedEnr.secp256k1.isSome()
typedEnr.secp256k1.get == keys.pubkey.getRawCompressed typedEnr.secp256k1.get == keys.pubkey.getRawCompressed()
typedEnr.ip.isSome typedEnr.ip.isSome()
typedEnr.ip.get == [byte 10, 20, 30, 40] typedEnr.ip.get() == [byte 10, 20, 30, 40]
typedEnr.tcp.isSome typedEnr.tcp.isSome()
typedEnr.tcp.get == 9000 typedEnr.tcp.get() == 9000
typedEnr.udp.isSome typedEnr.udp.isSome()
typedEnr.udp.get == 9000 typedEnr.udp.get() == 9000
test "ENR without address":
let
keys = newKeyPair()
enr = Record.init(100, keys.seckey, none(Address))
typedEnr = get enr.toTypedRecord()
check:
typedEnr.secp256k1.isSome()
typedEnr.secp256k1.get() == keys.pubkey.getRawCompressed()
typedEnr.ip.isNone()
typedEnr.tcp.isNone()
typedEnr.udp.isNone()
typedEnr.ip6.isNone()
typedEnr.tcp6.isNone()
typedEnr.udp6.isNone()