mirror of https://github.com/status-im/nim-eth.git
Don't use exceptions for enr get call (#453)
The ENR code used to be solely exception based, and these exceptions where a left-over of that. They are useless as later calls use Result anyhow. Additionally, they cause quite the performance loss because they are used in the "common path" for the toTypedRecord call, e.g. when reading the fields of ip6, tcp6 and udp6.
This commit is contained in:
parent
2c236f6495
commit
8b7d41f596
|
@ -12,10 +12,10 @@
|
|||
|
||||
import
|
||||
std/[strutils, macros, algorithm, options],
|
||||
stew/shims/net, stew/base64, nimcrypto,
|
||||
stew/shims/net, stew/[base64, results], nimcrypto,
|
||||
".."/../[rlp, keys]
|
||||
|
||||
export options
|
||||
export options, results, keys
|
||||
|
||||
const
|
||||
maxEnrSize = 300 ## Maximum size of an encoded node record, in bytes.
|
||||
|
@ -207,43 +207,47 @@ proc getField(r: Record, name: string, field: var Field): bool =
|
|||
field = v
|
||||
return true
|
||||
|
||||
proc requireKind(f: Field, kind: FieldKind) {.raises: [ValueError].} =
|
||||
proc requireKind(f: Field, kind: FieldKind): EnrResult[void] =
|
||||
if f.kind != kind:
|
||||
raise newException(ValueError, "Wrong field kind")
|
||||
err("Wrong field kind")
|
||||
else:
|
||||
ok()
|
||||
|
||||
proc get*(r: Record, key: string, T: type): T {.raises: [ValueError, Defect].} =
|
||||
proc get*(r: Record, key: string, T: type): EnrResult[T] =
|
||||
## Get the value from the provided key.
|
||||
## Throw `KeyError` if key does not exist.
|
||||
## Throw `ValueError` if the value is invalid according to type `T`.
|
||||
var f: Field
|
||||
if r.getField(key, f):
|
||||
when T is SomeInteger:
|
||||
requireKind(f, kNum)
|
||||
return T(f.num)
|
||||
? requireKind(f, kNum)
|
||||
ok(T(f.num))
|
||||
elif T is seq[byte]:
|
||||
requireKind(f, kBytes)
|
||||
return f.bytes
|
||||
? requireKind(f, kBytes)
|
||||
ok(f.bytes)
|
||||
elif T is string:
|
||||
requireKind(f, kString)
|
||||
return f.str
|
||||
? requireKind(f, kString)
|
||||
ok(f.str)
|
||||
elif T is PublicKey:
|
||||
requireKind(f, kBytes)
|
||||
? requireKind(f, kBytes)
|
||||
let pk = PublicKey.fromRaw(f.bytes)
|
||||
if pk.isErr:
|
||||
raise newException(ValueError, "Invalid public key")
|
||||
return pk[]
|
||||
err("Invalid public key")
|
||||
else:
|
||||
ok(pk[])
|
||||
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)
|
||||
when type(default(T)[low(T)]) is byte:
|
||||
? requireKind(f, kBytes)
|
||||
if f.bytes.len != T.len:
|
||||
err("Invalid byte blob length")
|
||||
else:
|
||||
var res: T
|
||||
copyMem(addr res[0], addr f.bytes[0], res.len)
|
||||
ok(res)
|
||||
else:
|
||||
{.fatal: "Unsupported output type in enr.get".}
|
||||
else:
|
||||
{.fatal: "Unsupported output type in enr.get".}
|
||||
else:
|
||||
raise newException(KeyError, "Key not found in ENR: " & key)
|
||||
err("Key not found in ENR")
|
||||
|
||||
proc get*(r: Record, T: type PublicKey): Option[T] =
|
||||
## Get the `PublicKey` from provided `Record`. Return `none` when there is
|
||||
|
@ -328,10 +332,11 @@ proc tryGet*(r: Record, key: string, T: type): Option[T] =
|
|||
## Get the value from the provided key.
|
||||
## Return `none` if the key does not exist or if the value is invalid
|
||||
## according to type `T`.
|
||||
try:
|
||||
return some get(r, key, T)
|
||||
except ValueError:
|
||||
discard
|
||||
let val = get(r, key, T)
|
||||
if val.isOk():
|
||||
some(val.get())
|
||||
else:
|
||||
none(T)
|
||||
|
||||
proc toTypedRecord*(r: Record): EnrResult[TypedRecord] =
|
||||
let id = r.tryGet("id", string)
|
||||
|
|
|
@ -123,14 +123,14 @@ suite "ENR":
|
|||
let updated = r.update(pk, [newField])
|
||||
check updated.isOk()
|
||||
check:
|
||||
r.get("test", uint) == 123
|
||||
r.get("test", uint).get() == 123
|
||||
r.seqNum == 2
|
||||
|
||||
block: # Insert same k:v pair, no update of seqNum should occur.
|
||||
let updated = r.update(pk, [newField])
|
||||
check updated.isOk()
|
||||
check:
|
||||
r.get("test", uint) == 123
|
||||
r.get("test", uint).get() == 123
|
||||
r.seqNum == 2
|
||||
|
||||
block: # Insert k:v pair with changed value, update of seqNum should occur.
|
||||
|
@ -138,7 +138,7 @@ suite "ENR":
|
|||
let updated = r.update(pk, [updatedField])
|
||||
check updated.isOk()
|
||||
check:
|
||||
r.get("test", uint) == 1234
|
||||
r.get("test", uint).get() == 1234
|
||||
r.seqNum == 3
|
||||
|
||||
test "ENR update sorted":
|
||||
|
|
Loading…
Reference in New Issue