mirror of https://github.com/status-im/nim-eth.git
Use results.Opt instead of option in discv5, utp and nat (#705)
+ some other minor cleanups
This commit is contained in:
parent
f169068df6
commit
26212c881b
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
# Ethereum KeyFile
|
# Ethereum KeyFile
|
||||||
# (c) Copyright 2018
|
# (c) Copyright 2018-2024
|
||||||
# Status Research & Development GmbH
|
# Status Research & Development GmbH
|
||||||
#
|
#
|
||||||
# Licensed under either of
|
# Licensed under either of
|
||||||
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
{.push raises: [].}
|
{.push raises: [].}
|
||||||
|
|
||||||
import stew/[byteutils, endians2, results]
|
import stew/[byteutils, endians2], results
|
||||||
|
|
||||||
from nimcrypto/utils import stripSpaces
|
from nimcrypto/utils import stripSpaces
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Copyright (c) 2019-2023 Status Research & Development GmbH
|
# Copyright (c) 2019-2024 Status Research & Development GmbH
|
||||||
# Licensed under either of
|
# Licensed under either of
|
||||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
||||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
||||||
|
@ -9,11 +9,13 @@
|
||||||
{.push raises: [].}
|
{.push raises: [].}
|
||||||
|
|
||||||
import
|
import
|
||||||
std/[options, os, strutils, times],
|
std/[os, strutils, times],
|
||||||
results, nat_traversal/[miniupnpc, natpmp],
|
results, nat_traversal/[miniupnpc, natpmp],
|
||||||
chronicles, json_serialization/std/net, chronos,
|
chronicles, json_serialization/std/net, chronos,
|
||||||
../common/utils, ./utils as netutils
|
../common/utils, ./utils as netutils
|
||||||
|
|
||||||
|
export results
|
||||||
|
|
||||||
type
|
type
|
||||||
NatStrategy* = enum
|
NatStrategy* = enum
|
||||||
NatAny
|
NatAny
|
||||||
|
@ -47,7 +49,7 @@ logScope:
|
||||||
|
|
||||||
## Also does threadvar initialisation.
|
## Also does threadvar initialisation.
|
||||||
## Must be called before redirectPorts() in each thread.
|
## Must be called before redirectPorts() in each thread.
|
||||||
proc getExternalIP*(natStrategy: NatStrategy, quiet = false): Option[IpAddress] =
|
proc getExternalIP*(natStrategy: NatStrategy, quiet = false): Opt[IpAddress] =
|
||||||
var externalIP: IpAddress
|
var externalIP: IpAddress
|
||||||
|
|
||||||
if natStrategy == NatAny or natStrategy == NatUpnp:
|
if natStrategy == NatAny or natStrategy == NatUpnp:
|
||||||
|
@ -83,7 +85,7 @@ proc getExternalIP*(natStrategy: NatStrategy, quiet = false): Option[IpAddress]
|
||||||
try:
|
try:
|
||||||
externalIP = parseIpAddress(ires.value)
|
externalIP = parseIpAddress(ires.value)
|
||||||
strategy = NatUpnp
|
strategy = NatUpnp
|
||||||
return some(externalIP)
|
return Opt.some(externalIP)
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
error "parseIpAddress() exception", err = e.msg
|
error "parseIpAddress() exception", err = e.msg
|
||||||
return
|
return
|
||||||
|
@ -102,7 +104,7 @@ proc getExternalIP*(natStrategy: NatStrategy, quiet = false): Option[IpAddress]
|
||||||
try:
|
try:
|
||||||
externalIP = parseIpAddress($(nires.value))
|
externalIP = parseIpAddress($(nires.value))
|
||||||
strategy = NatPmp
|
strategy = NatPmp
|
||||||
return some(externalIP)
|
return Opt.some(externalIP)
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
error "parseIpAddress() exception", err = e.msg
|
error "parseIpAddress() exception", err = e.msg
|
||||||
return
|
return
|
||||||
|
@ -113,7 +115,7 @@ proc getExternalIP*(natStrategy: NatStrategy, quiet = false): Option[IpAddress]
|
||||||
# Further more, we check if the bind address (user provided, or a "0.0.0.0"
|
# Further more, we check if the bind address (user provided, or a "0.0.0.0"
|
||||||
# default) is a public IP. That's a long shot, because code paths involving a
|
# default) is a public IP. That's a long shot, because code paths involving a
|
||||||
# user-provided bind address are not supposed to get here.
|
# user-provided bind address are not supposed to get here.
|
||||||
proc getRoutePrefSrc(bindIp: IpAddress): (Option[IpAddress], PrefSrcStatus) =
|
proc getRoutePrefSrc(bindIp: IpAddress): (Opt[IpAddress], PrefSrcStatus) =
|
||||||
let bindAddress = initTAddress(bindIp, Port(0))
|
let bindAddress = initTAddress(bindIp, Port(0))
|
||||||
|
|
||||||
if bindAddress.isAnyLocal():
|
if bindAddress.isAnyLocal():
|
||||||
|
@ -122,20 +124,20 @@ proc getRoutePrefSrc(bindIp: IpAddress): (Option[IpAddress], PrefSrcStatus) =
|
||||||
# No route was found, log error and continue without IP.
|
# No route was found, log error and continue without IP.
|
||||||
error "No routable IP address found, check your network connection",
|
error "No routable IP address found, check your network connection",
|
||||||
error = ip.error
|
error = ip.error
|
||||||
return (none(IpAddress), NoRoutingInfo)
|
return (Opt.none(IpAddress), NoRoutingInfo)
|
||||||
elif ip.get().isGlobalUnicast():
|
elif ip.get().isGlobalUnicast():
|
||||||
return (some(ip.get()), PrefSrcIsPublic)
|
return (Opt.some(ip.get()), PrefSrcIsPublic)
|
||||||
else:
|
else:
|
||||||
return (none(IpAddress), PrefSrcIsPrivate)
|
return (Opt.none(IpAddress), PrefSrcIsPrivate)
|
||||||
elif bindAddress.isGlobalUnicast():
|
elif bindAddress.isGlobalUnicast():
|
||||||
return (some(bindIp), BindAddressIsPublic)
|
return (Opt.some(bindIp), BindAddressIsPublic)
|
||||||
else:
|
else:
|
||||||
return (none(IpAddress), BindAddressIsPrivate)
|
return (Opt.none(IpAddress), BindAddressIsPrivate)
|
||||||
|
|
||||||
# Try to detect a public IP assigned to this host, before trying NAT traversal.
|
# Try to detect a public IP assigned to this host, before trying NAT traversal.
|
||||||
proc getPublicRoutePrefSrcOrExternalIP*(
|
proc getPublicRoutePrefSrcOrExternalIP*(
|
||||||
natStrategy: NatStrategy, bindIp: IpAddress, quiet = true):
|
natStrategy: NatStrategy, bindIp: IpAddress, quiet = true):
|
||||||
Option[IpAddress] =
|
Opt[IpAddress] =
|
||||||
let (prefSrcIp, prefSrcStatus) = getRoutePrefSrc(bindIp)
|
let (prefSrcIp, prefSrcStatus) = getRoutePrefSrc(bindIp)
|
||||||
|
|
||||||
case prefSrcStatus:
|
case prefSrcStatus:
|
||||||
|
@ -144,9 +146,9 @@ proc getPublicRoutePrefSrcOrExternalIP*(
|
||||||
of PrefSrcIsPrivate, BindAddressIsPrivate:
|
of PrefSrcIsPrivate, BindAddressIsPrivate:
|
||||||
let extIp = getExternalIP(natStrategy, quiet)
|
let extIp = getExternalIP(natStrategy, quiet)
|
||||||
if extIp.isSome:
|
if extIp.isSome:
|
||||||
return some(extIp.get)
|
return Opt.some(extIp.get)
|
||||||
|
|
||||||
proc doPortMapping(tcpPort, udpPort: Port, description: string): Option[(Port, Port)] {.gcsafe.} =
|
proc doPortMapping(tcpPort, udpPort: Port, description: string): Opt[(Port, Port)] {.gcsafe.} =
|
||||||
var
|
var
|
||||||
extTcpPort: Port
|
extTcpPort: Port
|
||||||
extUdpPort: Port
|
extUdpPort: Port
|
||||||
|
@ -196,7 +198,7 @@ proc doPortMapping(tcpPort, udpPort: Port, description: string): Option[(Port, P
|
||||||
extTcpPort = extPort
|
extTcpPort = extPort
|
||||||
of NatPmpProtocol.UDP:
|
of NatPmpProtocol.UDP:
|
||||||
extUdpPort = extPort
|
extUdpPort = extPort
|
||||||
return some((extTcpPort, extUdpPort))
|
return Opt.some((extTcpPort, extUdpPort))
|
||||||
|
|
||||||
type PortMappingArgs = tuple[tcpPort, udpPort: Port, description: string]
|
type PortMappingArgs = tuple[tcpPort, udpPort: Port, description: string]
|
||||||
var
|
var
|
||||||
|
@ -274,7 +276,7 @@ proc stopNatThread() {.noconv.} =
|
||||||
else:
|
else:
|
||||||
debug "NAT-PMP: deleted port mapping", externalPort = eport, internalPort = iport, protocol = protocol
|
debug "NAT-PMP: deleted port mapping", externalPort = eport, internalPort = iport, protocol = protocol
|
||||||
|
|
||||||
proc redirectPorts*(tcpPort, udpPort: Port, description: string): Option[(Port, Port)] =
|
proc redirectPorts*(tcpPort, udpPort: Port, description: string): Opt[(Port, Port)] =
|
||||||
result = doPortMapping(tcpPort, udpPort, description)
|
result = doPortMapping(tcpPort, udpPort, description)
|
||||||
if result.isSome:
|
if result.isSome:
|
||||||
(externalTcpPort, externalUdpPort) = result.get()
|
(externalTcpPort, externalUdpPort) = result.get()
|
||||||
|
@ -294,7 +296,7 @@ proc redirectPorts*(tcpPort, udpPort: Port, description: string): Option[(Port,
|
||||||
|
|
||||||
proc setupNat*(natStrategy: NatStrategy, tcpPort, udpPort: Port,
|
proc setupNat*(natStrategy: NatStrategy, tcpPort, udpPort: Port,
|
||||||
clientId: string):
|
clientId: string):
|
||||||
tuple[ip: Option[IpAddress], tcpPort, udpPort: Option[Port]] =
|
tuple[ip: Opt[IpAddress], tcpPort, udpPort: Opt[Port]] =
|
||||||
## Setup NAT port mapping and get external IP address.
|
## Setup NAT port mapping and get external IP address.
|
||||||
## If any of this fails, we don't return any IP address but do return the
|
## If any of this fails, we don't return any IP address but do return the
|
||||||
## original ports as best effort.
|
## original ports as best effort.
|
||||||
|
@ -308,13 +310,13 @@ proc setupNat*(natStrategy: NatStrategy, tcpPort, udpPort: Port,
|
||||||
description = clientId))
|
description = clientId))
|
||||||
if extPorts.isSome:
|
if extPorts.isSome:
|
||||||
let (extTcpPort, extUdpPort) = extPorts.get()
|
let (extTcpPort, extUdpPort) = extPorts.get()
|
||||||
(ip: some(ip), tcpPort: some(extTcpPort), udpPort: some(extUdpPort))
|
(ip: Opt.some(ip), tcpPort: Opt.some(extTcpPort), udpPort: Opt.some(extUdpPort))
|
||||||
else:
|
else:
|
||||||
warn "UPnP/NAT-PMP available but port forwarding failed"
|
warn "UPnP/NAT-PMP available but port forwarding failed"
|
||||||
(ip: none(IpAddress), tcpPort: some(tcpPort), udpPort: some(udpPort))
|
(ip: Opt.none(IpAddress), tcpPort: Opt.some(tcpPort), udpPort: Opt.some(udpPort))
|
||||||
else:
|
else:
|
||||||
warn "UPnP/NAT-PMP not available"
|
warn "UPnP/NAT-PMP not available"
|
||||||
(ip: none(IpAddress), tcpPort: some(tcpPort), udpPort: some(udpPort))
|
(ip: Opt.none(IpAddress), tcpPort: Opt.some(tcpPort), udpPort: Opt.some(udpPort))
|
||||||
|
|
||||||
type
|
type
|
||||||
NatConfig* = object
|
NatConfig* = object
|
||||||
|
@ -349,7 +351,7 @@ func completeCmdArg*(T: type NatConfig, val: string): seq[string] =
|
||||||
|
|
||||||
proc setupAddress*(natConfig: NatConfig, bindIp: IpAddress,
|
proc setupAddress*(natConfig: NatConfig, bindIp: IpAddress,
|
||||||
tcpPort, udpPort: Port, clientId: string):
|
tcpPort, udpPort: Port, clientId: string):
|
||||||
tuple[ip: Option[IpAddress], tcpPort, udpPort: Option[Port]]
|
tuple[ip: Opt[IpAddress], tcpPort, udpPort: Opt[Port]]
|
||||||
{.gcsafe.} =
|
{.gcsafe.} =
|
||||||
## Set-up of the external address via any of the ways as configured in
|
## Set-up of the external address via any of the ways as configured in
|
||||||
## `NatConfig`. In case all fails an error is logged and the bind ports are
|
## `NatConfig`. In case all fails an error is logged and the bind ports are
|
||||||
|
@ -359,7 +361,7 @@ proc setupAddress*(natConfig: NatConfig, bindIp: IpAddress,
|
||||||
|
|
||||||
if natConfig.hasExtIp:
|
if natConfig.hasExtIp:
|
||||||
# any required port redirection must be done by hand
|
# any required port redirection must be done by hand
|
||||||
return (some(natConfig.extIp), some(tcpPort), some(udpPort))
|
return (Opt.some(natConfig.extIp), Opt.some(tcpPort), Opt.some(udpPort))
|
||||||
|
|
||||||
case natConfig.nat:
|
case natConfig.nat:
|
||||||
of NatAny:
|
of NatAny:
|
||||||
|
@ -367,7 +369,7 @@ proc setupAddress*(natConfig: NatConfig, bindIp: IpAddress,
|
||||||
|
|
||||||
case prefSrcStatus:
|
case prefSrcStatus:
|
||||||
of NoRoutingInfo, PrefSrcIsPublic, BindAddressIsPublic:
|
of NoRoutingInfo, PrefSrcIsPublic, BindAddressIsPublic:
|
||||||
return (prefSrcIp, some(tcpPort), some(udpPort))
|
return (prefSrcIp, Opt.some(tcpPort), Opt.some(udpPort))
|
||||||
of PrefSrcIsPrivate, BindAddressIsPrivate:
|
of PrefSrcIsPrivate, BindAddressIsPrivate:
|
||||||
return setupNat(natConfig.nat, tcpPort, udpPort, clientId)
|
return setupNat(natConfig.nat, tcpPort, udpPort, clientId)
|
||||||
of NatNone:
|
of NatNone:
|
||||||
|
@ -375,12 +377,12 @@ proc setupAddress*(natConfig: NatConfig, bindIp: IpAddress,
|
||||||
|
|
||||||
case prefSrcStatus:
|
case prefSrcStatus:
|
||||||
of NoRoutingInfo, PrefSrcIsPublic, BindAddressIsPublic:
|
of NoRoutingInfo, PrefSrcIsPublic, BindAddressIsPublic:
|
||||||
return (prefSrcIp, some(tcpPort), some(udpPort))
|
return (prefSrcIp, Opt.some(tcpPort), Opt.some(udpPort))
|
||||||
of PrefSrcIsPrivate:
|
of PrefSrcIsPrivate:
|
||||||
error "No public IP address found. Should not use --nat:none option"
|
error "No public IP address found. Should not use --nat:none option"
|
||||||
return (none(IpAddress), some(tcpPort), some(udpPort))
|
return (Opt.none(IpAddress), Opt.some(tcpPort), Opt.some(udpPort))
|
||||||
of BindAddressIsPrivate:
|
of BindAddressIsPrivate:
|
||||||
error "Bind IP is not a public IP address. Should not use --nat:none option"
|
error "Bind IP is not a public IP address. Should not use --nat:none option"
|
||||||
return (none(IpAddress), some(tcpPort), some(udpPort))
|
return (Opt.none(IpAddress), Opt.some(tcpPort), Opt.some(udpPort))
|
||||||
of NatUpnp, NatPmp:
|
of NatUpnp, NatPmp:
|
||||||
return setupNat(natConfig.nat, tcpPort, udpPort, clientId)
|
return setupNat(natConfig.nat, tcpPort, udpPort, clientId)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
# Ethereum P2P
|
# Ethereum P2P
|
||||||
# (c) Copyright 2018-2023
|
# (c) Copyright 2018-2024
|
||||||
# Status Research & Development GmbH
|
# Status Research & Development GmbH
|
||||||
#
|
#
|
||||||
# Licensed under either of
|
# Licensed under either of
|
||||||
|
@ -14,7 +14,8 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
nimcrypto/[rijndael, keccak, utils],
|
nimcrypto/[rijndael, keccak, utils],
|
||||||
stew/[arrayops, byteutils, endians2, objects, results],
|
stew/[arrayops, byteutils, endians2, objects],
|
||||||
|
results,
|
||||||
".."/[keys, rlp],
|
".."/[keys, rlp],
|
||||||
./ecies
|
./ecies
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# nim-eth
|
# nim-eth
|
||||||
# Copyright (c) 2018-2023 Status Research & Development GmbH
|
# Copyright (c) 2018-2024 Status Research & Development GmbH
|
||||||
# Licensed and distributed under either of
|
# Licensed and distributed under either of
|
||||||
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
||||||
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
||||||
|
@ -10,7 +10,7 @@
|
||||||
import
|
import
|
||||||
std/[times, net],
|
std/[times, net],
|
||||||
chronos, stint, nimcrypto/keccak, chronicles,
|
chronos, stint, nimcrypto/keccak, chronicles,
|
||||||
stew/[objects, results],
|
stew/objects, results,
|
||||||
".."/[keys, rlp],
|
".."/[keys, rlp],
|
||||||
"."/[kademlia, enode]
|
"."/[kademlia, enode]
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# nim-eth - Node Discovery Protocol v5
|
# nim-eth - Node Discovery Protocol v5
|
||||||
# Copyright (c) 2020-2023 Status Research & Development GmbH
|
# Copyright (c) 2020-2024 Status Research & Development GmbH
|
||||||
# Licensed and distributed under either of
|
# Licensed and distributed under either of
|
||||||
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
||||||
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
||||||
|
@ -14,7 +14,7 @@
|
||||||
{.push raises: [].}
|
{.push raises: [].}
|
||||||
|
|
||||||
import
|
import
|
||||||
std/[tables, options, hashes, net],
|
std/[tables, hashes, net],
|
||||||
nimcrypto/[bcmode, rijndael, sha2], stint, chronicles,
|
nimcrypto/[bcmode, rijndael, sha2], stint, chronicles,
|
||||||
stew/[byteutils, endians2], metrics,
|
stew/[byteutils, endians2], metrics,
|
||||||
results,
|
results,
|
||||||
|
@ -23,7 +23,7 @@ import
|
||||||
|
|
||||||
from stew/objects import checkedEnumAssign
|
from stew/objects import checkedEnumAssign
|
||||||
|
|
||||||
export keys
|
export keys, results
|
||||||
|
|
||||||
declareCounter discovery_session_lru_cache_hits, "Session LRU cache hits"
|
declareCounter discovery_session_lru_cache_hits, "Session LRU cache hits"
|
||||||
declareCounter discovery_session_lru_cache_misses, "Session LRU cache misses"
|
declareCounter discovery_session_lru_cache_misses, "Session LRU cache misses"
|
||||||
|
@ -68,7 +68,7 @@ type
|
||||||
|
|
||||||
Challenge* = object
|
Challenge* = object
|
||||||
whoareyouData*: WhoareyouData
|
whoareyouData*: WhoareyouData
|
||||||
pubkey*: Option[PublicKey]
|
pubkey*: Opt[PublicKey]
|
||||||
|
|
||||||
StaticHeader* = object
|
StaticHeader* = object
|
||||||
flag: Flag
|
flag: Flag
|
||||||
|
@ -87,7 +87,7 @@ type
|
||||||
Packet* = object
|
Packet* = object
|
||||||
case flag*: Flag
|
case flag*: Flag
|
||||||
of OrdinaryMessage:
|
of OrdinaryMessage:
|
||||||
messageOpt*: Option[Message]
|
messageOpt*: Opt[Message]
|
||||||
requestNonce*: AESGCMNonce
|
requestNonce*: AESGCMNonce
|
||||||
srcId*: NodeId
|
srcId*: NodeId
|
||||||
of Whoareyou:
|
of Whoareyou:
|
||||||
|
@ -163,10 +163,10 @@ proc encryptGCM*(key: AesKey, nonce, pt, authData: openArray[byte]): seq[byte] =
|
||||||
ectx.clear()
|
ectx.clear()
|
||||||
|
|
||||||
proc decryptGCM*(key: AesKey, nonce, ct, authData: openArray[byte]):
|
proc decryptGCM*(key: AesKey, nonce, ct, authData: openArray[byte]):
|
||||||
Option[seq[byte]] =
|
Opt[seq[byte]] =
|
||||||
if ct.len <= gcmTagSize:
|
if ct.len <= gcmTagSize:
|
||||||
debug "cipher is missing tag", len = ct.len
|
debug "cipher is missing tag", len = ct.len
|
||||||
return
|
return Opt.none(seq[byte])
|
||||||
|
|
||||||
var dctx: GCM[aes128]
|
var dctx: GCM[aes128]
|
||||||
dctx.init(key, nonce, authData)
|
dctx.init(key, nonce, authData)
|
||||||
|
@ -177,9 +177,9 @@ proc decryptGCM*(key: AesKey, nonce, ct, authData: openArray[byte]):
|
||||||
dctx.clear()
|
dctx.clear()
|
||||||
|
|
||||||
if tag != ct.toOpenArray(ct.len - gcmTagSize, ct.high):
|
if tag != ct.toOpenArray(ct.len - gcmTagSize, ct.high):
|
||||||
return
|
return Opt.none(seq[byte])
|
||||||
|
|
||||||
return some(res)
|
Opt.some(res)
|
||||||
|
|
||||||
proc encryptHeader*(id: NodeId, iv, header: openArray[byte]): seq[byte] =
|
proc encryptHeader*(id: NodeId, iv, header: openArray[byte]): seq[byte] =
|
||||||
var ectx: CTR[aes128]
|
var ectx: CTR[aes128]
|
||||||
|
@ -247,7 +247,7 @@ proc encodeMessagePacket*(rng: var HmacDrbgContext, c: var Codec,
|
||||||
|
|
||||||
proc encodeWhoareyouPacket*(rng: var HmacDrbgContext, c: var Codec,
|
proc encodeWhoareyouPacket*(rng: var HmacDrbgContext, c: var Codec,
|
||||||
toId: NodeId, toAddr: Address, requestNonce: AESGCMNonce, recordSeq: uint64,
|
toId: NodeId, toAddr: Address, requestNonce: AESGCMNonce, recordSeq: uint64,
|
||||||
pubkey: Option[PublicKey]): seq[byte] =
|
pubkey: Opt[PublicKey]): seq[byte] =
|
||||||
let
|
let
|
||||||
idNonce = rng.generate(IdNonce)
|
idNonce = rng.generate(IdNonce)
|
||||||
|
|
||||||
|
@ -414,7 +414,7 @@ proc decodeMessagePacket(c: var Codec, fromAddr: Address, nonce: AESGCMNonce,
|
||||||
let message = ? decodeMessage(pt.get())
|
let message = ? decodeMessage(pt.get())
|
||||||
|
|
||||||
return ok(Packet(flag: Flag.OrdinaryMessage,
|
return ok(Packet(flag: Flag.OrdinaryMessage,
|
||||||
messageOpt: some(message), requestNonce: nonce, srcId: srcId))
|
messageOpt: Opt.some(message), requestNonce: nonce, srcId: srcId))
|
||||||
|
|
||||||
proc decodeWhoareyouPacket(c: var Codec, nonce: AESGCMNonce,
|
proc decodeWhoareyouPacket(c: var Codec, nonce: AESGCMNonce,
|
||||||
iv, header, ct: openArray[byte]): DecodeResult[Packet] =
|
iv, header, ct: openArray[byte]): DecodeResult[Packet] =
|
||||||
|
@ -473,13 +473,13 @@ proc decodeHandshakePacket(c: var Codec, fromAddr: Address, nonce: AESGCMNonce,
|
||||||
ephKeyRaw = authdata[ephKeyPos..<ephKeyPos + int(ephKeySize)]
|
ephKeyRaw = authdata[ephKeyPos..<ephKeyPos + int(ephKeySize)]
|
||||||
ephKey = ? PublicKey.fromRaw(ephKeyRaw)
|
ephKey = ? PublicKey.fromRaw(ephKeyRaw)
|
||||||
|
|
||||||
var record: Option[enr.Record]
|
var record: Opt[enr.Record]
|
||||||
let recordPos = ephKeyPos + int(ephKeySize)
|
let recordPos = ephKeyPos + int(ephKeySize)
|
||||||
if authdata.len() > recordPos:
|
if authdata.len() > recordPos:
|
||||||
# There is possibly an ENR still
|
# There is possibly an ENR still
|
||||||
try:
|
try:
|
||||||
# Signature check of record happens in decode.
|
# Signature check of record happens in decode.
|
||||||
record = some(rlp.decode(authdata.toOpenArray(recordPos, authdata.high),
|
record = Opt.some(rlp.decode(authdata.toOpenArray(recordPos, authdata.high),
|
||||||
enr.Record))
|
enr.Record))
|
||||||
except RlpError, ValueError:
|
except RlpError, ValueError:
|
||||||
return err("Invalid encoded ENR")
|
return err("Invalid encoded ENR")
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
{.push raises: [].}
|
{.push raises: [].}
|
||||||
|
|
||||||
import
|
import
|
||||||
std/[strutils, macros, algorithm, options, net],
|
std/[strutils, macros, algorithm, net],
|
||||||
nimcrypto/[keccak, utils],
|
nimcrypto/[keccak, utils],
|
||||||
stew/base64,
|
stew/base64,
|
||||||
results,
|
results,
|
||||||
|
@ -38,13 +38,13 @@ type
|
||||||
|
|
||||||
TypedRecord* = object
|
TypedRecord* = object
|
||||||
id*: string
|
id*: string
|
||||||
secp256k1*: Option[array[33, byte]]
|
secp256k1*: Opt[array[33, byte]]
|
||||||
ip*: Option[array[4, byte]]
|
ip*: Opt[array[4, byte]]
|
||||||
ip6*: Option[array[16, byte]]
|
ip6*: Opt[array[16, byte]]
|
||||||
tcp*: Option[int]
|
tcp*: Opt[int]
|
||||||
udp*: Option[int]
|
udp*: Opt[int]
|
||||||
tcp6*: Option[int]
|
tcp6*: Opt[int]
|
||||||
udp6*: Option[int]
|
udp6*: Opt[int]
|
||||||
|
|
||||||
FieldKind = enum
|
FieldKind = enum
|
||||||
kString,
|
kString,
|
||||||
|
@ -168,8 +168,8 @@ template toFieldPair*(key: string, value: auto): FieldPair =
|
||||||
|
|
||||||
func addAddress(
|
func addAddress(
|
||||||
fields: var seq[FieldPair],
|
fields: var seq[FieldPair],
|
||||||
ip: Option[IpAddress],
|
ip: Opt[IpAddress],
|
||||||
tcpPort, udpPort: Option[Port]) =
|
tcpPort, udpPort: Opt[Port]) =
|
||||||
## Add address information in new fields. Incomplete address
|
## Add address information in new fields. Incomplete address
|
||||||
## information is allowed (example: Port but not IP) as that information
|
## information is allowed (example: Port but not IP) as that information
|
||||||
## might be already in the ENR or added later.
|
## might be already in the ENR or added later.
|
||||||
|
@ -193,8 +193,8 @@ func addAddress(
|
||||||
func init*(
|
func init*(
|
||||||
T: type Record,
|
T: type Record,
|
||||||
seqNum: uint64, pk: PrivateKey,
|
seqNum: uint64, pk: PrivateKey,
|
||||||
ip: Option[IpAddress],
|
ip: Opt[IpAddress],
|
||||||
tcpPort, udpPort: Option[Port],
|
tcpPort, udpPort: Opt[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
|
||||||
|
@ -260,24 +260,24 @@ func get*(r: Record, key: string, T: type): EnrResult[T] =
|
||||||
else:
|
else:
|
||||||
err("Key not found in ENR")
|
err("Key not found in ENR")
|
||||||
|
|
||||||
func get*(r: Record, T: type PublicKey): Option[T] =
|
func get*(r: Record, T: type PublicKey): Opt[T] =
|
||||||
## Get the `PublicKey` from provided `Record`. Return `none` when there is
|
## Get the `PublicKey` from provided `Record`. Return `none` when there is
|
||||||
## no `PublicKey` in the record.
|
## no `PublicKey` in the record.
|
||||||
var pubkeyField: Field
|
var pubkeyField: Field
|
||||||
if r.getField("secp256k1", pubkeyField) and pubkeyField.kind == kBytes:
|
if r.getField("secp256k1", pubkeyField) and pubkeyField.kind == kBytes:
|
||||||
let pk = PublicKey.fromRaw(pubkeyField.bytes)
|
let pk = PublicKey.fromRaw(pubkeyField.bytes)
|
||||||
if pk.isOk:
|
if pk.isOk:
|
||||||
return some pk[]
|
return Opt.some(pk[])
|
||||||
none(T)
|
Opt.none(T)
|
||||||
|
|
||||||
func find(r: Record, key: string): Option[int] =
|
func find(r: Record, key: string): Opt[int] =
|
||||||
## Search for key in record key:value pairs.
|
## Search for key in record key:value pairs.
|
||||||
##
|
##
|
||||||
## Returns some(index of key) if key is found in record. Else return none.
|
## Returns some(index of key) if key is found in record. Else return none.
|
||||||
for i, (k, v) in r.pairs:
|
for i, (k, v) in r.pairs:
|
||||||
if k == key:
|
if k == key:
|
||||||
return some(i)
|
return Opt.some(i)
|
||||||
none(int)
|
Opt.none(int)
|
||||||
|
|
||||||
func update*(
|
func update*(
|
||||||
record: var Record, pk: PrivateKey,
|
record: var Record, pk: PrivateKey,
|
||||||
|
@ -324,9 +324,9 @@ func update*(
|
||||||
func update*(
|
func update*(
|
||||||
r: var Record,
|
r: var Record,
|
||||||
pk: PrivateKey,
|
pk: PrivateKey,
|
||||||
ip: Option[IpAddress],
|
ip: Opt[IpAddress],
|
||||||
tcpPort: Option[Port] = none[Port](),
|
tcpPort: Opt[Port] = Opt.none(Port),
|
||||||
udpPort: Option[Port] = none[Port](),
|
udpPort: Opt[Port] = Opt.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
|
||||||
|
@ -345,15 +345,11 @@ func update*(
|
||||||
fields.add extraFields
|
fields.add extraFields
|
||||||
r.update(pk, fields)
|
r.update(pk, fields)
|
||||||
|
|
||||||
func tryGet*(r: Record, key: string, T: type): Option[T] =
|
func tryGet*(r: Record, key: string, T: type): Opt[T] =
|
||||||
## Get the value from the provided key.
|
## Get the value from the provided key.
|
||||||
## Return `none` if the key does not exist or if the value is invalid
|
## Return `none` if the key does not exist or if the value is invalid
|
||||||
## according to type `T`.
|
## according to type `T`.
|
||||||
let val = get(r, key, T)
|
get(r, key, T).optValue()
|
||||||
if val.isOk():
|
|
||||||
some(val.get())
|
|
||||||
else:
|
|
||||||
none(T)
|
|
||||||
|
|
||||||
func toTypedRecord*(r: Record): EnrResult[TypedRecord] =
|
func toTypedRecord*(r: Record): EnrResult[TypedRecord] =
|
||||||
let id = r.tryGet("id", string)
|
let id = r.tryGet("id", string)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# nim-eth - Node Discovery Protocol v5
|
# nim-eth - Node Discovery Protocol v5
|
||||||
# Copyright (c) 2021-2023 Status Research & Development GmbH
|
# Copyright (c) 2021-2024 Status Research & Development GmbH
|
||||||
# Licensed and distributed under either of
|
# Licensed and distributed under either of
|
||||||
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
||||||
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
||||||
|
@ -18,11 +18,12 @@
|
||||||
{.push raises: [].}
|
{.push raises: [].}
|
||||||
|
|
||||||
import
|
import
|
||||||
std/[tables, options],
|
std/tables,
|
||||||
|
results,
|
||||||
chronos,
|
chronos,
|
||||||
./node
|
./node
|
||||||
|
|
||||||
export options
|
export results
|
||||||
|
|
||||||
const IpVoteTimeout = 5.minutes ## Duration until a vote expires
|
const IpVoteTimeout = 5.minutes ## Duration until a vote expires
|
||||||
|
|
||||||
|
@ -45,7 +46,7 @@ proc insert*(ipvote: var IpVote, key: NodeId, address: Address) =
|
||||||
## can only hold 1 vote.
|
## can only hold 1 vote.
|
||||||
ipvote.votes[key] = (address, now(chronos.Moment) + IpVoteTimeout)
|
ipvote.votes[key] = (address, now(chronos.Moment) + IpVoteTimeout)
|
||||||
|
|
||||||
proc majority*(ipvote: var IpVote): Option[Address] =
|
proc majority*(ipvote: var IpVote): Opt[Address] =
|
||||||
## Get the majority of votes on an address. Pruning of votes older than
|
## Get the majority of votes on an address. Pruning of votes older than
|
||||||
## `IpVoteTime` will be done before the majority count.
|
## `IpVoteTime` will be done before the majority count.
|
||||||
## Note: When there is a draw the selected "majority" will depend on whichever
|
## Note: When there is a draw the selected "majority" will depend on whichever
|
||||||
|
@ -66,11 +67,11 @@ proc majority*(ipvote: var IpVote): Option[Address] =
|
||||||
ipvote.votes.del(id)
|
ipvote.votes.del(id)
|
||||||
|
|
||||||
if ipCount.len <= 0:
|
if ipCount.len <= 0:
|
||||||
return none(Address)
|
return Opt.none(Address)
|
||||||
|
|
||||||
let (address, count) = ipCount.largest()
|
let (address, count) = ipCount.largest()
|
||||||
|
|
||||||
if uint(count) >= ipvote.threshold:
|
if uint(count) >= ipvote.threshold:
|
||||||
some(address)
|
Opt.some(address)
|
||||||
else:
|
else:
|
||||||
none(Address)
|
Opt.none(Address)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# nim-eth
|
# nim-eth
|
||||||
# Copyright (c) 2020-2023 Status Research & Development GmbH
|
# Copyright (c) 2020-2024 Status Research & Development GmbH
|
||||||
# Licensed and distributed under either of
|
# Licensed and distributed under either of
|
||||||
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
||||||
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
||||||
|
@ -8,7 +8,9 @@
|
||||||
|
|
||||||
{.push raises: [].}
|
{.push raises: [].}
|
||||||
|
|
||||||
import std/[tables, lists, options]
|
import std/[tables, lists], results
|
||||||
|
|
||||||
|
export results
|
||||||
|
|
||||||
type
|
type
|
||||||
LRUCache*[K, V] = object of RootObj
|
LRUCache*[K, V] = object of RootObj
|
||||||
|
@ -19,14 +21,14 @@ type
|
||||||
func init*[K, V](T: type LRUCache[K, V], capacity: int): LRUCache[K, V] =
|
func init*[K, V](T: type LRUCache[K, V], capacity: int): LRUCache[K, V] =
|
||||||
LRUCache[K, V](capacity: capacity) # Table and list init is done default
|
LRUCache[K, V](capacity: capacity) # Table and list init is done default
|
||||||
|
|
||||||
func get*[K, V](lru: var LRUCache[K, V], key: K): Option[V] =
|
func get*[K, V](lru: var LRUCache[K, V], key: K): Opt[V] =
|
||||||
let node = lru.table.getOrDefault(key, nil)
|
let node = lru.table.getOrDefault(key, nil)
|
||||||
if node.isNil:
|
if node.isNil:
|
||||||
return none(V)
|
return Opt.none(V)
|
||||||
|
|
||||||
lru.list.remove(node)
|
lru.list.remove(node)
|
||||||
lru.list.prepend(node)
|
lru.list.prepend(node)
|
||||||
return some(node.value[1])
|
return Opt.some(node.value[1])
|
||||||
|
|
||||||
func put*[K, V](lru: var LRUCache[K, V], key: K, value: V) =
|
func put*[K, V](lru: var LRUCache[K, V], key: K, value: V) =
|
||||||
let node = lru.table.getOrDefault(key, nil)
|
let node = lru.table.getOrDefault(key, nil)
|
||||||
|
|
|
@ -9,11 +9,11 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
std/[hashes, net],
|
std/[hashes, net],
|
||||||
nimcrypto/keccak, stint, chronos, chronicles,
|
nimcrypto/keccak, stint, chronos, chronicles, results,
|
||||||
../../keys, ../../net/utils,
|
../../keys, ../../net/utils,
|
||||||
./enr
|
./enr
|
||||||
|
|
||||||
export stint
|
export stint, results
|
||||||
|
|
||||||
type
|
type
|
||||||
NodeId* = UInt256
|
NodeId* = UInt256
|
||||||
|
@ -25,7 +25,7 @@ type
|
||||||
Node* = ref object
|
Node* = ref object
|
||||||
id*: NodeId
|
id*: NodeId
|
||||||
pubkey*: PublicKey
|
pubkey*: PublicKey
|
||||||
address*: Option[Address]
|
address*: Opt[Address]
|
||||||
record*: Record
|
record*: Record
|
||||||
seen*: bool ## Indicates if there was at least one successful
|
seen*: bool ## Indicates if there was at least one successful
|
||||||
## request-response with this node.
|
## request-response with this node.
|
||||||
|
@ -53,28 +53,28 @@ func newNode*(r: Record): Result[Node, cstring] =
|
||||||
let a = Address(ip: ipv4(tr.ip.get()), port: Port(tr.udp.get()))
|
let a = Address(ip: ipv4(tr.ip.get()), port: Port(tr.udp.get()))
|
||||||
|
|
||||||
ok(Node(id: pk.get().toNodeId(), pubkey: pk.get(), record: r,
|
ok(Node(id: pk.get().toNodeId(), pubkey: pk.get(), record: r,
|
||||||
address: some(a)))
|
address: Opt.some(a)))
|
||||||
else:
|
else:
|
||||||
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: Opt.none(Address)))
|
||||||
|
|
||||||
func update*(n: Node, pk: PrivateKey, ip: Option[IpAddress],
|
func update*(n: Node, pk: PrivateKey, ip: Opt[IpAddress],
|
||||||
tcpPort: Option[Port] = none[Port](),
|
tcpPort: Opt[Port] = Opt.none(Port),
|
||||||
udpPort: Option[Port] = none[Port](),
|
udpPort: Opt[Port] = Opt.none(Port),
|
||||||
extraFields: openArray[FieldPair] = []): 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():
|
||||||
if udpPort.isSome():
|
if udpPort.isSome():
|
||||||
let a = Address(ip: ip.get(), port: udpPort.get())
|
let a = Address(ip: ip.get(), port: udpPort.get())
|
||||||
n.address = some(a)
|
n.address = Opt.some(a)
|
||||||
elif n.address.isSome():
|
elif n.address.isSome():
|
||||||
let a = Address(ip: ip.get(), port: n.address.get().port)
|
let a = Address(ip: ip.get(), port: n.address.get().port)
|
||||||
n.address = some(a)
|
n.address = Opt.some(a)
|
||||||
else:
|
else:
|
||||||
n.address = none(Address)
|
n.address = Opt.none(Address)
|
||||||
else:
|
else:
|
||||||
n.address = none(Address)
|
n.address = Opt.none(Address)
|
||||||
|
|
||||||
ok()
|
ok()
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
{.push raises: [].}
|
{.push raises: [].}
|
||||||
|
|
||||||
import
|
import
|
||||||
std/[sets, options, net],
|
std/[sets, net],
|
||||||
results, chronicles, chronos,
|
results, chronicles, chronos,
|
||||||
../../net/utils,
|
../../net/utils,
|
||||||
"."/[node, enr, routing_table]
|
"."/[node, enr, routing_table]
|
||||||
|
@ -32,7 +32,7 @@ func validIp(sender, address: IpAddress): bool =
|
||||||
|
|
||||||
proc verifyNodesRecords(
|
proc verifyNodesRecords(
|
||||||
enrs: openArray[Record], src: Node, nodesLimit: int,
|
enrs: openArray[Record], src: Node, nodesLimit: int,
|
||||||
distances: Option[seq[uint16]]): seq[Node] =
|
distances: Opt[seq[uint16]]): seq[Node] =
|
||||||
## Verify and convert ENRs to a sequence of nodes. Only ENRs that pass
|
## Verify and convert ENRs to a sequence of nodes. Only ENRs that pass
|
||||||
## verification will be added. ENRs are verified for duplicates, invalid
|
## verification will be added. ENRs are verified for duplicates, invalid
|
||||||
## addresses and invalid distances if those are specified.
|
## addresses and invalid distances if those are specified.
|
||||||
|
@ -86,9 +86,9 @@ proc verifyNodesRecords(
|
||||||
|
|
||||||
proc verifyNodesRecords*(
|
proc verifyNodesRecords*(
|
||||||
enrs: openArray[Record], src: Node, nodesLimit: int): seq[Node] =
|
enrs: openArray[Record], src: Node, nodesLimit: int): seq[Node] =
|
||||||
verifyNodesRecords(enrs, src, nodesLimit, none[seq[uint16]]())
|
verifyNodesRecords(enrs, src, nodesLimit, Opt.none(seq[uint16]))
|
||||||
|
|
||||||
proc verifyNodesRecords*(
|
proc verifyNodesRecords*(
|
||||||
enrs: openArray[Record], src: Node, nodesLimit: int,
|
enrs: openArray[Record], src: Node, nodesLimit: int,
|
||||||
distances: seq[uint16]): seq[Node] =
|
distances: seq[uint16]): seq[Node] =
|
||||||
verifyNodesRecords(enrs, src, nodesLimit, some[seq[uint16]](distances))
|
verifyNodesRecords(enrs, src, nodesLimit, Opt.some(distances))
|
||||||
|
|
|
@ -81,7 +81,7 @@
|
||||||
{.push raises: [].}
|
{.push raises: [].}
|
||||||
|
|
||||||
import
|
import
|
||||||
std/[tables, sets, options, math, sequtils, algorithm],
|
std/[tables, sets, math, sequtils, algorithm],
|
||||||
json_serialization/std/net,
|
json_serialization/std/net,
|
||||||
results, chronicles, chronos, stint, metrics,
|
results, chronicles, chronos, stint, metrics,
|
||||||
".."/../[rlp, keys],
|
".."/../[rlp, keys],
|
||||||
|
@ -89,7 +89,7 @@ import
|
||||||
ip_vote, nodes_verification]
|
ip_vote, nodes_verification]
|
||||||
|
|
||||||
export
|
export
|
||||||
options, results, node, enr, encoding.maxDiscv5PacketSize
|
results, node, enr, encoding.maxDiscv5PacketSize
|
||||||
|
|
||||||
declareCounter discovery_message_requests_outgoing,
|
declareCounter discovery_message_requests_outgoing,
|
||||||
"Discovery protocol outgoing message requests", labels = ["response"]
|
"Discovery protocol outgoing message requests", labels = ["response"]
|
||||||
|
@ -141,7 +141,7 @@ type
|
||||||
pendingRequests: Table[AESGCMNonce, PendingRequest]
|
pendingRequests: Table[AESGCMNonce, PendingRequest]
|
||||||
routingTable*: RoutingTable
|
routingTable*: RoutingTable
|
||||||
codec*: Codec
|
codec*: Codec
|
||||||
awaitedMessages: Table[(NodeId, RequestId), Future[Option[Message]]]
|
awaitedMessages: Table[(NodeId, RequestId), Future[Opt[Message]]]
|
||||||
refreshLoop: Future[void]
|
refreshLoop: Future[void]
|
||||||
revalidateLoop: Future[void]
|
revalidateLoop: Future[void]
|
||||||
ipMajorityLoop: Future[void]
|
ipMajorityLoop: Future[void]
|
||||||
|
@ -178,8 +178,8 @@ const
|
||||||
responseTimeout: defaultResponseTimeout
|
responseTimeout: defaultResponseTimeout
|
||||||
)
|
)
|
||||||
|
|
||||||
chronicles.formatIt(Option[Port]): $it
|
chronicles.formatIt(Opt[Port]): $it
|
||||||
chronicles.formatIt(Option[IpAddress]): $it
|
chronicles.formatIt(Opt[IpAddress]): $it
|
||||||
|
|
||||||
proc addNode*(d: Protocol, node: Node): bool =
|
proc addNode*(d: Protocol, node: Node): bool =
|
||||||
## Add `Node` to discovery routing table.
|
## Add `Node` to discovery routing table.
|
||||||
|
@ -383,9 +383,9 @@ proc handleMessage(
|
||||||
trace "Received unimplemented message kind", kind = message.kind,
|
trace "Received unimplemented message kind", kind = message.kind,
|
||||||
origin = fromAddr
|
origin = fromAddr
|
||||||
else:
|
else:
|
||||||
var waiter: Future[Option[Message]]
|
var waiter: Future[Opt[Message]]
|
||||||
if d.awaitedMessages.take((srcId, message.reqId), waiter):
|
if d.awaitedMessages.take((srcId, message.reqId), waiter):
|
||||||
waiter.complete(some(message))
|
waiter.complete(Opt.some(message))
|
||||||
else:
|
else:
|
||||||
discovery_unsolicited_messages.inc()
|
discovery_unsolicited_messages.inc()
|
||||||
trace "Timed out or unrequested message", kind = message.kind,
|
trace "Timed out or unrequested message", kind = message.kind,
|
||||||
|
@ -404,10 +404,12 @@ proc sendWhoareyou(d: Protocol, toId: NodeId, a: Address,
|
||||||
let key = HandshakeKey(nodeId: toId, address: a)
|
let key = HandshakeKey(nodeId: toId, address: a)
|
||||||
if not d.codec.hasHandshake(key):
|
if not d.codec.hasHandshake(key):
|
||||||
let
|
let
|
||||||
recordSeq = if node.isSome(): node.get().record.seqNum
|
recordSeq =
|
||||||
else: 0
|
if node.isSome():
|
||||||
pubkey = if node.isSome(): some(node.get().pubkey)
|
node.get().record.seqNum
|
||||||
else: none(PublicKey)
|
else:
|
||||||
|
0
|
||||||
|
pubkey = node.map(proc(node: Node): PublicKey = node.pubkey)
|
||||||
|
|
||||||
let data = encodeWhoareyouPacket(d.rng[], d.codec, toId, a, requestNonce,
|
let data = encodeWhoareyouPacket(d.rng[], d.codec, toId, a, requestNonce,
|
||||||
recordSeq, pubkey)
|
recordSeq, pubkey)
|
||||||
|
@ -504,13 +506,13 @@ proc registerRequest(d: Protocol, n: Node, message: seq[byte],
|
||||||
d.pendingRequests.del(nonce)
|
d.pendingRequests.del(nonce)
|
||||||
|
|
||||||
proc waitMessage(d: Protocol, fromNode: Node, reqId: RequestId):
|
proc waitMessage(d: Protocol, fromNode: Node, reqId: RequestId):
|
||||||
Future[Option[Message]] {.async: (raw: true, raises: [CancelledError]).} =
|
Future[Opt[Message]] {.async: (raw: true, raises: [CancelledError]).} =
|
||||||
let retFuture = Future[Option[Message]].Raising([CancelledError]).init("discv5.waitMessage")
|
let retFuture = Future[Opt[Message]].Raising([CancelledError]).init("discv5.waitMessage")
|
||||||
let key = (fromNode.id, reqId)
|
let key = (fromNode.id, reqId)
|
||||||
sleepAsync(d.responseTimeout).addCallback() do(data: pointer):
|
sleepAsync(d.responseTimeout).addCallback() do(data: pointer):
|
||||||
d.awaitedMessages.del(key)
|
d.awaitedMessages.del(key)
|
||||||
if not retFuture.finished:
|
if not retFuture.finished:
|
||||||
retFuture.complete(none(Message))
|
retFuture.complete(Opt.none(Message))
|
||||||
d.awaitedMessages[key] = retFuture
|
d.awaitedMessages[key] = retFuture
|
||||||
retFuture
|
retFuture
|
||||||
|
|
||||||
|
@ -881,7 +883,7 @@ proc updateExternalIp*(d: Protocol, extIp: IpAddress, udpPort: Port): bool =
|
||||||
let
|
let
|
||||||
previous = d.localNode.address
|
previous = d.localNode.address
|
||||||
res = d.localNode.update(d.privateKey,
|
res = d.localNode.update(d.privateKey,
|
||||||
ip = some(extIp), udpPort = some(udpPort))
|
ip = Opt.some(extIp), udpPort = Opt.some(udpPort))
|
||||||
|
|
||||||
if res.isErr:
|
if res.isErr:
|
||||||
warn "Failed updating ENR with newly discovered external address",
|
warn "Failed updating ENR with newly discovered external address",
|
||||||
|
@ -967,11 +969,11 @@ func init*(
|
||||||
|
|
||||||
proc newProtocol*(
|
proc newProtocol*(
|
||||||
privKey: PrivateKey,
|
privKey: PrivateKey,
|
||||||
enrIp: Option[IpAddress],
|
enrIp: Opt[IpAddress],
|
||||||
enrTcpPort, enrUdpPort: Option[Port],
|
enrTcpPort, enrUdpPort: Opt[Port],
|
||||||
localEnrFields: openArray[(string, seq[byte])] = [],
|
localEnrFields: openArray[(string, seq[byte])] = [],
|
||||||
bootstrapRecords: openArray[Record] = [],
|
bootstrapRecords: openArray[Record] = [],
|
||||||
previousRecord = none[enr.Record](),
|
previousRecord = Opt.none(enr.Record),
|
||||||
bindPort: Port,
|
bindPort: Port,
|
||||||
bindIp = IPv4_any(),
|
bindIp = IPv4_any(),
|
||||||
enrAutoUpdate = false,
|
enrAutoUpdate = false,
|
||||||
|
@ -1028,11 +1030,11 @@ proc newProtocol*(
|
||||||
|
|
||||||
proc newProtocol*(
|
proc newProtocol*(
|
||||||
privKey: PrivateKey,
|
privKey: PrivateKey,
|
||||||
enrIp: Option[IpAddress],
|
enrIp: Opt[IpAddress],
|
||||||
enrTcpPort, enrUdpPort: Option[Port],
|
enrTcpPort, enrUdpPort: Opt[Port],
|
||||||
localEnrFields: openArray[(string, seq[byte])] = [],
|
localEnrFields: openArray[(string, seq[byte])] = [],
|
||||||
bootstrapRecords: openArray[Record] = [],
|
bootstrapRecords: openArray[Record] = [],
|
||||||
previousRecord = none[enr.Record](),
|
previousRecord = Opt.none(enr.Record),
|
||||||
bindPort: Port,
|
bindPort: Port,
|
||||||
bindIp: Opt[IpAddress],
|
bindIp: Opt[IpAddress],
|
||||||
enrAutoUpdate = false,
|
enrAutoUpdate = false,
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
{.push raises: [].}
|
{.push raises: [].}
|
||||||
|
|
||||||
import
|
import
|
||||||
std/[options, net],
|
std/net,
|
||||||
stint, stew/endians2,
|
stint, stew/endians2,
|
||||||
node, lru
|
node, lru
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
# Ethereum P2P
|
# Ethereum P2P
|
||||||
# (c) Copyright 2018-2023
|
# (c) Copyright 2018-2024
|
||||||
# Status Research & Development GmbH
|
# Status Research & Development GmbH
|
||||||
#
|
#
|
||||||
# Licensed under either of
|
# Licensed under either of
|
||||||
|
@ -13,7 +13,7 @@
|
||||||
{.push raises: [].}
|
{.push raises: [].}
|
||||||
|
|
||||||
import
|
import
|
||||||
stew/[results, endians2],
|
stew/endians2, results,
|
||||||
nimcrypto/[rijndael, bcmode, hash, hmac, sha2, utils],
|
nimcrypto/[rijndael, bcmode, hash, hmac, sha2, utils],
|
||||||
../keys
|
../keys
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,7 @@ type
|
||||||
|
|
||||||
Packet* = object
|
Packet* = object
|
||||||
header*: PacketHeaderV1
|
header*: PacketHeaderV1
|
||||||
eack*: Option[SelectiveAckExtension]
|
eack*: Opt[SelectiveAckExtension]
|
||||||
payload*: seq[uint8]
|
payload*: seq[uint8]
|
||||||
|
|
||||||
TimeStampInfo* = object
|
TimeStampInfo* = object
|
||||||
|
@ -169,7 +169,7 @@ func decodePacket*(bytes: openArray[byte]): Result[Packet, string] =
|
||||||
|
|
||||||
return ok(Packet(
|
return ok(Packet(
|
||||||
header: header,
|
header: header,
|
||||||
eack: none[SelectiveAckExtension](),
|
eack: Opt.none(SelectiveAckExtension),
|
||||||
payload: payload))
|
payload: payload))
|
||||||
else:
|
else:
|
||||||
# packet with the selective ack extension
|
# packet with the selective ack extension
|
||||||
|
@ -200,7 +200,7 @@ func decodePacket*(bytes: openArray[byte]): Result[Packet, string] =
|
||||||
else:
|
else:
|
||||||
bytes[minimalHeaderSizeWithSelectiveAck..^1]
|
bytes[minimalHeaderSizeWithSelectiveAck..^1]
|
||||||
|
|
||||||
return ok(Packet(header: header, eack: some(extension), payload: payload))
|
return ok(Packet(header: header, eack: Opt.some(extension), payload: payload))
|
||||||
|
|
||||||
proc modifyTimeStampAndAckNr*(
|
proc modifyTimeStampAndAckNr*(
|
||||||
packetBytes: var seq[byte], newTimestamp: uint32, newAckNr: uint16) =
|
packetBytes: var seq[byte], newTimestamp: uint32, newAckNr: uint16) =
|
||||||
|
@ -229,7 +229,7 @@ proc synPacket*(
|
||||||
ackNr: 0'u16 # At start, no acks have been received
|
ackNr: 0'u16 # At start, no acks have been received
|
||||||
)
|
)
|
||||||
|
|
||||||
Packet(header: h, eack: none[SelectiveAckExtension](), payload: @[])
|
Packet(header: h, eack: Opt.none(SelectiveAckExtension), payload: @[])
|
||||||
|
|
||||||
proc ackPacket*(
|
proc ackPacket*(
|
||||||
seqNr: uint16,
|
seqNr: uint16,
|
||||||
|
@ -237,14 +237,14 @@ proc ackPacket*(
|
||||||
ackNr: uint16,
|
ackNr: uint16,
|
||||||
bufferSize: uint32,
|
bufferSize: uint32,
|
||||||
timestampDiff: uint32,
|
timestampDiff: uint32,
|
||||||
acksBitmask: Option[array[4, byte]] = none[array[4, byte]]()
|
acksBitmask: Opt[array[4, byte]] = Opt.none(array[4, byte])
|
||||||
): Packet =
|
): Packet =
|
||||||
|
|
||||||
let (extensionByte, extensionData) =
|
let (extensionByte, extensionData) =
|
||||||
if acksBitmask.isSome():
|
if acksBitmask.isSome():
|
||||||
(1'u8, some(SelectiveAckExtension(acks: acksBitmask.unsafeGet())))
|
(1'u8, Opt.some(SelectiveAckExtension(acks: acksBitmask.unsafeGet())))
|
||||||
else:
|
else:
|
||||||
(0'u8, none[SelectiveAckExtension]())
|
(0'u8, Opt.none(SelectiveAckExtension))
|
||||||
|
|
||||||
let h = PacketHeaderV1(
|
let h = PacketHeaderV1(
|
||||||
pType: ST_STATE,
|
pType: ST_STATE,
|
||||||
|
@ -280,7 +280,7 @@ proc dataPacket*(
|
||||||
ackNr: ackNr
|
ackNr: ackNr
|
||||||
)
|
)
|
||||||
|
|
||||||
Packet(header: h, eack: none[SelectiveAckExtension](), payload: payload)
|
Packet(header: h, eack: Opt.none(SelectiveAckExtension), payload: payload)
|
||||||
|
|
||||||
proc resetPacket*(
|
proc resetPacket*(
|
||||||
seqNr: uint16, sndConnectionId: uint16, ackNr: uint16): Packet =
|
seqNr: uint16, sndConnectionId: uint16, ackNr: uint16): Packet =
|
||||||
|
@ -298,7 +298,7 @@ proc resetPacket*(
|
||||||
ackNr: ackNr
|
ackNr: ackNr
|
||||||
)
|
)
|
||||||
|
|
||||||
Packet(header: h, eack: none[SelectiveAckExtension](), payload: @[])
|
Packet(header: h, eack: Opt.none(SelectiveAckExtension), payload: @[])
|
||||||
|
|
||||||
proc finPacket*(
|
proc finPacket*(
|
||||||
seqNr: uint16,
|
seqNr: uint16,
|
||||||
|
@ -319,4 +319,4 @@ proc finPacket*(
|
||||||
ackNr: ackNr
|
ackNr: ackNr
|
||||||
)
|
)
|
||||||
|
|
||||||
Packet(header: h, eack: none[SelectiveAckExtension](), payload: @[])
|
Packet(header: h, eack: Opt.none(SelectiveAckExtension), payload: @[])
|
||||||
|
|
|
@ -9,11 +9,12 @@
|
||||||
import
|
import
|
||||||
std/[hashes, sugar],
|
std/[hashes, sugar],
|
||||||
chronos, chronicles,
|
chronos, chronicles,
|
||||||
|
results,
|
||||||
../p2p/discoveryv5/[protocol, messages_encoding, encoding],
|
../p2p/discoveryv5/[protocol, messages_encoding, encoding],
|
||||||
./utp_router,
|
./utp_router,
|
||||||
../keys
|
../keys
|
||||||
|
|
||||||
export utp_router, protocol
|
export utp_router, protocol, results
|
||||||
|
|
||||||
logScope:
|
logScope:
|
||||||
topics = "eth utp utp_discv5_protocol"
|
topics = "eth utp utp_discv5_protocol"
|
||||||
|
@ -30,7 +31,7 @@ type
|
||||||
proc init*(T: type NodeAddress, nodeId: NodeId, address: Address): NodeAddress =
|
proc init*(T: type NodeAddress, nodeId: NodeId, address: Address): NodeAddress =
|
||||||
NodeAddress(nodeId: nodeId, address: address)
|
NodeAddress(nodeId: nodeId, address: address)
|
||||||
|
|
||||||
proc init*(T: type NodeAddress, node: Node): Option[NodeAddress] =
|
proc init*(T: type NodeAddress, node: Node): Opt[NodeAddress] =
|
||||||
node.address.map((address: Address) =>
|
node.address.map((address: Address) =>
|
||||||
NodeAddress(nodeId: node.id, address: address))
|
NodeAddress(nodeId: node.id, address: address))
|
||||||
|
|
||||||
|
|
|
@ -96,7 +96,7 @@ proc new*(
|
||||||
socketConfig: SocketConfig = SocketConfig.init(),
|
socketConfig: SocketConfig = SocketConfig.init(),
|
||||||
allowConnectionCb: AllowConnectionCallback[TransportAddress] = nil,
|
allowConnectionCb: AllowConnectionCallback[TransportAddress] = nil,
|
||||||
sendCallbackBuilder: SendCallbackBuilder = nil,
|
sendCallbackBuilder: SendCallbackBuilder = nil,
|
||||||
rng = newRng()): UtpProtocol {.raises: [CatchableError].} =
|
rng = newRng()): UtpProtocol {.raises: [TransportOsError].} =
|
||||||
|
|
||||||
doAssert(not(isNil(acceptConnectionCb)))
|
doAssert(not(isNil(acceptConnectionCb)))
|
||||||
|
|
||||||
|
@ -125,7 +125,7 @@ proc new*(
|
||||||
socketConfig: SocketConfig = SocketConfig.init(),
|
socketConfig: SocketConfig = SocketConfig.init(),
|
||||||
allowConnectionCb: AllowConnectionCallback[TransportAddress] = nil,
|
allowConnectionCb: AllowConnectionCallback[TransportAddress] = nil,
|
||||||
sendCallbackBuilder: SendCallbackBuilder = nil,
|
sendCallbackBuilder: SendCallbackBuilder = nil,
|
||||||
rng = newRng()): UtpProtocol {.raises: [CatchableError].} =
|
rng = newRng()): UtpProtocol {.raises: [TransportOsError].} =
|
||||||
GC_ref(udata)
|
GC_ref(udata)
|
||||||
UtpProtocol.new(
|
UtpProtocol.new(
|
||||||
acceptConnectionCb,
|
acceptConnectionCb,
|
||||||
|
|
|
@ -7,8 +7,9 @@
|
||||||
{.push raises: [].}
|
{.push raises: [].}
|
||||||
|
|
||||||
import
|
import
|
||||||
std/[tables, options, sugar],
|
std/tables,
|
||||||
chronos, chronicles, metrics,
|
chronos, chronicles, metrics,
|
||||||
|
results,
|
||||||
../keys,
|
../keys,
|
||||||
./utp_socket,
|
./utp_socket,
|
||||||
./packets
|
./packets
|
||||||
|
@ -67,18 +68,18 @@ const
|
||||||
# This should probably be in standard lib, it allows lazy composition of options
|
# This should probably be in standard lib, it allows lazy composition of options
|
||||||
# i.e one can write: O1 orElse O2 orElse O3, and chain will be evaluated to
|
# i.e one can write: O1 orElse O2 orElse O3, and chain will be evaluated to
|
||||||
# first option which isSome()
|
# first option which isSome()
|
||||||
template orElse[A](a: Option[A], b: Option[A]): Option[A] =
|
template orElse[A](a: Opt[A], b: Opt[A]): Opt[A] =
|
||||||
if (a.isSome()):
|
if (a.isSome()):
|
||||||
a
|
a
|
||||||
else:
|
else:
|
||||||
b
|
b
|
||||||
|
|
||||||
proc getUtpSocket[A](s: UtpRouter[A], k: UtpSocketKey[A]): Option[UtpSocket[A]] =
|
proc getUtpSocket[A](s: UtpRouter[A], k: UtpSocketKey[A]): Opt[UtpSocket[A]] =
|
||||||
let s = s.sockets.getOrDefault(k)
|
let s = s.sockets.getOrDefault(k)
|
||||||
if s == nil:
|
if s == nil:
|
||||||
none[UtpSocket[A]]()
|
Opt.none(UtpSocket[A])
|
||||||
else:
|
else:
|
||||||
some(s)
|
Opt.some(s)
|
||||||
|
|
||||||
proc deRegisterUtpSocket[A](s: UtpRouter[A], socket: UtpSocket[A]) =
|
proc deRegisterUtpSocket[A](s: UtpRouter[A], socket: UtpSocket[A]) =
|
||||||
s.sockets.del(socket.socketKey)
|
s.sockets.del(socket.socketKey)
|
||||||
|
@ -164,7 +165,7 @@ proc getUserData*[A, T](router: UtpRouter[A]): T =
|
||||||
# There are different possibilities on how the connection got established, need
|
# There are different possibilities on how the connection got established, need
|
||||||
# to check every case.
|
# to check every case.
|
||||||
proc getSocketOnReset[A](
|
proc getSocketOnReset[A](
|
||||||
r: UtpRouter[A], sender: A, id: uint16): Option[UtpSocket[A]] =
|
r: UtpRouter[A], sender: A, id: uint16): Opt[UtpSocket[A]] =
|
||||||
# id is our recv id
|
# id is our recv id
|
||||||
let recvKey = UtpSocketKey[A].init(sender, id)
|
let recvKey = UtpSocketKey[A].init(sender, id)
|
||||||
|
|
||||||
|
@ -176,8 +177,8 @@ proc getSocketOnReset[A](
|
||||||
let sendNoInitKey = UtpSocketKey[A].init(sender, id + 1)
|
let sendNoInitKey = UtpSocketKey[A].init(sender, id + 1)
|
||||||
|
|
||||||
r.getUtpSocket(recvKey)
|
r.getUtpSocket(recvKey)
|
||||||
.orElse(r.getUtpSocket(sendInitKey).filter(s => s.connectionIdSnd == id))
|
.orElse(r.getUtpSocket(sendInitKey).filter(proc(s: UtpSocket[A]): bool = s.connectionIdSnd == id))
|
||||||
.orElse(r.getUtpSocket(sendNoInitKey).filter(s => s.connectionIdSnd == id))
|
.orElse(r.getUtpSocket(sendNoInitKey).filter(proc(s: UtpSocket[A]): bool = s.connectionIdSnd == id))
|
||||||
|
|
||||||
proc shouldAllowConnection[A](
|
proc shouldAllowConnection[A](
|
||||||
r: UtpRouter[A], remoteAddress: A, connectionId: uint16): bool =
|
r: UtpRouter[A], remoteAddress: A, connectionId: uint16): bool =
|
||||||
|
|
|
@ -78,6 +78,8 @@ type
|
||||||
# to move the socket in `Connected` state.
|
# to move the socket in `Connected` state.
|
||||||
# If set to none, the incoming socket will immediately be set to `Connected`
|
# If set to none, the incoming socket will immediately be set to `Connected`
|
||||||
# state and will be able to transfer data.
|
# state and will be able to transfer data.
|
||||||
|
# TODO: Move to Opt but need to figure out current compile error:
|
||||||
|
# cannot instantiate: 'Opt[T]'; Maybe generic arguments are missing
|
||||||
incomingSocketReceiveTimeout*: Option[Duration]
|
incomingSocketReceiveTimeout*: Option[Duration]
|
||||||
|
|
||||||
# Timeout after which the send window will be reset to its minimal value
|
# Timeout after which the send window will be reset to its minimal value
|
||||||
|
@ -260,7 +262,7 @@ type
|
||||||
eventLoop: Future[void]
|
eventLoop: Future[void]
|
||||||
|
|
||||||
# timer which is started when peer max window drops below current packet size
|
# timer which is started when peer max window drops below current packet size
|
||||||
zeroWindowTimer: Option[Moment]
|
zeroWindowTimer: Opt[Moment]
|
||||||
|
|
||||||
# last measured delay between current local timestamp and remote sent
|
# last measured delay between current local timestamp and remote sent
|
||||||
# timestamp, in microseconds.
|
# timestamp, in microseconds.
|
||||||
|
@ -552,7 +554,7 @@ proc checkTimeouts(socket: UtpSocket) =
|
||||||
let remoteWindow = 2 * socket.socketConfig.payloadSize
|
let remoteWindow = 2 * socket.socketConfig.payloadSize
|
||||||
socket.maxRemoteWindow = remoteWindow
|
socket.maxRemoteWindow = remoteWindow
|
||||||
debug "Reset remote window to minimal value", remoteWindow
|
debug "Reset remote window to minimal value", remoteWindow
|
||||||
socket.zeroWindowTimer = none[Moment]()
|
socket.zeroWindowTimer = Opt.none(Moment)
|
||||||
|
|
||||||
if (currentTime > socket.rtoTimeout):
|
if (currentTime > socket.rtoTimeout):
|
||||||
debug "CheckTimeouts rto timeout",
|
debug "CheckTimeouts rto timeout",
|
||||||
|
@ -1086,9 +1088,9 @@ proc generateSelectiveAckBitMask*(socket: UtpSocket): array[4, byte] =
|
||||||
proc generateAckPacket*(socket: UtpSocket): Packet =
|
proc generateAckPacket*(socket: UtpSocket): Packet =
|
||||||
let bitmask =
|
let bitmask =
|
||||||
if (socket.reorderCount != 0 and (not socket.reachedFin)):
|
if (socket.reorderCount != 0 and (not socket.reachedFin)):
|
||||||
some(socket.generateSelectiveAckBitMask())
|
Opt.some(socket.generateSelectiveAckBitMask())
|
||||||
else:
|
else:
|
||||||
none[array[4, byte]]()
|
Opt.none(array[4, byte])
|
||||||
|
|
||||||
let bufferSize = socket.getRcvWindowSize()
|
let bufferSize = socket.getRcvWindowSize()
|
||||||
|
|
||||||
|
@ -1319,7 +1321,7 @@ proc processPacketInternal(socket: UtpSocket, p: Packet) =
|
||||||
# when zeroWindowTimer is hit and maxRemoteWindow still is equal
|
# when zeroWindowTimer is hit and maxRemoteWindow still is equal
|
||||||
# to 0 then it will be reset to the minimal value
|
# to 0 then it will be reset to the minimal value
|
||||||
socket.zeroWindowTimer =
|
socket.zeroWindowTimer =
|
||||||
some(timestampInfo.moment + socket.socketConfig.remoteWindowResetTimeout)
|
Opt.some(timestampInfo.moment + socket.socketConfig.remoteWindowResetTimeout)
|
||||||
|
|
||||||
debug "Remote window size dropped below packet size",
|
debug "Remote window size dropped below packet size",
|
||||||
currentTime = timestampInfo.moment,
|
currentTime = timestampInfo.moment,
|
||||||
|
@ -1988,7 +1990,7 @@ proc new[A](
|
||||||
closeCallbacks: newSeq[Future[void]](),
|
closeCallbacks: newSeq[Future[void]](),
|
||||||
pendingWrites: initDeque[WriteRequest](),
|
pendingWrites: initDeque[WriteRequest](),
|
||||||
eventQueue: newAsyncQueue[SocketEvent](),
|
eventQueue: newAsyncQueue[SocketEvent](),
|
||||||
zeroWindowTimer: none[Moment](),
|
zeroWindowTimer: Opt.none(Moment),
|
||||||
socketKey: UtpSocketKey.init(to, rcvId),
|
socketKey: UtpSocketKey.init(to, rcvId),
|
||||||
slowStart: true,
|
slowStart: true,
|
||||||
fastTimeout: false,
|
fastTimeout: false,
|
||||||
|
|
|
@ -13,13 +13,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(parseIpAddress("127.0.0.1")), some(Port(9000)),
|
Opt.some(parseIpAddress("127.0.0.1")), Opt.some(Port(9000)),
|
||||||
some(Port(9000))).expect("Properly initialized private key")
|
Opt.some(Port(9000))).expect("Properly initialized 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(parseIpAddress("127.0.0.1")), some(Port(9000)),
|
Opt.some(parseIpAddress("127.0.0.1")), Opt.some(Port(9000)),
|
||||||
some(Port(9000))).expect("Properly initialized private key")
|
Opt.some(Port(9000))).expect("Properly initialized 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,
|
||||||
|
|
|
@ -10,8 +10,8 @@ proc generate() =
|
||||||
let
|
let
|
||||||
rng = newRng()
|
rng = newRng()
|
||||||
privKey = PrivateKey.random(rng[])
|
privKey = PrivateKey.random(rng[])
|
||||||
ip = some(parseIpAddress("127.0.0.1"))
|
ip = Opt.some(parseIpAddress("127.0.0.1"))
|
||||||
port = some(Port(20301))
|
port = Opt.some(Port(20301))
|
||||||
|
|
||||||
block:
|
block:
|
||||||
let record = enr.Record.init(1, privKey, ip, port, port)[]
|
let record = enr.Record.init(1, privKey, ip, port, port)[]
|
||||||
|
|
|
@ -23,15 +23,15 @@ proc initDiscoveryNode*(
|
||||||
address: Address,
|
address: Address,
|
||||||
bootstrapRecords: openArray[Record] = [],
|
bootstrapRecords: openArray[Record] = [],
|
||||||
localEnrFields: openArray[(string, seq[byte])] = [],
|
localEnrFields: openArray[(string, seq[byte])] = [],
|
||||||
previousRecord = none[enr.Record]()):
|
previousRecord = Opt.none(enr.Record)):
|
||||||
discv5_protocol.Protocol =
|
discv5_protocol.Protocol =
|
||||||
# set bucketIpLimit to allow bucket split
|
# set bucketIpLimit to allow bucket split
|
||||||
let config = DiscoveryConfig.init(1000, 24, 5)
|
let config = DiscoveryConfig.init(1000, 24, 5)
|
||||||
|
|
||||||
let protocol = newProtocol(
|
let protocol = newProtocol(
|
||||||
privKey,
|
privKey,
|
||||||
some(address.ip),
|
Opt.some(address.ip),
|
||||||
some(address.port), some(address.port),
|
Opt.some(address.port), Opt.some(address.port),
|
||||||
bindPort = address.port,
|
bindPort = address.port,
|
||||||
bootstrapRecords = bootstrapRecords,
|
bootstrapRecords = bootstrapRecords,
|
||||||
localEnrFields = localEnrFields,
|
localEnrFields = localEnrFields,
|
||||||
|
@ -51,8 +51,8 @@ func generateNode*(privKey: PrivateKey, port: int = 20302,
|
||||||
ip: IpAddress = parseIpAddress("127.0.0.1"),
|
ip: IpAddress = parseIpAddress("127.0.0.1"),
|
||||||
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, Opt.some(ip),
|
||||||
some(port), some(port), localEnrFields).expect("Properly initialized private key")
|
Opt.some(port), Opt.some(port), localEnrFields).expect("Properly initialized private key")
|
||||||
result = newNode(enr).expect("Properly initialized node")
|
result = newNode(enr).expect("Properly initialized node")
|
||||||
|
|
||||||
proc generateNRandomNodes*(rng: var HmacDrbgContext, n: int): seq[Node] =
|
proc generateNRandomNodes*(rng: var HmacDrbgContext, n: int): seq[Node] =
|
||||||
|
|
|
@ -423,18 +423,18 @@ suite "Discovery v5 Tests":
|
||||||
test "New protocol with enr":
|
test "New protocol with enr":
|
||||||
let
|
let
|
||||||
privKey = PrivateKey.random(rng[])
|
privKey = PrivateKey.random(rng[])
|
||||||
ip = some(parseIpAddress("127.0.0.1"))
|
ip = Opt.some(parseIpAddress("127.0.0.1"))
|
||||||
port = Port(20301)
|
port = Port(20301)
|
||||||
node = newProtocol(privKey, ip, some(port), some(port), bindPort = port,
|
node = newProtocol(privKey, ip, Opt.some(port), Opt.some(port), bindPort = port,
|
||||||
rng = rng)
|
rng = rng)
|
||||||
noUpdatesNode = newProtocol(privKey, ip, some(port), some(port),
|
noUpdatesNode = newProtocol(privKey, ip, Opt.some(port), Opt.some(port),
|
||||||
bindPort = port, rng = rng, previousRecord = some(node.getRecord()))
|
bindPort = port, rng = rng, previousRecord = Opt.some(node.getRecord()))
|
||||||
updatesNode = newProtocol(privKey, ip, some(port), some(Port(20302)),
|
updatesNode = newProtocol(privKey, ip, Opt.some(port), Opt.some(Port(20302)),
|
||||||
bindPort = port, rng = rng,
|
bindPort = port, rng = rng,
|
||||||
previousRecord = some(noUpdatesNode.getRecord()))
|
previousRecord = Opt.some(noUpdatesNode.getRecord()))
|
||||||
moreUpdatesNode = newProtocol(privKey, ip, some(port), some(port),
|
moreUpdatesNode = newProtocol(privKey, ip, Opt.some(port), Opt.some(port),
|
||||||
bindPort = port, rng = rng, localEnrFields = {"addfield": @[byte 0]},
|
bindPort = port, rng = rng, localEnrFields = {"addfield": @[byte 0]},
|
||||||
previousRecord = some(updatesNode.getRecord()))
|
previousRecord = Opt.some(updatesNode.getRecord()))
|
||||||
check:
|
check:
|
||||||
node.getRecord().seqNum == 1
|
node.getRecord().seqNum == 1
|
||||||
noUpdatesNode.getRecord().seqNum == 1
|
noUpdatesNode.getRecord().seqNum == 1
|
||||||
|
@ -444,8 +444,8 @@ suite "Discovery v5 Tests":
|
||||||
# Defect (for now?) on incorrect key use
|
# Defect (for now?) on incorrect key use
|
||||||
expect ResultDefect:
|
expect ResultDefect:
|
||||||
let incorrectKeyUpdates = newProtocol(PrivateKey.random(rng[]),
|
let incorrectKeyUpdates = newProtocol(PrivateKey.random(rng[]),
|
||||||
ip, some(port), some(port), bindPort = port, rng = rng,
|
ip, Opt.some(port), Opt.some(port), bindPort = port, rng = rng,
|
||||||
previousRecord = some(updatesNode.getRecord()))
|
previousRecord = Opt.some(updatesNode.getRecord()))
|
||||||
|
|
||||||
asyncTest "Update node record with revalidate":
|
asyncTest "Update node record with revalidate":
|
||||||
let
|
let
|
||||||
|
@ -518,8 +518,8 @@ suite "Discovery v5 Tests":
|
||||||
let
|
let
|
||||||
port = Port(9000)
|
port = Port(9000)
|
||||||
srcRecord = enr.Record.init(1, PrivateKey.random(rng[]),
|
srcRecord = enr.Record.init(1, PrivateKey.random(rng[]),
|
||||||
some(parseIpAddress("11.12.13.14")),
|
Opt.some(parseIpAddress("11.12.13.14")),
|
||||||
some(port), some(port))[]
|
Opt.some(port), Opt.some(port))[]
|
||||||
srcNode = newNode(srcRecord)[]
|
srcNode = newNode(srcRecord)[]
|
||||||
pk = PrivateKey.random(rng[])
|
pk = PrivateKey.random(rng[])
|
||||||
targetDistance = @[logDistance(srcNode.id, pk.toPublicKey().toNodeId())]
|
targetDistance = @[logDistance(srcNode.id, pk.toPublicKey().toNodeId())]
|
||||||
|
@ -528,8 +528,8 @@ suite "Discovery v5 Tests":
|
||||||
block: # Duplicates
|
block: # Duplicates
|
||||||
let
|
let
|
||||||
record = enr.Record.init(
|
record = enr.Record.init(
|
||||||
1, pk, some(parseIpAddress("12.13.14.15")),
|
1, pk, Opt.some(parseIpAddress("12.13.14.15")),
|
||||||
some(port), some(port))[]
|
Opt.some(port), Opt.some(port))[]
|
||||||
|
|
||||||
# Exact duplicates
|
# Exact duplicates
|
||||||
var records = @[record, record]
|
var records = @[record, record]
|
||||||
|
@ -538,8 +538,8 @@ suite "Discovery v5 Tests":
|
||||||
|
|
||||||
# Node id duplicates
|
# Node id duplicates
|
||||||
let recordSameId = enr.Record.init(
|
let recordSameId = enr.Record.init(
|
||||||
1, pk, some(parseIpAddress("212.13.14.15")),
|
1, pk, Opt.some(parseIpAddress("212.13.14.15")),
|
||||||
some(port), some(port))[]
|
Opt.some(port), Opt.some(port))[]
|
||||||
records.add(recordSameId)
|
records.add(recordSameId)
|
||||||
nodes = verifyNodesRecords(records, srcNode, limit, targetDistance)
|
nodes = verifyNodesRecords(records, srcNode, limit, targetDistance)
|
||||||
check nodes.len == 1
|
check nodes.len == 1
|
||||||
|
@ -547,7 +547,7 @@ suite "Discovery v5 Tests":
|
||||||
block: # No address
|
block: # No address
|
||||||
let
|
let
|
||||||
recordNoAddress = enr.Record.init(
|
recordNoAddress = enr.Record.init(
|
||||||
1, pk, none(IpAddress), some(port), some(port))[]
|
1, pk, Opt.none(IpAddress), Opt.some(port), Opt.some(port))[]
|
||||||
records = [recordNoAddress]
|
records = [recordNoAddress]
|
||||||
test = verifyNodesRecords(records, srcNode, limit, targetDistance)
|
test = verifyNodesRecords(records, srcNode, limit, targetDistance)
|
||||||
check test.len == 0
|
check test.len == 0
|
||||||
|
@ -555,8 +555,8 @@ suite "Discovery v5 Tests":
|
||||||
block: # Invalid address - any local
|
block: # Invalid address - any local
|
||||||
let
|
let
|
||||||
recordInvalidAddress = enr.Record.init(
|
recordInvalidAddress = enr.Record.init(
|
||||||
1, pk, some(parseIpAddress("0.0.0.0")),
|
1, pk, Opt.some(parseIpAddress("0.0.0.0")),
|
||||||
some(port), some(port))[]
|
Opt.some(port), Opt.some(port))[]
|
||||||
records = [recordInvalidAddress]
|
records = [recordInvalidAddress]
|
||||||
test = verifyNodesRecords(records, srcNode, limit, targetDistance)
|
test = verifyNodesRecords(records, srcNode, limit, targetDistance)
|
||||||
check test.len == 0
|
check test.len == 0
|
||||||
|
@ -564,8 +564,8 @@ suite "Discovery v5 Tests":
|
||||||
block: # Invalid address - site local
|
block: # Invalid address - site local
|
||||||
let
|
let
|
||||||
recordInvalidAddress = enr.Record.init(
|
recordInvalidAddress = enr.Record.init(
|
||||||
1, pk, some(parseIpAddress("10.1.2.3")),
|
1, pk, Opt.some(parseIpAddress("10.1.2.3")),
|
||||||
some(port), some(port))[]
|
Opt.some(port), Opt.some(port))[]
|
||||||
records = [recordInvalidAddress]
|
records = [recordInvalidAddress]
|
||||||
test = verifyNodesRecords(records, srcNode, limit, targetDistance)
|
test = verifyNodesRecords(records, srcNode, limit, targetDistance)
|
||||||
check test.len == 0
|
check test.len == 0
|
||||||
|
@ -573,8 +573,8 @@ suite "Discovery v5 Tests":
|
||||||
block: # Invalid address - loopback
|
block: # Invalid address - loopback
|
||||||
let
|
let
|
||||||
recordInvalidAddress = enr.Record.init(
|
recordInvalidAddress = enr.Record.init(
|
||||||
1, pk, some(parseIpAddress("127.0.0.1")),
|
1, pk, Opt.some(parseIpAddress("127.0.0.1")),
|
||||||
some(port), some(port))[]
|
Opt.some(port), Opt.some(port))[]
|
||||||
records = [recordInvalidAddress]
|
records = [recordInvalidAddress]
|
||||||
test = verifyNodesRecords(records, srcNode, limit, targetDistance)
|
test = verifyNodesRecords(records, srcNode, limit, targetDistance)
|
||||||
check test.len == 0
|
check test.len == 0
|
||||||
|
@ -582,8 +582,8 @@ suite "Discovery v5 Tests":
|
||||||
block: # Invalid distance
|
block: # Invalid distance
|
||||||
let
|
let
|
||||||
recordInvalidDistance = enr.Record.init(
|
recordInvalidDistance = enr.Record.init(
|
||||||
1, pk, some(parseIpAddress("12.13.14.15")),
|
1, pk, Opt.some(parseIpAddress("12.13.14.15")),
|
||||||
some(port), some(port))[]
|
Opt.some(port), Opt.some(port))[]
|
||||||
records = [recordInvalidDistance]
|
records = [recordInvalidDistance]
|
||||||
test = verifyNodesRecords(records, srcNode, limit, @[0'u16])
|
test = verifyNodesRecords(records, srcNode, limit, @[0'u16])
|
||||||
check test.len == 0
|
check test.len == 0
|
||||||
|
@ -591,8 +591,8 @@ suite "Discovery v5 Tests":
|
||||||
block: # Invalid distance but distance validation is disabled
|
block: # Invalid distance but distance validation is disabled
|
||||||
let
|
let
|
||||||
recordInvalidDistance = enr.Record.init(
|
recordInvalidDistance = enr.Record.init(
|
||||||
1, pk, some(parseIpAddress("12.13.14.15")),
|
1, pk, Opt.some(parseIpAddress("12.13.14.15")),
|
||||||
some(port), some(port))[]
|
Opt.some(port), Opt.some(port))[]
|
||||||
records = [recordInvalidDistance]
|
records = [recordInvalidDistance]
|
||||||
test = verifyNodesRecords(records, srcNode, limit)
|
test = verifyNodesRecords(records, srcNode, limit)
|
||||||
check test.len == 1
|
check test.len == 1
|
||||||
|
@ -601,8 +601,8 @@ suite "Discovery v5 Tests":
|
||||||
let
|
let
|
||||||
port = Port(9000)
|
port = Port(9000)
|
||||||
srcRecord = enr.Record.init(1, PrivateKey.random(rng[]),
|
srcRecord = enr.Record.init(1, PrivateKey.random(rng[]),
|
||||||
some(parseIpAddress("127.0.0.0")),
|
Opt.some(parseIpAddress("127.0.0.0")),
|
||||||
some(port), some(port))[]
|
Opt.some(port), Opt.some(port))[]
|
||||||
srcNode = newNode(srcRecord)[]
|
srcNode = newNode(srcRecord)[]
|
||||||
pk = PrivateKey.random(rng[])
|
pk = PrivateKey.random(rng[])
|
||||||
targetDistance = @[logDistance(srcNode.id, pk.toPublicKey().toNodeId())]
|
targetDistance = @[logDistance(srcNode.id, pk.toPublicKey().toNodeId())]
|
||||||
|
@ -611,16 +611,16 @@ suite "Discovery v5 Tests":
|
||||||
block: # valid address - lo with lo src
|
block: # valid address - lo with lo src
|
||||||
let
|
let
|
||||||
record = enr.Record.init(
|
record = enr.Record.init(
|
||||||
1, pk, some(parseIpAddress("127.0.0.1")),
|
1, pk, Opt.some(parseIpAddress("127.0.0.1")),
|
||||||
some(port), some(port))[]
|
Opt.some(port), Opt.some(port))[]
|
||||||
test = verifyNodesRecords([record], srcNode, limit, targetDistance)
|
test = verifyNodesRecords([record], srcNode, limit, targetDistance)
|
||||||
check test.len == 1
|
check test.len == 1
|
||||||
|
|
||||||
block: # valid address - global with lo src
|
block: # valid address - global with lo src
|
||||||
let
|
let
|
||||||
record = enr.Record.init(
|
record = enr.Record.init(
|
||||||
1, pk, some(parseIpAddress("1.2.3.4")),
|
1, pk, Opt.some(parseIpAddress("1.2.3.4")),
|
||||||
some(port), some(port))[]
|
Opt.some(port), Opt.some(port))[]
|
||||||
test = verifyNodesRecords([record], srcNode, limit, targetDistance)
|
test = verifyNodesRecords([record], srcNode, limit, targetDistance)
|
||||||
check test.len == 1
|
check test.len == 1
|
||||||
|
|
||||||
|
@ -628,8 +628,8 @@ suite "Discovery v5 Tests":
|
||||||
let
|
let
|
||||||
port = Port(9000)
|
port = Port(9000)
|
||||||
srcRecord = enr.Record.init(1, PrivateKey.random(rng[]),
|
srcRecord = enr.Record.init(1, PrivateKey.random(rng[]),
|
||||||
some(parseIpAddress("192.168.1.1")),
|
Opt.some(parseIpAddress("192.168.1.1")),
|
||||||
some(port), some(port))[]
|
Opt.some(port), Opt.some(port))[]
|
||||||
srcNode = newNode(srcRecord)[]
|
srcNode = newNode(srcRecord)[]
|
||||||
pk = PrivateKey.random(rng[])
|
pk = PrivateKey.random(rng[])
|
||||||
targetDistance = @[logDistance(srcNode.id, pk.toPublicKey().toNodeId())]
|
targetDistance = @[logDistance(srcNode.id, pk.toPublicKey().toNodeId())]
|
||||||
|
@ -638,16 +638,16 @@ suite "Discovery v5 Tests":
|
||||||
block: # valid address - site local with site local src
|
block: # valid address - site local with site local src
|
||||||
let
|
let
|
||||||
record = enr.Record.init(
|
record = enr.Record.init(
|
||||||
1, pk, some(parseIpAddress("192.168.1.2")),
|
1, pk, Opt.some(parseIpAddress("192.168.1.2")),
|
||||||
some(port), some(port))[]
|
Opt.some(port), Opt.some(port))[]
|
||||||
test = verifyNodesRecords([record], srcNode, limit, targetDistance)
|
test = verifyNodesRecords([record], srcNode, limit, targetDistance)
|
||||||
check test.len == 1
|
check test.len == 1
|
||||||
|
|
||||||
block: # valid address - global with site local src
|
block: # valid address - global with site local src
|
||||||
let
|
let
|
||||||
record = enr.Record.init(
|
record = enr.Record.init(
|
||||||
1, pk, some(parseIpAddress("1.2.3.4")),
|
1, pk, Opt.some(parseIpAddress("1.2.3.4")),
|
||||||
some(port), some(port))[]
|
Opt.some(port), Opt.some(port))[]
|
||||||
test = verifyNodesRecords([record], srcNode, limit, targetDistance)
|
test = verifyNodesRecords([record], srcNode, limit, targetDistance)
|
||||||
check test.len == 1
|
check test.len == 1
|
||||||
|
|
||||||
|
@ -691,8 +691,8 @@ suite "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(parseIpAddress("127.0.0.1")), some(Port(9000)),
|
Opt.some(parseIpAddress("127.0.0.1")), Opt.some(Port(9000)),
|
||||||
some(Port(9000))).expect("Properly initialized private key")
|
Opt.some(Port(9000))).expect("Properly initialized 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))
|
||||||
|
|
||||||
|
@ -720,8 +720,8 @@ suite "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(parseIpAddress("127.0.0.1")), some(Port(9000)),
|
Opt.some(parseIpAddress("127.0.0.1")), Opt.some(Port(9000)),
|
||||||
some(Port(9000))).expect("Properly initialized private key")
|
Opt.some(Port(9000))).expect("Properly initialized 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:
|
||||||
|
@ -751,8 +751,8 @@ suite "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(parseIpAddress("127.0.0.1")), some(Port(9000)),
|
Opt.some(parseIpAddress("127.0.0.1")), Opt.some(Port(9000)),
|
||||||
some(Port(9000))).expect("Properly initialized private key")
|
Opt.some(Port(9000))).expect("Properly initialized 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))
|
||||||
|
|
||||||
|
|
|
@ -265,13 +265,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(parseIpAddress("127.0.0.1")), some(Port(9000)),
|
Opt.some(parseIpAddress("127.0.0.1")), Opt.some(Port(9000)),
|
||||||
some(Port(9000))).expect("Properly initialized private key")
|
Opt.some(Port(9000))).expect("Properly initialized 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(parseIpAddress("127.0.0.1")), some(Port(9000)),
|
Opt.some(parseIpAddress("127.0.0.1")), Opt.some(Port(9000)),
|
||||||
some(Port(9000))).expect("Properly initialized private key")
|
Opt.some(Port(9000))).expect("Properly initialized private key")
|
||||||
nodeB = newNode(enrRecB).expect("Properly initialized record")
|
nodeB = newNode(enrRecB).expect("Properly initialized record")
|
||||||
|
|
||||||
var
|
var
|
||||||
|
@ -358,7 +358,7 @@ suite "Discovery v5.1 Packet Encodings Test Vectors":
|
||||||
idNonce: hexToByteArray[idNonceSize](whoareyouIdNonce),
|
idNonce: hexToByteArray[idNonceSize](whoareyouIdNonce),
|
||||||
recordSeq: whoareyouEnrSeq,
|
recordSeq: whoareyouEnrSeq,
|
||||||
challengeData: hexToSeqByte(whoareyouChallengeData))
|
challengeData: hexToSeqByte(whoareyouChallengeData))
|
||||||
pubkey = some(privKeyA.toPublicKey())
|
pubkey = Opt.some(privKeyA.toPublicKey())
|
||||||
challenge = Challenge(whoareyouData: whoareyouData, pubkey: pubkey)
|
challenge = Challenge(whoareyouData: whoareyouData, pubkey: pubkey)
|
||||||
key = HandshakeKey(nodeId: nodeA.id, address: nodeA.address.get())
|
key = HandshakeKey(nodeId: nodeA.id, address: nodeA.address.get())
|
||||||
|
|
||||||
|
@ -408,7 +408,7 @@ suite "Discovery v5.1 Packet Encodings Test Vectors":
|
||||||
idNonce: hexToByteArray[idNonceSize](whoareyouIdNonce),
|
idNonce: hexToByteArray[idNonceSize](whoareyouIdNonce),
|
||||||
recordSeq: whoareyouEnrSeq,
|
recordSeq: whoareyouEnrSeq,
|
||||||
challengeData: hexToSeqByte(whoareyouChallengeData))
|
challengeData: hexToSeqByte(whoareyouChallengeData))
|
||||||
pubkey = none(PublicKey)
|
pubkey = Opt.none(PublicKey)
|
||||||
challenge = Challenge(whoareyouData: whoareyouData, pubkey: pubkey)
|
challenge = Challenge(whoareyouData: whoareyouData, pubkey: pubkey)
|
||||||
key = HandshakeKey(nodeId: nodeA.id, address: nodeA.address.get())
|
key = HandshakeKey(nodeId: nodeA.id, address: nodeA.address.get())
|
||||||
|
|
||||||
|
@ -486,13 +486,13 @@ suite "Discovery v5.1 Additional Encode/Decode":
|
||||||
privKeyB = PrivateKey.random(rng[]) # receiver -> decode
|
privKeyB = PrivateKey.random(rng[]) # receiver -> decode
|
||||||
|
|
||||||
enrRecA = enr.Record.init(1, privKeyA,
|
enrRecA = enr.Record.init(1, privKeyA,
|
||||||
some(parseIpAddress("127.0.0.1")), some(Port(9000)),
|
Opt.some(parseIpAddress("127.0.0.1")), Opt.some(Port(9000)),
|
||||||
some(Port(9000))).expect("Properly initialized private key")
|
Opt.some(Port(9000))).expect("Properly initialized 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(parseIpAddress("127.0.0.1")), some(Port(9000)),
|
Opt.some(parseIpAddress("127.0.0.1")), Opt.some(Port(9000)),
|
||||||
some(Port(9000))).expect("Properly initialized private key")
|
Opt.some(Port(9000))).expect("Properly initialized private key")
|
||||||
nodeB = newNode(enrRecB).expect("Properly initialized record")
|
nodeB = newNode(enrRecB).expect("Properly initialized record")
|
||||||
|
|
||||||
var
|
var
|
||||||
|
@ -520,7 +520,7 @@ suite "Discovery v5.1 Additional Encode/Decode":
|
||||||
let recordSeq = 0'u64
|
let recordSeq = 0'u64
|
||||||
|
|
||||||
let data = encodeWhoareyouPacket(rng[], codecA, nodeB.id,
|
let data = encodeWhoareyouPacket(rng[], codecA, nodeB.id,
|
||||||
nodeB.address.get(), requestNonce, recordSeq, none(PublicKey))
|
nodeB.address.get(), requestNonce, recordSeq, Opt.none(PublicKey))
|
||||||
|
|
||||||
let decoded = codecB.decodePacket(nodeA.address.get(), data)
|
let decoded = codecB.decodePacket(nodeA.address.get(), data)
|
||||||
|
|
||||||
|
@ -542,7 +542,7 @@ suite "Discovery v5.1 Additional Encode/Decode":
|
||||||
m = PingMessage(enrSeq: 0)
|
m = PingMessage(enrSeq: 0)
|
||||||
reqId = RequestId.init(rng[])
|
reqId = RequestId.init(rng[])
|
||||||
message = encodeMessage(m, reqId)
|
message = encodeMessage(m, reqId)
|
||||||
pubkey = some(privKeyA.toPublicKey())
|
pubkey = Opt.some(privKeyA.toPublicKey())
|
||||||
|
|
||||||
# Encode/decode whoareyou packet to get the handshake stored and the
|
# Encode/decode whoareyou packet to get the handshake stored and the
|
||||||
# whoareyou data returned. It's either that or construct the header for the
|
# whoareyou data returned. It's either that or construct the header for the
|
||||||
|
@ -572,7 +572,7 @@ suite "Discovery v5.1 Additional Encode/Decode":
|
||||||
m = PingMessage(enrSeq: 0)
|
m = PingMessage(enrSeq: 0)
|
||||||
reqId = RequestId.init(rng[])
|
reqId = RequestId.init(rng[])
|
||||||
message = encodeMessage(m, reqId)
|
message = encodeMessage(m, reqId)
|
||||||
pubkey = none(PublicKey)
|
pubkey = Opt.none(PublicKey)
|
||||||
|
|
||||||
# Encode/decode whoareyou packet to get the handshake stored and the
|
# Encode/decode whoareyou packet to get the handshake stored and the
|
||||||
# whoareyou data returned. It's either that or construct the header for the
|
# whoareyou data returned. It's either that or construct the header for the
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
{.used.}
|
{.used.}
|
||||||
|
|
||||||
import
|
import
|
||||||
std/[options, sequtils, net],
|
std/[sequtils, net],
|
||||||
unittest2,
|
unittest2,
|
||||||
../../eth/p2p/discoveryv5/enr, ../../eth/[keys, rlp]
|
../../eth/p2p/discoveryv5/enr, ../../eth/[keys, rlp]
|
||||||
|
|
||||||
|
@ -68,9 +68,9 @@ suite "ENR":
|
||||||
let
|
let
|
||||||
keypair = KeyPair.random(rng[])
|
keypair = KeyPair.random(rng[])
|
||||||
ip = parseIpAddress("10.20.30.40")
|
ip = parseIpAddress("10.20.30.40")
|
||||||
port = some(Port(9000))
|
port = Opt.some(Port(9000))
|
||||||
enr = Record.init(
|
enr = Record.init(
|
||||||
100, keypair.seckey, some(ip), port, port,@[])[]
|
100, keypair.seckey, Opt.some(ip), port, port,@[])[]
|
||||||
typedEnr = get enr.toTypedRecord()
|
typedEnr = get enr.toTypedRecord()
|
||||||
|
|
||||||
check:
|
check:
|
||||||
|
@ -89,9 +89,9 @@ suite "ENR":
|
||||||
test "ENR without address":
|
test "ENR without address":
|
||||||
let
|
let
|
||||||
keypair = KeyPair.random(rng[])
|
keypair = KeyPair.random(rng[])
|
||||||
port = none(Port)
|
port = Opt.none(Port)
|
||||||
enr = Record.init(
|
enr = Record.init(
|
||||||
100, keypair.seckey, none(IpAddress), port, port)[]
|
100, keypair.seckey, Opt.none(IpAddress), port, port)[]
|
||||||
typedEnr = get enr.toTypedRecord()
|
typedEnr = get enr.toTypedRecord()
|
||||||
|
|
||||||
check:
|
check:
|
||||||
|
@ -122,7 +122,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(IpAddress), none(Port), none(Port))[]
|
var r = Record.init(1, pk, Opt.none(IpAddress), Opt.none(Port), Opt.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])
|
||||||
|
@ -189,12 +189,12 @@ suite "ENR":
|
||||||
let
|
let
|
||||||
pk = PrivateKey.fromHex(
|
pk = PrivateKey.fromHex(
|
||||||
"5d2908f3f09ea1ff2e327c3f623159639b00af406e9009de5fd4b910fc34049d")[]
|
"5d2908f3f09ea1ff2e327c3f623159639b00af406e9009de5fd4b910fc34049d")[]
|
||||||
var r = Record.init(1, pk, none(IpAddress),
|
var r = Record.init(1, pk, Opt.none(IpAddress),
|
||||||
some(Port(9000)), some(Port(9000)))[]
|
Opt.some(Port(9000)), Opt.some(Port(9000)))[]
|
||||||
|
|
||||||
block:
|
block:
|
||||||
let updated = r.update(pk, none(IpAddress),
|
let updated = r.update(pk, Opt.none(IpAddress),
|
||||||
some(Port(9000)), some(Port(9000)))
|
Opt.some(Port(9000)), Opt.some(Port(9000)))
|
||||||
check updated.isOk()
|
check updated.isOk()
|
||||||
check:
|
check:
|
||||||
r.tryGet("ip", uint).isNone()
|
r.tryGet("ip", uint).isNone()
|
||||||
|
@ -203,8 +203,8 @@ suite "ENR":
|
||||||
r.seqNum == 1
|
r.seqNum == 1
|
||||||
|
|
||||||
block:
|
block:
|
||||||
let updated = r.update(pk, none(IpAddress),
|
let updated = r.update(pk, Opt.none(IpAddress),
|
||||||
some(Port(9001)), some(Port(9002)))
|
Opt.some(Port(9001)), Opt.some(Port(9002)))
|
||||||
check updated.isOk()
|
check updated.isOk()
|
||||||
check:
|
check:
|
||||||
r.tryGet("ip", uint).isNone()
|
r.tryGet("ip", uint).isNone()
|
||||||
|
@ -213,8 +213,8 @@ suite "ENR":
|
||||||
r.seqNum == 2
|
r.seqNum == 2
|
||||||
|
|
||||||
block:
|
block:
|
||||||
let updated = r.update(pk, some(parseIpAddress("10.20.30.40")),
|
let updated = r.update(pk, Opt.some(parseIpAddress("10.20.30.40")),
|
||||||
some(Port(9000)), some(Port(9000)))
|
Opt.some(Port(9000)), Opt.some(Port(9000)))
|
||||||
check updated.isOk()
|
check updated.isOk()
|
||||||
|
|
||||||
let typedEnr = r.toTypedRecord().get()
|
let typedEnr = r.toTypedRecord().get()
|
||||||
|
@ -232,8 +232,8 @@ suite "ENR":
|
||||||
r.seqNum == 3
|
r.seqNum == 3
|
||||||
|
|
||||||
block:
|
block:
|
||||||
let updated = r.update(pk, some(parseIpAddress("10.20.30.40")),
|
let updated = r.update(pk, Opt.some(parseIpAddress("10.20.30.40")),
|
||||||
some(Port(9001)), some(Port(9001)))
|
Opt.some(Port(9001)), Opt.some(Port(9001)))
|
||||||
check updated.isOk()
|
check updated.isOk()
|
||||||
|
|
||||||
let typedEnr = r.toTypedRecord().get()
|
let typedEnr = r.toTypedRecord().get()
|
||||||
|
|
|
@ -31,7 +31,7 @@ suite "IP vote":
|
||||||
votes.insert(NodeId.random(rng[]), addr3);
|
votes.insert(NodeId.random(rng[]), addr3);
|
||||||
votes.insert(NodeId.random(rng[]), addr3);
|
votes.insert(NodeId.random(rng[]), addr3);
|
||||||
|
|
||||||
check votes.majority() == some(addr2)
|
check votes.majority() == Opt.some(addr2)
|
||||||
|
|
||||||
test "Votes below threshold":
|
test "Votes below threshold":
|
||||||
const threshold = 10
|
const threshold = 10
|
||||||
|
@ -67,7 +67,7 @@ suite "IP vote":
|
||||||
for i in 0..<(threshold):
|
for i in 0..<(threshold):
|
||||||
votes.insert(NodeId.random(rng[]), addr3);
|
votes.insert(NodeId.random(rng[]), addr3);
|
||||||
|
|
||||||
check votes.majority() == some(addr3)
|
check votes.majority() == Opt.some(addr3)
|
||||||
|
|
||||||
test "Double votes with same address":
|
test "Double votes with same address":
|
||||||
const threshold = 2
|
const threshold = 2
|
||||||
|
@ -85,7 +85,7 @@ suite "IP vote":
|
||||||
votes.insert(NodeId.random(rng[]), addr2);
|
votes.insert(NodeId.random(rng[]), addr2);
|
||||||
votes.insert(NodeId.random(rng[]), addr2);
|
votes.insert(NodeId.random(rng[]), addr2);
|
||||||
|
|
||||||
check votes.majority() == some(addr2)
|
check votes.majority() == Opt.some(addr2)
|
||||||
|
|
||||||
test "Double votes with different address":
|
test "Double votes with different address":
|
||||||
const threshold = 2
|
const threshold = 2
|
||||||
|
@ -105,4 +105,4 @@ suite "IP vote":
|
||||||
votes.insert(NodeId.random(rng[]), addr2);
|
votes.insert(NodeId.random(rng[]), addr2);
|
||||||
votes.insert(NodeId.random(rng[]), addr3);
|
votes.insert(NodeId.random(rng[]), addr3);
|
||||||
|
|
||||||
check votes.majority() == some(addr3)
|
check votes.majority() == Opt.some(addr3)
|
||||||
|
|
|
@ -460,8 +460,8 @@ 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.update(pk,
|
let updated = updatedNode1.update(pk,
|
||||||
some(parseIpAddress("192.168.0.1")),
|
Opt.some(parseIpAddress("192.168.0.1")),
|
||||||
some(Port(9000)), some(Port(9000)))
|
Opt.some(Port(9000)), Opt.some(Port(9000)))
|
||||||
check updated.isOk()
|
check updated.isOk()
|
||||||
check table.addNode(updatedNode1) == Existing
|
check table.addNode(updatedNode1) == Existing
|
||||||
|
|
||||||
|
@ -509,8 +509,8 @@ 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.update(pk,
|
let updated = updatedNode1.update(pk,
|
||||||
some(parseIpAddress("192.168.0.1")),
|
Opt.some(parseIpAddress("192.168.0.1")),
|
||||||
some(Port(9000+i)), some(Port(9000+i)))
|
Opt.some(Port(9000+i)), Opt.some(Port(9000+i)))
|
||||||
check updated.isOk()
|
check updated.isOk()
|
||||||
check table.addNode(updatedNode1) == Existing
|
check table.addNode(updatedNode1) == Existing
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Copyright (c) 2020-2023 Status Research & Development GmbH
|
# Copyright (c) 2020-2024 Status Research & Development GmbH
|
||||||
# Licensed and distributed under either of
|
# Licensed and distributed under either of
|
||||||
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
||||||
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
||||||
|
@ -72,7 +72,7 @@ suite "uTP packet encoding":
|
||||||
test "Encode/decode ACK packet: with extensions":
|
test "Encode/decode ACK packet: with extensions":
|
||||||
let
|
let
|
||||||
bitMask: array[4, byte] = [1'u8, 2, 3, 4]
|
bitMask: array[4, byte] = [1'u8, 2, 3, 4]
|
||||||
ackPacket = ackPacket(5, 10, 20, 30, 40, some(bitMask))
|
ackPacket = ackPacket(5, 10, 20, 30, 40, Opt.some(bitMask))
|
||||||
encoded = encodePacket(ackPacket)
|
encoded = encodePacket(ackPacket)
|
||||||
decoded = decodePacket(encoded)
|
decoded = decodePacket(encoded)
|
||||||
|
|
||||||
|
@ -88,7 +88,7 @@ suite "uTP packet encoding":
|
||||||
|
|
||||||
test "Fail to decode packet with malformed extensions":
|
test "Fail to decode packet with malformed extensions":
|
||||||
let bitMask: array[4, byte] = [1'u8, 2, 3, 4]
|
let bitMask: array[4, byte] = [1'u8, 2, 3, 4]
|
||||||
let ackPacket = ackPacket(5, 10, 20, 30, 40, some(bitMask))
|
let ackPacket = ackPacket(5, 10, 20, 30, 40, Opt.some(bitMask))
|
||||||
|
|
||||||
block: # nextExtension to non zero
|
block: # nextExtension to non zero
|
||||||
var encoded = encodePacket(ackPacket)
|
var encoded = encodePacket(ackPacket)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Copyright (c) 2020-2021 Status Research & Development GmbH
|
# Copyright (c) 2020-2024 Status Research & Development GmbH
|
||||||
# Licensed and distributed under either of
|
# Licensed and distributed under either of
|
||||||
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
||||||
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
||||||
|
@ -7,7 +7,6 @@
|
||||||
{.used.}
|
{.used.}
|
||||||
|
|
||||||
import
|
import
|
||||||
std/options,
|
|
||||||
stew/byteutils,
|
stew/byteutils,
|
||||||
unittest2,
|
unittest2,
|
||||||
../../eth/utp/packets,
|
../../eth/utp/packets,
|
||||||
|
@ -27,7 +26,7 @@ suite "uTP packets test vectors":
|
||||||
seqNr: 11884,
|
seqNr: 11884,
|
||||||
ackNr: 0
|
ackNr: 0
|
||||||
),
|
),
|
||||||
eack: none[SelectiveAckExtension](),
|
eack: Opt.none(SelectiveAckExtension),
|
||||||
payload: @[]
|
payload: @[]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -51,7 +50,7 @@ suite "uTP packets test vectors":
|
||||||
seqNr: 16807,
|
seqNr: 16807,
|
||||||
ackNr: 11885
|
ackNr: 11885
|
||||||
),
|
),
|
||||||
eack: none[SelectiveAckExtension](),
|
eack: Opt.none(SelectiveAckExtension),
|
||||||
payload: @[]
|
payload: @[]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -78,7 +77,7 @@ suite "uTP packets test vectors":
|
||||||
seqNr: 16807,
|
seqNr: 16807,
|
||||||
ackNr: 11885
|
ackNr: 11885
|
||||||
),
|
),
|
||||||
eack: some(SelectiveAckExtension(
|
eack: Opt.some(SelectiveAckExtension(
|
||||||
acks: bitMask
|
acks: bitMask
|
||||||
)),
|
)),
|
||||||
payload: @[]
|
payload: @[]
|
||||||
|
@ -104,7 +103,7 @@ suite "uTP packets test vectors":
|
||||||
seqNr: 8334,
|
seqNr: 8334,
|
||||||
ackNr: 16806
|
ackNr: 16806
|
||||||
),
|
),
|
||||||
eack: none[SelectiveAckExtension](),
|
eack: Opt.none(SelectiveAckExtension),
|
||||||
payload: @[0'u8, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
payload: @[0'u8, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -128,7 +127,7 @@ suite "uTP packets test vectors":
|
||||||
seqNr: 41050,
|
seqNr: 41050,
|
||||||
ackNr: 16806
|
ackNr: 16806
|
||||||
),
|
),
|
||||||
eack: none[SelectiveAckExtension](),
|
eack: Opt.none(SelectiveAckExtension),
|
||||||
payload: @[]
|
payload: @[]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -152,7 +151,7 @@ suite "uTP packets test vectors":
|
||||||
seqNr: 55413,
|
seqNr: 55413,
|
||||||
ackNr: 16807
|
ackNr: 16807
|
||||||
),
|
),
|
||||||
eack: none[SelectiveAckExtension](),
|
eack: Opt.none(SelectiveAckExtension),
|
||||||
payload: @[]
|
payload: @[]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -211,7 +211,7 @@ proc run(config: DiscoveryConf) {.raises: [CatchableError].} =
|
||||||
config.listenAddress, udpPort, udpPort, "dcli")
|
config.listenAddress, udpPort, udpPort, "dcli")
|
||||||
|
|
||||||
let d = newProtocol(config.nodeKey,
|
let d = newProtocol(config.nodeKey,
|
||||||
extIp, none(Port), extUdpPort,
|
extIp, Opt.none(Port), extUdpPort,
|
||||||
bootstrapRecords = config.bootnodes,
|
bootstrapRecords = config.bootnodes,
|
||||||
bindIp = bindIp, bindPort = udpPort,
|
bindIp = bindIp, bindPort = udpPort,
|
||||||
enrAutoUpdate = config.enrAutoUpdate)
|
enrAutoUpdate = config.enrAutoUpdate)
|
||||||
|
|
Loading…
Reference in New Issue