Introduce enr.TypedRecord that can replace enr.Record in the future

This commit is contained in:
Zahary Karadjov 2019-12-18 03:10:09 +02:00 committed by zah
parent 39857d57f0
commit 988d743c9a
1 changed files with 51 additions and 6 deletions

View File

@ -1,4 +1,4 @@
import strutils, macros, algorithm import strutils, macros, algorithm, options
import eth/[rlp, keys], nimcrypto, stew/base64 import eth/[rlp, keys], nimcrypto, stew/base64
type type
@ -10,6 +10,16 @@ type
EnrUri* = distinct string EnrUri* = distinct string
TypedRecord* = object
id*: string
secp256k1*: Option[array[33, byte]]
ip*: Option[array[4, byte]]
ip6*: Option[array[16, byte]]
tcp*: Option[int]
udp*: Option[int]
tcp6*: Option[int]
udp6*: Option[int]
FieldKind = enum FieldKind = enum
kString, kString,
kNum, kNum,
@ -91,18 +101,28 @@ proc requireKind(f: Field, kind: FieldKind) =
if f.kind != kind: if f.kind != kind:
raise newException(ValueError, "Wrong field kind") raise newException(ValueError, "Wrong field kind")
proc get*[T: seq[byte] | string | SomeInteger](r: Record, key: string, typ: typedesc[T]): typ = proc get*(r: Record, key: string, T: type): T =
var f: Field var f: Field
if r.getField(key, f): if r.getField(key, f):
when typ is SomeInteger: when T is SomeInteger:
requireKind(f, kNum) requireKind(f, kNum)
return typ(f.num) return T(f.num)
elif typ is seq[byte]: elif T is seq[byte]:
requireKind(f, kBytes) requireKind(f, kBytes)
return f.bytes return f.bytes
elif typ is string: elif T is string:
requireKind(f, kString) requireKind(f, kString)
return f.str return f.str
elif T is array:
when type(result[0]) is byte:
requireKind(f, kBytes)
if f.bytes.len != result.len:
raise newException(ValueError, "Invalid byte blob length")
copyMem(addr result[0], addr f.bytes[0], result.len)
else:
{.fatal: "Unsupported output type in enr.get".}
else:
{.fatal: "Unsupported output type in enr.get".}
else: else:
raise newException(KeyError, "Key not found in ENR: " & key) raise newException(KeyError, "Key not found in ENR: " & key)
@ -111,6 +131,31 @@ proc get*(r: Record, pubKey: var PublicKey): bool =
if r.getField("secp256k1", pubkeyField) and pubkeyField.kind == kBytes: if r.getField("secp256k1", pubkeyField) and pubkeyField.kind == kBytes:
result = recoverPublicKey(pubkeyField.bytes, pubKey) == EthKeysStatus.Success result = recoverPublicKey(pubkeyField.bytes, pubKey) == EthKeysStatus.Success
proc tryGet*(r: Record, key: string, T: type): Option[T] =
try:
return some r.get(key, T)
except CatchableError:
discard
func toTypedRecord*(r: Record): Option[TypedRecord] =
let id = r.tryGet("id", string)
if id.isSome:
var tr: TypedRecord
tr.id = id.get
template readField(fieldName: untyped) {.dirty.} =
tr.fieldName = tryGet(r, astToStr(fieldName), type(tr.fieldName.get))
readField secp256k1
readField ip
readField ip6
readField tcp
readField tcp6
readField udp
readField udp6
return some(tr)
proc verifySignatureV4(r: Record, sigData: openarray[byte], content: seq[byte]): bool = proc verifySignatureV4(r: Record, sigData: openarray[byte], content: seq[byte]): bool =
var publicKey: PublicKey var publicKey: PublicKey
if r.get(publicKey): if r.get(publicKey):