Enable chronos dualstack with new constructor. (#681)

* Add constructor which will use latest chronos feature.

* Add ability to send to IPv4 addresses via dualstack socket.

* Fix decoding IPv4 mapped addresses.

* Use `*` instead of IPv6 address `::`.

* Removing debugging log statements.

* Address review comments.

* Remove debugging statements.

* Eliminate unnecessary variables.
This commit is contained in:
Eugene Kabanov 2024-04-24 14:38:52 +03:00 committed by GitHub
parent d66a29db7c
commit 4cd9e27c09
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 83 additions and 16 deletions

View File

@ -123,6 +123,10 @@ const
## call ## call
type type
OptAddress* = object
ip*: Opt[IpAddress]
port*: Port
DiscoveryConfig* = object DiscoveryConfig* = object
tableIpLimits*: TableIpLimits tableIpLimits*: TableIpLimits
bitsPerHop*: int bitsPerHop*: int
@ -133,7 +137,7 @@ type
transp: DatagramTransport transp: DatagramTransport
localNode*: Node localNode*: Node
privateKey: PrivateKey privateKey: PrivateKey
bindAddress: Address ## UDP binding address bindAddress: OptAddress ## UDP binding address
pendingRequests: Table[AESGCMNonce, PendingRequest] pendingRequests: Table[AESGCMNonce, PendingRequest]
routingTable*: RoutingTable routingTable*: RoutingTable
codec*: Codec codec*: Codec
@ -270,7 +274,7 @@ proc sendTo(d: Protocol, a: Address, data: seq[byte]): Future[void] {.async.} =
# One case that needs this error available upwards is when revalidating # One case that needs this error available upwards is when revalidating
# nodes. Else the revalidation might end up clearing the routing tabl # nodes. Else the revalidation might end up clearing the routing tabl
# because of ping failures due to own network connection failure. # because of ping failures due to own network connection failure.
warn "Discovery send failed", msg = e.msg, address = a warn "Discovery send failed", msg = e.msg, address = $ta
proc send*(d: Protocol, a: Address, data: seq[byte]) = proc send*(d: Protocol, a: Address, data: seq[byte]) =
asyncSpawn sendTo(d, a, data) asyncSpawn sendTo(d, a, data)
@ -478,13 +482,7 @@ proc processClient(transp: DatagramTransport, raddr: TransportAddress):
warn "Transport getMessage", exception = e.name, msg = e.msg warn "Transport getMessage", exception = e.name, msg = e.msg
return return
let ip = try: raddr.address() proto.receive(Address(ip: raddr.toIpAddress(), port: raddr.port), buf)
except ValueError as e:
error "Not a valid IpAddress", exception = e.name, msg = e.msg
return
let a = Address(ip: ip, port: raddr.port)
proto.receive(a, buf)
proc replaceNode(d: Protocol, n: Node) = proc replaceNode(d: Protocol, n: Node) =
if n.record notin d.bootstrapRecords: if n.record notin d.bootstrapRecords:
@ -1006,7 +1004,7 @@ proc newProtocol*(
Protocol( Protocol(
privateKey: privKey, privateKey: privKey,
localNode: node, localNode: node,
bindAddress: Address(ip: bindIp, port: bindPort), bindAddress: OptAddress(ip: Opt.some(bindIp), port: bindPort),
codec: Codec(localNode: node, privKey: privKey, codec: Codec(localNode: node, privKey: privKey,
sessions: Sessions.init(256)), sessions: Sessions.init(256)),
bootstrapRecords: @bootstrapRecords, bootstrapRecords: @bootstrapRecords,
@ -1018,17 +1016,86 @@ proc newProtocol*(
responseTimeout: config.responseTimeout, responseTimeout: config.responseTimeout,
rng: rng) rng: rng)
template listeningAddress*(p: Protocol): Address = proc newProtocol*(
p.bindAddress privKey: PrivateKey,
enrIp: Option[IpAddress],
enrTcpPort, enrUdpPort: Option[Port],
localEnrFields: openArray[(string, seq[byte])] = [],
bootstrapRecords: openArray[Record] = [],
previousRecord = none[enr.Record](),
bindPort: Port,
bindIp: Opt[IpAddress],
enrAutoUpdate = false,
config = defaultDiscoveryConfig,
rng = newRng()): Protocol =
let
customEnrFields = mapIt(localEnrFields, toFieldPair(it[0], it[1]))
record =
if previousRecord.isSome():
var res = previousRecord.get()
res.update(privKey, enrIp, enrTcpPort, enrUdpPort,
customEnrFields).expect("Record within size limits and correct key")
res
else:
enr.Record.init(1, privKey, enrIp, enrTcpPort, enrUdpPort,
customEnrFields).expect("Record within size limits")
proc open*(d: Protocol) {.raises: [CatchableError].} = info "Discovery ENR initialized", enrAutoUpdate, seqNum = record.seqNum,
ip = enrIp, tcpPort = enrTcpPort, udpPort = enrUdpPort,
customEnrFields, uri = toURI(record)
if enrIp.isNone():
if enrAutoUpdate:
notice "No external IP provided for the ENR, this node will not be " &
"discoverable until the ENR is updated with the discovered " &
"external IP address"
else:
warn "No external IP provided for the ENR, this node will not be " &
"discoverable"
let node = newNode(record).expect("Properly initialized record")
doAssert not(isNil(rng)), "RNG initialization failed"
Protocol(
privateKey: privKey,
localNode: node,
bindAddress: OptAddress(ip: bindIp, port: bindPort),
codec: Codec(localNode: node, privKey: privKey,
sessions: Sessions.init(256)),
bootstrapRecords: @bootstrapRecords,
ipVote: IpVote.init(),
enrAutoUpdate: enrAutoUpdate,
routingTable: RoutingTable.init(
node, config.bitsPerHop, config.tableIpLimits, rng),
handshakeTimeout: config.handshakeTimeout,
responseTimeout: config.responseTimeout,
rng: rng)
proc `$`*(a: OptAddress): string =
if a.ip.isNone():
"*:" & $a.port
else:
$a.ip.get() & ":" & $a.port
chronicles.formatIt(OptAddress): $it
template listeningAddress*(p: Protocol): Address =
if p.bindAddress.ip.isNone():
let ta = getAutoAddress(p.bindAddress.port)
Address(ta.toIpAddress(), ta.port)
else:
Address(p.bindAddress.ip.get(), p.bindAddress.port)
proc open*(d: Protocol) {.raises: [TransportOsError].} =
info "Starting discovery node", node = d.localNode, info "Starting discovery node", node = d.localNode,
bindAddress = d.bindAddress bindAddress = d.bindAddress
# TODO allow binding to specific IP / IPv6 / etc # TODO allow binding to specific IP / IPv6 / etc
let ta = initTAddress(d.bindAddress.ip, d.bindAddress.port) d.transp =
d.transp = newDatagramTransport(processClient, udata = d, local = ta) newDatagramTransport(processClient, udata = d,
localPort = d.bindAddress.port,
local = d.bindAddress.ip)
d.seedTable() d.seedTable()
proc start*(d: Protocol) = proc start*(d: Protocol) =