Add update of ENR on newly discovered address

This commit is contained in:
kdeme 2021-01-26 14:11:22 +01:00 committed by zah
parent 689eef2c11
commit bfbad64d83
10 changed files with 177 additions and 78 deletions

View File

@ -14,12 +14,12 @@ type
DiscoveryConf* = object DiscoveryConf* = object
logLevel* {. logLevel* {.
defaultValue: LogLevel.DEBUG defaultValue: LogLevel.DEBUG
desc: "Sets the log level." desc: "Sets the log level"
name: "log-level" .}: LogLevel name: "log-level" .}: LogLevel
udpPort* {. udpPort* {.
defaultValue: 9009 defaultValue: 9009
desc: "UDP listening port." desc: "UDP listening port"
name: "udp-port" .}: uint16 name: "udp-port" .}: uint16
listenAddress* {. listenAddress* {.
@ -28,32 +28,39 @@ type
name: "listen-address" }: ValidIpAddress name: "listen-address" }: ValidIpAddress
bootnodes* {. bootnodes* {.
desc: "ENR URI of node to bootstrap discovery with. Argument may be repeated." desc: "ENR URI of node to bootstrap discovery with. Argument may be repeated"
name: "bootnode" .}: seq[enr.Record] name: "bootnode" .}: seq[enr.Record]
nat* {. nat* {.
desc: "Specify method to use for determining public address. " & desc: "Specify method to use for determining public address. " &
"Must be one of: any, none, upnp, pmp, extip:<IP>." "Must be one of: any, none, upnp, pmp, extip:<IP>"
defaultValue: "any" .}: string defaultValue: "any" .}: string
enrAutoUpdate* {.
defaultValue: false
desc: "Discovery can automatically update its ENR with the IP address " &
"and UDP port as seen by other nodes it communicates with. " &
"This option allows to enable/disable this functionality"
name: "enr-auto-update" .}: bool
nodeKey* {. nodeKey* {.
desc: "P2P node private key as hex.", desc: "P2P node private key as hex",
defaultValue: PrivateKey.random(keys.newRng()[]) defaultValue: PrivateKey.random(keys.newRng()[])
name: "nodekey" .}: PrivateKey name: "nodekey" .}: PrivateKey
metricsEnabled* {. metricsEnabled* {.
defaultValue: false defaultValue: false
desc: "Enable the metrics server." desc: "Enable the metrics server"
name: "metrics" .}: bool name: "metrics" .}: bool
metricsAddress* {. metricsAddress* {.
defaultValue: defaultAdminListenAddress(config) defaultValue: defaultAdminListenAddress(config)
desc: "Listening address of the metrics server." desc: "Listening address of the metrics server"
name: "metrics-address" .}: ValidIpAddress name: "metrics-address" .}: ValidIpAddress
metricsPort* {. metricsPort* {.
defaultValue: 8008 defaultValue: 8008
desc: "Listening HTTP port of the metrics server." desc: "Listening HTTP port of the metrics server"
name: "metrics-port" .}: Port name: "metrics-port" .}: Port
case cmd* {. case cmd* {.
@ -163,7 +170,8 @@ proc run(config: DiscoveryConf) =
let let
(ip, tcpPort, udpPort) = setupNat(config) (ip, tcpPort, udpPort) = setupNat(config)
d = newProtocol(config.nodeKey, ip, tcpPort, udpPort, d = newProtocol(config.nodeKey, ip, tcpPort, udpPort,
bootstrapRecords = config.bootnodes, bindIp = config.listenAddress) bootstrapRecords = config.bootnodes, bindIp = config.listenAddress,
enrAutoUpdate = config.enrAutoUpdate)
d.open() d.open()

View File

@ -144,7 +144,8 @@ template toFieldPair*(key: string, value: auto): FieldPair =
(key, toField(value)) (key, toField(value))
proc addAddress(fields: var seq[FieldPair], ip: Option[ValidIpAddress], proc addAddress(fields: var seq[FieldPair], ip: Option[ValidIpAddress],
tcpPort, udpPort: Port) = tcpPort, udpPort: Option[Port]) =
# It makes sense to add ports only when there is an IP provided
if ip.isSome(): if ip.isSome():
let let
ipExt = ip.get() ipExt = ip.get()
@ -152,16 +153,15 @@ proc addAddress(fields: var seq[FieldPair], ip: Option[ValidIpAddress],
fields.add(if isV6: ("ip6", ipExt.address_v6.toField) fields.add(if isV6: ("ip6", ipExt.address_v6.toField)
else: ("ip", ipExt.address_v4.toField)) else: ("ip", ipExt.address_v4.toField))
fields.add(((if isV6: "tcp6" else: "tcp"), tcpPort.uint16.toField)) if tcpPort.isSome():
fields.add(((if isV6: "udp6" else: "udp"), udpPort.uint16.toField)) fields.add(((if isV6: "tcp6" else: "tcp"), tcpPort.get().uint16.toField))
else: if udpPort.isSome():
fields.add(("tcp", tcpPort.uint16.toField)) fields.add(((if isV6: "udp6" else: "udp"), udpPort.get().uint16.toField))
fields.add(("udp", udpPort.uint16.toField))
proc init*(T: type Record, seqNum: uint64, proc init*(T: type Record, seqNum: uint64,
pk: PrivateKey, pk: PrivateKey,
ip: Option[ValidIpAddress], ip: Option[ValidIpAddress],
tcpPort, udpPort: Port, tcpPort, udpPort: Option[Port],
extraFields: openarray[FieldPair] = []): extraFields: openarray[FieldPair] = []):
EnrResult[T] = EnrResult[T] =
## Initialize a `Record` with given sequence number, private key, optional ## Initialize a `Record` with given sequence number, private key, optional
@ -281,7 +281,7 @@ proc update*(record: var Record, pk: PrivateKey,
proc update*(r: var Record, pk: PrivateKey, proc update*(r: var Record, pk: PrivateKey,
ip: Option[ValidIpAddress], ip: Option[ValidIpAddress],
tcpPort, udpPort: Port, tcpPort, udpPort: Option[Port] = none[Port](),
extraFields: openarray[FieldPair] = []): extraFields: openarray[FieldPair] = []):
EnrResult[void] = EnrResult[void] =
## Update a `Record` with given ip address, tcp port, udp port and optional ## Update a `Record` with given ip address, tcp port, udp port and optional

View File

@ -48,14 +48,20 @@ func newNode*(r: Record): Result[Node, cstring] =
ok(Node(id: pk.get().toNodeId(), pubkey: pk.get(), record: r, ok(Node(id: pk.get().toNodeId(), pubkey: pk.get(), record: r,
address: none(Address))) address: none(Address)))
proc updateNode*(n: Node, pk: PrivateKey, ip: Option[ValidIpAddress], proc update*(n: Node, pk: PrivateKey, ip: Option[ValidIpAddress],
tcpPort, udpPort: Port, extraFields: openarray[FieldPair] = []): tcpPort, udpPort: Option[Port] = none[Port](),
Result[void, cstring] = extraFields: openarray[FieldPair] = []): Result[void, cstring] =
? n.record.update(pk, ip, tcpPort, udpPort, extraFields) ? n.record.update(pk, ip, tcpPort, udpPort, extraFields)
if ip.isSome(): if ip.isSome():
let a = Address(ip: ip.get(), port: udpPort) if udpPort.isSome():
let a = Address(ip: ip.get(), port: udpPort.get())
n.address = some(a) n.address = some(a)
elif n.address.isSome():
let a = Address(ip: ip.get(), port: n.address.get().port)
n.address = some(a)
else:
n.address = none(Address)
else: else:
n.address = none(Address) n.address = none(Address)

View File

@ -1,5 +1,5 @@
# nim-eth - Node Discovery Protocol v5 # nim-eth - Node Discovery Protocol v5
# Copyright (c) 2020 Status Research & Development GmbH # Copyright (c) 2020-2021 Status Research & Development GmbH
# Licensed under either of # Licensed under either of
# * Apache License, version 2.0, (LICENSE-APACHEv2) # * Apache License, version 2.0, (LICENSE-APACHEv2)
# * MIT license (LICENSE-MIT) # * MIT license (LICENSE-MIT)
@ -106,6 +106,8 @@ const
## refresh the routing table. ## refresh the routing table.
revalidateMax = 10000 ## Revalidation of a peer is done between 0 and this revalidateMax = 10000 ## Revalidation of a peer is done between 0 and this
## value in milliseconds ## value in milliseconds
ipMajorityInterval = 5.minutes ## Interval for checking the latest IP:Port
## majority and updating this when ENR auto update is set.
initialLookups = 1 ## Amount of lookups done when populating the routing table initialLookups = 1 ## Amount of lookups done when populating the routing table
handshakeTimeout* = 2.seconds ## timeout for the reply on the handshakeTimeout* = 2.seconds ## timeout for the reply on the
## whoareyou message ## whoareyou message
@ -124,9 +126,11 @@ type
awaitedMessages: Table[(NodeId, RequestId), Future[Option[Message]]] awaitedMessages: Table[(NodeId, RequestId), Future[Option[Message]]]
refreshLoop: Future[void] refreshLoop: Future[void]
revalidateLoop: Future[void] revalidateLoop: Future[void]
ipMajorityLoop: Future[void]
lastLookup: chronos.Moment lastLookup: chronos.Moment
bootstrapRecords*: seq[Record] bootstrapRecords*: seq[Record]
ipVote: IpVote ipVote: IpVote
enrAutoUpdate: bool
rng*: ref BrHmacDrbgContext rng*: ref BrHmacDrbgContext
PendingRequest = object PendingRequest = object
@ -890,21 +894,46 @@ proc refreshLoop(d: Protocol) {.async, raises: [Exception, Defect].} =
trace "Discovered nodes in random target query", nodes = randomQuery.len trace "Discovered nodes in random target query", nodes = randomQuery.len
debug "Total nodes in discv5 routing table", total = d.routingTable.len() debug "Total nodes in discv5 routing table", total = d.routingTable.len()
let majority = d.ipVote.majority()
if majority.isSome():
let address = majority.get()
debug "Majority on voted address", address
await sleepAsync(refreshInterval) await sleepAsync(refreshInterval)
except CancelledError: except CancelledError:
trace "refreshLoop canceled" trace "refreshLoop canceled"
proc ipMajorityLoop(d: Protocol) {.async, raises: [Exception, Defect].} =
try:
while true:
let majority = d.ipVote.majority()
if majority.isSome():
if d.localNode.address != majority:
let address = majority.get()
let previous = d.localNode.address
if d.enrAutoUpdate:
let res = d.localNode.update(d.privateKey,
ip = some(address.ip), udpPort = some(address.port))
if res.isErr:
warn "Failed updating ENR with newly discovered external address",
majority, previous, error = res.error
else:
info "Updated ENR with newly discovered external address",
majority, previous, uri = toURI(d.localNode.record)
else:
warn "Discovered new external address but ENR auto update is off",
majority, previous
else:
debug "Discovered external address matches current address", majority,
current = d.localNode.address
await sleepAsync(ipMajorityInterval)
except CancelledError:
trace "ipMajorityLoop canceled"
proc newProtocol*(privKey: PrivateKey, proc newProtocol*(privKey: PrivateKey,
externalIp: Option[ValidIpAddress], tcpPort, udpPort: Port, externalIp: Option[ValidIpAddress],
tcpPort, udpPort: Port,
localEnrFields: openarray[(string, seq[byte])] = [], localEnrFields: openarray[(string, seq[byte])] = [],
bootstrapRecords: openarray[Record] = [], bootstrapRecords: openarray[Record] = [],
previousRecord = none[enr.Record](), previousRecord = none[enr.Record](),
bindIp = IPv4_any(), bindIp = IPv4_any(),
enrAutoUpdate = false,
tableIpLimits = DefaultTableIpLimits, tableIpLimits = DefaultTableIpLimits,
rng = newRng()): rng = newRng()):
Protocol {.raises: [Defect].} = Protocol {.raises: [Defect].} =
@ -920,11 +949,11 @@ proc newProtocol*(privKey: PrivateKey,
var record: Record var record: Record
if previousRecord.isSome(): if previousRecord.isSome():
record = previousRecord.get() record = previousRecord.get()
record.update(privKey, externalIp, tcpPort, udpPort, record.update(privKey, externalIp, some(tcpPort), some(udpPort),
extraFields).expect("Record within size limits and correct key") extraFields).expect("Record within size limits and correct key")
else: else:
record = enr.Record.init(1, privKey, externalIp, tcpPort, udpPort, record = enr.Record.init(1, privKey, externalIp, some(tcpPort),
extraFields).expect("Record within size limits") some(udpPort), extraFields).expect("Record within size limits")
let node = newNode(record).expect("Properly initialized record") let node = newNode(record).expect("Properly initialized record")
# TODO Consider whether this should be a Defect # TODO Consider whether this should be a Defect
@ -938,6 +967,7 @@ proc newProtocol*(privKey: PrivateKey,
sessions: Sessions.init(256)), sessions: Sessions.init(256)),
bootstrapRecords: @bootstrapRecords, bootstrapRecords: @bootstrapRecords,
ipVote: IpVote.init(), ipVote: IpVote.init(),
enrAutoUpdate: enrAutoUpdate,
rng: rng) rng: rng)
result.routingTable.init(node, DefaultBitsPerHop, tableIpLimits, rng) result.routingTable.init(node, DefaultBitsPerHop, tableIpLimits, rng)
@ -959,6 +989,7 @@ proc open*(d: Protocol) {.raises: [Exception, Defect].} =
proc start*(d: Protocol) {.raises: [Exception, Defect].} = proc start*(d: Protocol) {.raises: [Exception, Defect].} =
d.refreshLoop = refreshLoop(d) d.refreshLoop = refreshLoop(d)
d.revalidateLoop = revalidateLoop(d) d.revalidateLoop = revalidateLoop(d)
d.ipMajorityLoop = ipMajorityLoop(d)
proc close*(d: Protocol) {.raises: [Exception, Defect].} = proc close*(d: Protocol) {.raises: [Exception, Defect].} =
doAssert(not d.transp.closed) doAssert(not d.transp.closed)
@ -968,6 +999,8 @@ proc close*(d: Protocol) {.raises: [Exception, Defect].} =
d.revalidateLoop.cancel() d.revalidateLoop.cancel()
if not d.refreshLoop.isNil: if not d.refreshLoop.isNil:
d.refreshLoop.cancel() d.refreshLoop.cancel()
if not d.ipMajorityLoop.isNil:
d.ipMajorityLoop.cancel()
d.transp.close() d.transp.close()
@ -979,5 +1012,7 @@ proc closeWait*(d: Protocol) {.async, raises: [Exception, Defect].} =
await d.revalidateLoop.cancelAndWait() await d.revalidateLoop.cancelAndWait()
if not d.refreshLoop.isNil: if not d.refreshLoop.isNil:
await d.refreshLoop.cancelAndWait() await d.refreshLoop.cancelAndWait()
if not d.ipMajorityLoop.isNil:
await d.ipMajorityLoop.cancelAndWait()
await d.transp.closeWait() await d.transp.closeWait()

View File

@ -1,6 +1,6 @@
import import
testutils/fuzzing, stew/shims/net, stew/byteutils, testutils/fuzzing, stew/shims/net, stew/byteutils,
eth/p2p/discoveryv5/[encodingv1, enr, sessions, node] eth/p2p/discoveryv5/[encoding, enr, sessions, node]
init: init:
const const
@ -12,13 +12,13 @@ init:
privKeyB = PrivateKey.fromHex(nodeBKey)[] # receive -> decode privKeyB = PrivateKey.fromHex(nodeBKey)[] # receive -> decode
enrRecA = enr.Record.init(1, privKeyA, enrRecA = enr.Record.init(1, privKeyA,
some(ValidIpAddress.init("127.0.0.1")), Port(9000), some(ValidIpAddress.init("127.0.0.1")), some(Port(9000)),
Port(9000)).expect("Properly intialized private key") some(Port(9000))).expect("Properly intialized private key")
nodeA = newNode(enrRecA).expect("Properly initialized record") nodeA = newNode(enrRecA).expect("Properly initialized record")
enrRecB = enr.Record.init(1, privKeyB, enrRecB = enr.Record.init(1, privKeyB,
some(ValidIpAddress.init("127.0.0.1")), Port(9000), some(ValidIpAddress.init("127.0.0.1")), some(Port(9000)),
Port(9000)).expect("Properly intialized private key") some(Port(9000))).expect("Properly intialized private key")
nodeB = newNode(enrRecB).expect("Properly initialized record") nodeB = newNode(enrRecB).expect("Properly initialized record")
var codecB = Codec(localNode: nodeB, privKey: privKeyB, var codecB = Codec(localNode: nodeB, privKey: privKeyB,

View File

@ -38,7 +38,7 @@ proc generateNode*(privKey: PrivateKey, port: int = 20302,
localEnrFields: openarray[FieldPair] = []): Node = localEnrFields: openarray[FieldPair] = []): Node =
let port = Port(port) let port = Port(port)
let enr = enr.Record.init(1, privKey, some(ip), let enr = enr.Record.init(1, privKey, some(ip),
port, port, localEnrFields).expect("Properly intialized private key") some(port), some(port), localEnrFields).expect("Properly intialized private key")
result = newNode(enr).expect("Properly initialized node") result = newNode(enr).expect("Properly initialized node")
proc nodeAndPrivKeyAtDistance*(n: Node, rng: var BrHmacDrbgContext, d: uint32, proc nodeAndPrivKeyAtDistance*(n: Node, rng: var BrHmacDrbgContext, d: uint32,

View File

@ -463,7 +463,7 @@ procSuite "Discovery v5 Tests":
port = Port(9000) port = Port(9000)
fromNoderecord = enr.Record.init(1, PrivateKey.random(rng[]), fromNoderecord = enr.Record.init(1, PrivateKey.random(rng[]),
some(ValidIpAddress.init("11.12.13.14")), some(ValidIpAddress.init("11.12.13.14")),
port, port)[] some(port), some(port))[]
fromNode = newNode(fromNoderecord)[] fromNode = newNode(fromNoderecord)[]
pk = PrivateKey.random(rng[]) pk = PrivateKey.random(rng[])
targetDistance = logDist(fromNode.id, pk.toPublicKey().toNodeId()) targetDistance = logDist(fromNode.id, pk.toPublicKey().toNodeId())
@ -471,7 +471,8 @@ procSuite "Discovery v5 Tests":
block: # Duplicates block: # Duplicates
let let
record = enr.Record.init( record = enr.Record.init(
1, pk, some(ValidIpAddress.init("12.13.14.15")), port, port)[] 1, pk, some(ValidIpAddress.init("12.13.14.15")),
some(port), some(port))[]
# Exact duplicates # Exact duplicates
var records = @[record, record] var records = @[record, record]
@ -480,7 +481,8 @@ procSuite "Discovery v5 Tests":
# Node id duplicates # Node id duplicates
let recordSameId = enr.Record.init( let recordSameId = enr.Record.init(
1, pk, some(ValidIpAddress.init("212.13.14.15")), port, port)[] 1, pk, some(ValidIpAddress.init("212.13.14.15")),
some(port), some(port))[]
records.add(recordSameId) records.add(recordSameId)
nodes = verifyNodesRecords(records, fromNode, targetDistance) nodes = verifyNodesRecords(records, fromNode, targetDistance)
check nodes.len == 1 check nodes.len == 1
@ -488,7 +490,7 @@ procSuite "Discovery v5 Tests":
block: # No address block: # No address
let let
recordNoAddress = enr.Record.init( recordNoAddress = enr.Record.init(
1, pk, none(ValidIpAddress), port, port)[] 1, pk, none(ValidIpAddress), some(port), some(port))[]
records = [recordNoAddress] records = [recordNoAddress]
test = verifyNodesRecords(records, fromNode, targetDistance) test = verifyNodesRecords(records, fromNode, targetDistance)
check test.len == 0 check test.len == 0
@ -497,7 +499,7 @@ procSuite "Discovery v5 Tests":
let let
recordInvalidAddress = enr.Record.init( recordInvalidAddress = enr.Record.init(
1, pk, some(ValidIpAddress.init("10.1.2.3")), 1, pk, some(ValidIpAddress.init("10.1.2.3")),
port, port)[] some(port), some(port))[]
records = [recordInvalidAddress] records = [recordInvalidAddress]
test = verifyNodesRecords(records, fromNode, targetDistance) test = verifyNodesRecords(records, fromNode, targetDistance)
check test.len == 0 check test.len == 0
@ -505,7 +507,8 @@ procSuite "Discovery v5 Tests":
block: # Invalid address - loopback block: # Invalid address - loopback
let let
recordInvalidAddress = enr.Record.init( recordInvalidAddress = enr.Record.init(
1, pk, some(ValidIpAddress.init("127.0.0.1")), port, port)[] 1, pk, some(ValidIpAddress.init("127.0.0.1")),
some(port), some(port))[]
records = [recordInvalidAddress] records = [recordInvalidAddress]
test = verifyNodesRecords(records, fromNode, targetDistance) test = verifyNodesRecords(records, fromNode, targetDistance)
check test.len == 0 check test.len == 0
@ -513,7 +516,8 @@ procSuite "Discovery v5 Tests":
block: # Invalid distance block: # Invalid distance
let let
recordInvalidDistance = enr.Record.init( recordInvalidDistance = enr.Record.init(
1, pk, some(ValidIpAddress.init("12.13.14.15")), port, port)[] 1, pk, some(ValidIpAddress.init("12.13.14.15")),
some(port), some(port))[]
records = [recordInvalidDistance] records = [recordInvalidDistance]
test = verifyNodesRecords(records, fromNode, 0'u32) test = verifyNodesRecords(records, fromNode, 0'u32)
check test.len == 0 check test.len == 0
@ -530,8 +534,8 @@ procSuite "Discovery v5 Tests":
let let
privKey = PrivateKey.random(rng[]) privKey = PrivateKey.random(rng[])
enrRec = enr.Record.init(1, privKey, enrRec = enr.Record.init(1, privKey,
some(ValidIpAddress.init("127.0.0.1")), Port(9000), some(ValidIpAddress.init("127.0.0.1")), some(Port(9000)),
Port(9000)).expect("Properly intialized private key") some(Port(9000))).expect("Properly intialized private key")
sendNode = newNode(enrRec).expect("Properly initialized record") sendNode = newNode(enrRec).expect("Properly initialized record")
var codec = Codec(localNode: sendNode, privKey: privKey, sessions: Sessions.init(5)) var codec = Codec(localNode: sendNode, privKey: privKey, sessions: Sessions.init(5))
@ -559,8 +563,8 @@ procSuite "Discovery v5 Tests":
let let
privKey = PrivateKey.random(rng[]) privKey = PrivateKey.random(rng[])
enrRec = enr.Record.init(1, privKey, enrRec = enr.Record.init(1, privKey,
some(ValidIpAddress.init("127.0.0.1")), Port(9000), some(ValidIpAddress.init("127.0.0.1")), some(Port(9000)),
Port(9000)).expect("Properly intialized private key") some(Port(9000))).expect("Properly intialized private key")
sendNode = newNode(enrRec).expect("Properly initialized record") sendNode = newNode(enrRec).expect("Properly initialized record")
var codec = Codec(localNode: sendNode, privKey: privKey, sessions: Sessions.init(5)) var codec = Codec(localNode: sendNode, privKey: privKey, sessions: Sessions.init(5))
for i in 0 ..< 5: for i in 0 ..< 5:
@ -590,8 +594,8 @@ procSuite "Discovery v5 Tests":
a = localAddress(20303) a = localAddress(20303)
privKey = PrivateKey.random(rng[]) privKey = PrivateKey.random(rng[])
enrRec = enr.Record.init(1, privKey, enrRec = enr.Record.init(1, privKey,
some(ValidIpAddress.init("127.0.0.1")), Port(9000), some(ValidIpAddress.init("127.0.0.1")), some(Port(9000)),
Port(9000)).expect("Properly intialized private key") some(Port(9000))).expect("Properly intialized private key")
sendNode = newNode(enrRec).expect("Properly initialized record") sendNode = newNode(enrRec).expect("Properly initialized record")
var codec = Codec(localNode: sendNode, privKey: privKey, sessions: Sessions.init(5)) var codec = Codec(localNode: sendNode, privKey: privKey, sessions: Sessions.init(5))

View File

@ -219,13 +219,13 @@ suite "Discovery v5.1 Packet Encodings Test Vectors":
privKeyB = PrivateKey.fromHex(nodeBKey)[] # receive -> decode privKeyB = PrivateKey.fromHex(nodeBKey)[] # receive -> decode
enrRecA = enr.Record.init(1, privKeyA, enrRecA = enr.Record.init(1, privKeyA,
some(ValidIpAddress.init("127.0.0.1")), Port(9000), some(ValidIpAddress.init("127.0.0.1")), some(Port(9000)),
Port(9000)).expect("Properly intialized private key") some(Port(9000))).expect("Properly intialized private key")
nodeA = newNode(enrRecA).expect("Properly initialized record") nodeA = newNode(enrRecA).expect("Properly initialized record")
enrRecB = enr.Record.init(1, privKeyB, enrRecB = enr.Record.init(1, privKeyB,
some(ValidIpAddress.init("127.0.0.1")), Port(9000), some(ValidIpAddress.init("127.0.0.1")), some(Port(9000)),
Port(9000)).expect("Properly intialized private key") some(Port(9000))).expect("Properly intialized private key")
nodeB = newNode(enrRecB).expect("Properly initialized record") nodeB = newNode(enrRecB).expect("Properly initialized record")
var var
@ -432,12 +432,14 @@ suite "Discovery v5.1 Additional Encode/Decode":
privKeyA = PrivateKey.random(rng[]) # sender -> encode privKeyA = PrivateKey.random(rng[]) # sender -> encode
privKeyB = PrivateKey.random(rng[]) # receiver -> decode privKeyB = PrivateKey.random(rng[]) # receiver -> decode
enrRecA = enr.Record.init(1, privKeyA, some(ValidIpAddress.init("127.0.0.1")), Port(9000), enrRecA = enr.Record.init(1, privKeyA,
Port(9000)).expect("Properly intialized private key") some(ValidIpAddress.init("127.0.0.1")), some(Port(9000)),
some(Port(9000))).expect("Properly intialized private key")
nodeA = newNode(enrRecA).expect("Properly initialized record") nodeA = newNode(enrRecA).expect("Properly initialized record")
enrRecB = enr.Record.init(1, privKeyB, some(ValidIpAddress.init("127.0.0.1")), Port(9000), enrRecB = enr.Record.init(1, privKeyB,
Port(9000)).expect("Properly intialized private key") some(ValidIpAddress.init("127.0.0.1")), some(Port(9000)),
some(Port(9000))).expect("Properly intialized private key")
nodeB = newNode(enrRecB).expect("Properly initialized record") nodeB = newNode(enrRecB).expect("Properly initialized record")
var var

View File

@ -60,8 +60,9 @@ suite "ENR":
let let
keypair = KeyPair.random(rng[]) keypair = KeyPair.random(rng[])
ip = ValidIpAddress.init("10.20.30.40") ip = ValidIpAddress.init("10.20.30.40")
port = some(Port(9000))
enr = Record.init( enr = Record.init(
100, keypair.seckey, some(ip), Port(9000), Port(9000),@[])[] 100, keypair.seckey, some(ip), port, port,@[])[]
typedEnr = get enr.toTypedRecord() typedEnr = get enr.toTypedRecord()
check: check:
@ -80,8 +81,9 @@ suite "ENR":
test "ENR without address": test "ENR without address":
let let
keypair = KeyPair.random(rng[]) keypair = KeyPair.random(rng[])
port = some(Port(9000))
enr = Record.init( enr = Record.init(
100, keypair.seckey, none(ValidIpAddress), Port(9000), Port(9000))[] 100, keypair.seckey, none(ValidIpAddress), port, port)[]
typedEnr = get enr.toTypedRecord() typedEnr = get enr.toTypedRecord()
check: check:
@ -89,11 +91,8 @@ suite "ENR":
typedEnr.secp256k1.get() == keypair.pubkey.toRawCompressed() typedEnr.secp256k1.get() == keypair.pubkey.toRawCompressed()
typedEnr.ip.isNone() typedEnr.ip.isNone()
typedEnr.tcp.isSome() typedEnr.tcp.isNone()
typedEnr.tcp.get() == 9000 typedEnr.udp.isNone()
typedEnr.udp.isSome()
typedEnr.udp.get() == 9000
typedEnr.ip6.isNone() typedEnr.ip6.isNone()
typedEnr.tcp6.isNone() typedEnr.tcp6.isNone()
@ -115,7 +114,7 @@ suite "ENR":
pk = PrivateKey.fromHex( pk = PrivateKey.fromHex(
"5d2908f3f09ea1ff2e327c3f623159639b00af406e9009de5fd4b910fc34049d")[] "5d2908f3f09ea1ff2e327c3f623159639b00af406e9009de5fd4b910fc34049d")[]
newField = toFieldPair("test", 123'u) newField = toFieldPair("test", 123'u)
var r = Record.init(1, pk, none(ValidIpAddress), Port(9000), Port(9000))[] var r = Record.init(1, pk, none(ValidIpAddress), none(Port), none(Port))[]
block: # Insert new k:v pair, update of seqNum should occur. block: # Insert new k:v pair, update of seqNum should occur.
let updated = r.update(pk, [newField]) let updated = r.update(pk, [newField])
@ -182,20 +181,63 @@ suite "ENR":
let let
pk = PrivateKey.fromHex( pk = PrivateKey.fromHex(
"5d2908f3f09ea1ff2e327c3f623159639b00af406e9009de5fd4b910fc34049d")[] "5d2908f3f09ea1ff2e327c3f623159639b00af406e9009de5fd4b910fc34049d")[]
var r = Record.init(1, pk, none(ValidIpAddress), Port(9000), Port(9000))[] var r = Record.init(1, pk, none(ValidIpAddress),
some(Port(9000)), some(Port(9000)))[]
block: block:
let updated = r.update(pk, none(ValidIpAddress), Port(9000), Port(9000)) let updated = r.update(pk, none(ValidIpAddress),
some(Port(9000)), some(Port(9000)))
check updated.isOk() check updated.isOk()
check: check:
r.get("tcp", uint) == 9000 r.tryGet("ip", uint).isNone()
r.get("udp", uint) == 9000 r.tryGet("tcp", uint).isNone()
r.tryGet("udp", uint).isNone()
r.seqNum == 1 r.seqNum == 1
block: block:
let updated = r.update(pk, none(ValidIpAddress), Port(9001), Port(9002)) let updated = r.update(pk, none(ValidIpAddress),
some(Port(9001)), some(Port(9002)))
check updated.isOk() check updated.isOk()
check: check:
r.get("tcp", uint) == 9001 r.tryGet("ip", uint).isNone()
r.get("udp", uint) == 9002 r.tryGet("tcp", uint).isNone()
r.tryGet("udp", uint).isNone()
r.seqNum == 1
block:
let updated = r.update(pk, some(ValidIpAddress.init("10.20.30.40")),
some(Port(9000)), some(Port(9000)))
check updated.isOk()
let typedEnr = r.toTypedRecord().get()
check:
typedEnr.ip.isSome()
typedEnr.ip.get() == [byte 10, 20, 30, 40]
typedEnr.tcp.isSome()
typedEnr.tcp.get() == 9000
typedEnr.udp.isSome()
typedEnr.udp.get() == 9000
r.seqNum == 2 r.seqNum == 2
block:
let updated = r.update(pk, some(ValidIpAddress.init("10.20.30.40")),
some(Port(9001)), some(Port(9001)))
check updated.isOk()
let typedEnr = r.toTypedRecord().get()
check:
typedEnr.ip.isSome()
typedEnr.ip.get() == [byte 10, 20, 30, 40]
typedEnr.tcp.isSome()
typedEnr.tcp.get() == 9001
typedEnr.udp.isSome()
typedEnr.udp.get() == 9001
r.seqNum == 3

View File

@ -472,8 +472,9 @@ suite "Routing Table Tests":
let updatedNode1 = generateNode(pk) let updatedNode1 = generateNode(pk)
# Need to do an update to get seqNum increased # Need to do an update to get seqNum increased
let updated = updatedNode1.updateNode(pk, let updated = updatedNode1.update(pk,
some(ValidIpAddress.init("192.168.0.1")), Port(9000), Port(9000)) some(ValidIpAddress.init("192.168.0.1")),
some(Port(9000)), some(Port(9000)))
check updated.isOk() check updated.isOk()
check table.addNode(updatedNode1) == Existing check table.addNode(updatedNode1) == Existing
@ -524,8 +525,9 @@ suite "Routing Table Tests":
for i in 0..<DefaultTableIpLimits.bucketIpLimit + 1: for i in 0..<DefaultTableIpLimits.bucketIpLimit + 1:
# Need to do an update to get seqNum increased # Need to do an update to get seqNum increased
let updated = updatedNode1.updateNode(pk, let updated = updatedNode1.update(pk,
some(ValidIpAddress.init("192.168.0.1")), Port(9000+i), Port(9000+i)) some(ValidIpAddress.init("192.168.0.1")),
some(Port(9000+i)), some(Port(9000+i)))
check updated.isOk() check updated.isOk()
check table.addNode(updatedNode1) == Existing check table.addNode(updatedNode1) == Existing