mirror of https://github.com/status-im/nim-eth.git
Add ENR Record.init and update call for dual stack
This commit is contained in:
parent
470baf82bd
commit
45b311fe9c
|
@ -243,7 +243,9 @@ func init*(
|
|||
extraFields: openArray[FieldPair] = []):
|
||||
EnrResult[T] =
|
||||
## Initialize a `Record` with given sequence number, private key, optional
|
||||
## ip address, tcp port, udp port, and optional custom k:v pairs.
|
||||
## IP address, TCP port, UDP port, and optional custom k:v pairs.
|
||||
##
|
||||
## The IP address can be an IPv4 or IPv6 address.
|
||||
##
|
||||
## Can fail in case the record exceeds the `maxEnrSize`.
|
||||
doAssert(not hasPredefinedKey(extraFields), "Predefined key in custom pairs")
|
||||
|
@ -254,6 +256,51 @@ func init*(
|
|||
fields.insert extraFields
|
||||
makeEnrAux(seqNum, "v4", pk, fields)
|
||||
|
||||
func init*(
|
||||
T: type Record,
|
||||
seqNum: uint64, pk: PrivateKey,
|
||||
ip4: array[4, byte],
|
||||
ip6: array[16, byte],
|
||||
tcp4Port: Opt[Port] = Opt.none(Port),
|
||||
udp4Port: Opt[Port] = Opt.none(Port),
|
||||
tcp6Port: Opt[Port] = Opt.none(Port),
|
||||
udp6Port: Opt[Port] = Opt.none(Port),
|
||||
extraFields: openArray[FieldPair] = []
|
||||
): EnrResult[T] =
|
||||
## Initialize a `Record` with given sequence number, private key, IPv4 and IPv6
|
||||
## address, optional TCP port and UDP port for both IPv4 and IPV6, and
|
||||
## optional custom k:v pairs.
|
||||
##
|
||||
## This function is to be used when running in IPv4 and IPv6 dual stack mode.
|
||||
## The tcp6 and udp6 fields will only be set if they differ from the tcp and udp
|
||||
## fields.
|
||||
##
|
||||
## Can fail in case the record exceeds the `maxEnrSize`.
|
||||
doAssert(not hasPredefinedKey(extraFields), "Predefined key in custom pairs")
|
||||
|
||||
var fields = newSeq[FieldPair]()
|
||||
|
||||
fields.insert(("ip", ip4.toField))
|
||||
fields.insert(("ip6", ip6.toField))
|
||||
|
||||
if tcp4Port.isSome():
|
||||
fields.insert(("tcp", tcp4Port.value().uint16.toField))
|
||||
if udp4Port.isSome():
|
||||
fields.insert(("udp", udp4Port.value().uint16.toField))
|
||||
|
||||
# From the ENR specification:
|
||||
# "Declaring the same port number in both tcp, tcp6 or udp, udp6 should be avoided
|
||||
# but doesn't render the record invalid."
|
||||
if tcp6Port.isSome():
|
||||
if tcp6Port != tcp4Port:
|
||||
fields.insert(("tcp6", tcp6Port.value().uint16.toField))
|
||||
if udp6Port.isSome():
|
||||
if udp6Port != udp4Port:
|
||||
fields.insert(("udp6", udp6Port.value().uint16.toField))
|
||||
|
||||
fields.add extraFields
|
||||
makeEnrAux(seqNum, "v4", pk, extraFields)
|
||||
|
||||
func getField(r: Record, name: string, field: var Field): bool =
|
||||
# It might be more correct to do binary search,
|
||||
# as the fields are sorted, but it's unlikely to
|
||||
|
@ -357,6 +404,73 @@ func update*(
|
|||
|
||||
ok()
|
||||
|
||||
func update*(
|
||||
record: var Record,
|
||||
pk: PrivateKey,
|
||||
ip4: array[4, byte],
|
||||
ip6: array[16, byte],
|
||||
tcp4Port: Opt[Port] = Opt.none(Port),
|
||||
udp4Port: Opt[Port] = Opt.none(Port),
|
||||
tcp6Port: Opt[Port] = Opt.none(Port),
|
||||
udp6Port: Opt[Port] = Opt.none(Port),
|
||||
extraFields: openArray[FieldPair] = []):
|
||||
EnrResult[void] =
|
||||
## Update a `Record` with given IPv4 and IPv6 address, optional TCP port and
|
||||
## UDP port for both IPv4 and IPV6, and optional custom k:v pairs.
|
||||
##
|
||||
## This function is to be used when running in IPv4 and IPv6 dual stack mode.
|
||||
## The tcp6 and udp6 fields will only be set if they differ from the tcp and udp
|
||||
## fields.
|
||||
##
|
||||
## If none of the k:v pairs are changed, the sequence number of the `Record`
|
||||
## will still be incremented and a new signature will be applied.
|
||||
##
|
||||
## Providing an `Opt.none` for `tcp4Port`/`udp4Port`/`tcp6Port`/`udp6Port`/
|
||||
## will leave the corresponding field untouched.
|
||||
##
|
||||
## Can fail in case of wrong `PrivateKey`, if the size of the resulting record
|
||||
## exceeds `maxEnrSize` or if maximum sequence number is reached. The `Record`
|
||||
## will not be altered in these cases.
|
||||
# TODO: deprecate this call and have individual functions for updating?
|
||||
doAssert(not hasPredefinedKey(extraFields), "Predefined key in custom pairs")
|
||||
|
||||
var r = record
|
||||
|
||||
let pubkey = r.get(PublicKey)
|
||||
if pubkey.isNone() or pubkey.get() != pk.toPublicKey():
|
||||
return err("Public key does not correspond with given private key")
|
||||
|
||||
var fields = newSeq[FieldPair]()
|
||||
|
||||
fields.insert(("ip", ip4.toField))
|
||||
fields.insert(("ip6", ip6.toField))
|
||||
|
||||
if tcp4Port.isSome():
|
||||
fields.insert(("tcp", tcp4Port.value().uint16.toField))
|
||||
if udp4Port.isSome():
|
||||
fields.insert(("udp", udp4Port.value().uint16.toField))
|
||||
|
||||
# From the ENR specification:
|
||||
# "Declaring the same port number in both tcp, tcp6 or udp, udp6 should be avoided
|
||||
# but doesn't render the record invalid."
|
||||
if tcp6Port.isSome():
|
||||
if tcp6Port != tcp4Port:
|
||||
fields.insert(("tcp6", tcp6Port.value().uint16.toField))
|
||||
if udp6Port.isSome():
|
||||
if udp6Port != udp4Port:
|
||||
fields.insert(("udp6", udp6Port.value().uint16.toField))
|
||||
|
||||
r.pairs.insert extraFields
|
||||
|
||||
if r.seqNum == high(type r.seqNum): # highly unlikely
|
||||
return err("Maximum sequence number reached")
|
||||
r.seqNum.inc()
|
||||
|
||||
r.raw = ? makeEnrRaw(r.seqNum, pk, r.pairs)
|
||||
record = r
|
||||
|
||||
ok()
|
||||
|
||||
func tryGet*(r: Record, key: string, T: type): Opt[T] =
|
||||
## Get the value from the provided key.
|
||||
## Return `none` if the key does not exist or if the value is invalid
|
||||
|
|
Loading…
Reference in New Issue