mirror of https://github.com/status-im/nim-eth.git
Add update of ENR on newly discovered address
This commit is contained in:
parent
689eef2c11
commit
bfbad64d83
|
@ -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()
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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():
|
||||||
n.address = some(a)
|
let a = Address(ip: ip.get(), port: udpPort.get())
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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))
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue