2020-02-17 17:44:56 +01:00
|
|
|
import
|
2020-06-09 11:09:35 +02:00
|
|
|
std/hashes, nimcrypto, stint, chronos, stew/shims/net,
|
2020-05-28 10:19:36 +02:00
|
|
|
eth/keys, enr
|
2019-12-16 21:38:45 +02:00
|
|
|
|
2020-04-30 00:11:03 +02:00
|
|
|
{.push raises: [Defect].}
|
|
|
|
|
2019-12-16 21:38:45 +02:00
|
|
|
type
|
2020-05-28 10:19:36 +02:00
|
|
|
NodeId* = UInt256
|
|
|
|
|
|
|
|
Address* = object
|
2020-06-09 11:09:35 +02:00
|
|
|
ip*: ValidIpAddress
|
2020-05-28 10:19:36 +02:00
|
|
|
port*: Port
|
|
|
|
|
2019-12-16 21:38:45 +02:00
|
|
|
Node* = ref object
|
|
|
|
id*: NodeId
|
2020-05-28 10:19:36 +02:00
|
|
|
pubkey*: PublicKey
|
|
|
|
address*: Option[Address]
|
2019-12-16 21:38:45 +02:00
|
|
|
record*: Record
|
2020-06-30 13:35:15 +02:00
|
|
|
seen*: bool ## Indicates if there was at least one successful
|
|
|
|
## request-response with this node.
|
2019-12-16 21:38:45 +02:00
|
|
|
|
|
|
|
proc toNodeId*(pk: PublicKey): NodeId =
|
2020-04-04 18:44:01 +02:00
|
|
|
readUintBE[256](keccak256.digest(pk.toRaw()).data)
|
2019-12-16 21:38:45 +02:00
|
|
|
|
2020-05-28 10:19:36 +02:00
|
|
|
proc newNode*(r: Record): Result[Node, cstring] =
|
2019-12-16 21:38:45 +02:00
|
|
|
# TODO: Handle IPv6
|
|
|
|
|
2020-04-30 00:11:03 +02:00
|
|
|
let pk = r.get(PublicKey)
|
2020-05-28 10:19:36 +02:00
|
|
|
# This check is redundant as the deserialisation of `Record` will already fail
|
|
|
|
# at `verifySignature` if there is no public key
|
2020-04-30 00:11:03 +02:00
|
|
|
if pk.isNone():
|
2020-05-28 10:19:36 +02:00
|
|
|
return err("Could not recover public key from ENR")
|
2020-02-12 15:36:39 +02:00
|
|
|
|
2020-05-28 10:19:36 +02:00
|
|
|
let tr = ? r.toTypedRecord()
|
|
|
|
if tr.ip.isSome() and tr.udp.isSome():
|
2020-06-11 21:24:52 +02:00
|
|
|
let a = Address(ip: ipv4(tr.ip.get()), port: Port(tr.udp.get()))
|
2020-05-28 10:19:36 +02:00
|
|
|
|
|
|
|
ok(Node(id: pk.get().toNodeId(), pubkey: pk.get() , record: r,
|
|
|
|
address: some(a)))
|
|
|
|
else:
|
|
|
|
ok(Node(id: pk.get().toNodeId(), pubkey: pk.get(), record: r,
|
|
|
|
address: none(Address)))
|
2019-12-16 21:38:45 +02:00
|
|
|
|
2020-05-28 10:19:36 +02:00
|
|
|
proc hash*(n: Node): hashes.Hash = hash(n.pubkey.toRaw)
|
2020-05-01 22:34:26 +02:00
|
|
|
proc `==`*(a, b: Node): bool =
|
2020-04-30 00:11:03 +02:00
|
|
|
(a.isNil and b.isNil) or
|
2020-05-28 10:19:36 +02:00
|
|
|
(not a.isNil and not b.isNil and a.pubkey == b.pubkey)
|
2019-12-18 12:36:11 +02:00
|
|
|
|
2020-05-28 10:19:36 +02:00
|
|
|
proc `$`*(a: Address): string =
|
|
|
|
result.add($a.ip)
|
|
|
|
result.add(":" & $a.port)
|
2020-03-18 15:27:26 +01:00
|
|
|
|
2020-05-01 22:34:26 +02:00
|
|
|
proc `$`*(n: Node): string =
|
2019-12-16 21:38:45 +02:00
|
|
|
if n == nil:
|
2020-05-28 10:19:36 +02:00
|
|
|
"Node[uninitialized]"
|
|
|
|
elif n.address.isNone():
|
|
|
|
"Node[unaddressable]"
|
2019-12-16 21:38:45 +02:00
|
|
|
else:
|
2020-05-28 10:19:36 +02:00
|
|
|
"Node[" & $n.address.get().ip & ":" & $n.address.get().port & "]"
|