Use results.Opt instead of option in discv5, utp and nat (#705)

+ some other minor cleanups
This commit is contained in:
Kim De Mey 2024-06-18 18:09:27 +02:00 committed by GitHub
parent f169068df6
commit 26212c881b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
29 changed files with 265 additions and 258 deletions

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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]

View File

@ -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")

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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()

View File

@ -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))

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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: @[])

View File

@ -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))

View File

@ -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,

View File

@ -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 =

View File

@ -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,

View File

@ -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,

View File

@ -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)[]

View File

@ -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] =

View File

@ -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))

View File

@ -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

View File

@ -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()

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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: @[]
) )

View File

@ -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)