mirror of https://github.com/status-im/nim-eth.git
Enr rlp lists (#408)
* Don't fail ENR decoding when value is an RLP list * Store RLP raw list in the ENR field pair instead * Add ENR kList FieldKind so lists can be treated differently Treated differently now when printing out the ENR, mentioning that it is a raw RLP list
This commit is contained in:
parent
6fbf129ba9
commit
f101c83626
|
@ -46,7 +46,8 @@ type
|
||||||
FieldKind = enum
|
FieldKind = enum
|
||||||
kString,
|
kString,
|
||||||
kNum,
|
kNum,
|
||||||
kBytes
|
kBytes,
|
||||||
|
kList
|
||||||
|
|
||||||
Field = object
|
Field = object
|
||||||
case kind: FieldKind
|
case kind: FieldKind
|
||||||
|
@ -56,6 +57,9 @@ type
|
||||||
num: BiggestUInt
|
num: BiggestUInt
|
||||||
of kBytes:
|
of kBytes:
|
||||||
bytes: seq[byte]
|
bytes: seq[byte]
|
||||||
|
of kList:
|
||||||
|
listRaw: seq[byte] ## Differently from the other kinds, this is is stored
|
||||||
|
## as raw (encoded) RLP data, and thus treated as such further on.
|
||||||
|
|
||||||
EnrResult*[T] = Result[T, cstring]
|
EnrResult*[T] = Result[T, cstring]
|
||||||
|
|
||||||
|
@ -68,6 +72,8 @@ template toField[T](v: T): Field =
|
||||||
Field(kind: kBytes, bytes: v)
|
Field(kind: kBytes, bytes: v)
|
||||||
elif T is SomeUnsignedInt:
|
elif T is SomeUnsignedInt:
|
||||||
Field(kind: kNum, num: BiggestUInt(v))
|
Field(kind: kNum, num: BiggestUInt(v))
|
||||||
|
elif T is object|tuple:
|
||||||
|
Field(kind: kList, listRaw: rlp.encode(v))
|
||||||
else:
|
else:
|
||||||
{.error: "Unsupported field type".}
|
{.error: "Unsupported field type".}
|
||||||
|
|
||||||
|
@ -80,6 +86,8 @@ proc `==`(a, b: Field): bool =
|
||||||
return a.num == b.num
|
return a.num == b.num
|
||||||
of kBytes:
|
of kBytes:
|
||||||
return a.bytes == b.bytes
|
return a.bytes == b.bytes
|
||||||
|
of kList:
|
||||||
|
return a.listRaw == b.listRaw
|
||||||
else:
|
else:
|
||||||
return false
|
return false
|
||||||
|
|
||||||
|
@ -96,6 +104,7 @@ proc makeEnrRaw(seqNum: uint64, pk: PrivateKey,
|
||||||
of kString: w.append(v.str)
|
of kString: w.append(v.str)
|
||||||
of kNum: w.append(v.num)
|
of kNum: w.append(v.num)
|
||||||
of kBytes: w.append(v.bytes)
|
of kBytes: w.append(v.bytes)
|
||||||
|
of kList: w.appendRawBytes(v.listRaw) # No encoding needs to happen
|
||||||
w.finish()
|
w.finish()
|
||||||
|
|
||||||
let toSign = block:
|
let toSign = block:
|
||||||
|
@ -419,7 +428,16 @@ proc fromBytesAux(r: var Record): bool {.raises: [RlpError, Defect].} =
|
||||||
let v = rlp.read(uint16)
|
let v = rlp.read(uint16)
|
||||||
r.pairs.add((k, Field(kind: kNum, num: v)))
|
r.pairs.add((k, Field(kind: kNum, num: v)))
|
||||||
else:
|
else:
|
||||||
r.pairs.add((k, Field(kind: kBytes, bytes: rlp.read(seq[byte]))))
|
# Don't know really what this is supposed to represent so drop it in
|
||||||
|
# `kBytes` field pair when a single byte or blob.
|
||||||
|
if rlp.isSingleByte() or rlp.isBlob():
|
||||||
|
r.pairs.add((k, Field(kind: kBytes, bytes: rlp.read(seq[byte]))))
|
||||||
|
elif rlp.isList():
|
||||||
|
# Not supporting decoding lists as value (especially unknown ones),
|
||||||
|
# just drop the raw RLP value in there.
|
||||||
|
r.pairs.add((k, Field(kind: kList, listRaw: @(rlp.rawData()))))
|
||||||
|
# Need to skip the element still.
|
||||||
|
rlp.skipElem()
|
||||||
|
|
||||||
verifySignature(r)
|
verifySignature(r)
|
||||||
|
|
||||||
|
@ -463,6 +481,8 @@ proc `$`(f: Field): string =
|
||||||
"0x" & f.bytes.toHex
|
"0x" & f.bytes.toHex
|
||||||
of kString:
|
of kString:
|
||||||
"\"" & f.str & "\""
|
"\"" & f.str & "\""
|
||||||
|
of kList:
|
||||||
|
"(Raw RLP list) " & "0x" & f.listRaw.toHex
|
||||||
|
|
||||||
proc `$`*(r: Record): string =
|
proc `$`*(r: Record): string =
|
||||||
result = "("
|
result = "("
|
||||||
|
|
|
@ -37,7 +37,7 @@ suite "ENR":
|
||||||
var r: Record
|
var r: Record
|
||||||
check not fromBytes(r, [])
|
check not fromBytes(r, [])
|
||||||
|
|
||||||
test "Base64 dserialsation without data":
|
test "Base64 deserialsation without data":
|
||||||
var r: Record
|
var r: Record
|
||||||
let sigValid = r.fromURI("enr:")
|
let sigValid = r.fromURI("enr:")
|
||||||
check(not sigValid)
|
check(not sigValid)
|
||||||
|
@ -243,3 +243,25 @@ suite "ENR":
|
||||||
typedEnr.udp.get() == 9001
|
typedEnr.udp.get() == 9001
|
||||||
|
|
||||||
r.seqNum == 4
|
r.seqNum == 4
|
||||||
|
|
||||||
|
test "ENR with RLP list value":
|
||||||
|
type
|
||||||
|
RlpTestList = object
|
||||||
|
number: uint16
|
||||||
|
data: seq[byte]
|
||||||
|
text: string
|
||||||
|
|
||||||
|
let rlpList =
|
||||||
|
RlpTestList(number: 72, data: @[byte 0x0, 0x1, 0x2], text: "Hi there")
|
||||||
|
|
||||||
|
let pk = PrivateKey.fromHex(
|
||||||
|
"5d2908f3f09ea1ff2e327c3f623159639b00af406e9009de5fd4b910fc34049d")[]
|
||||||
|
var r = initRecord(123, pk, {"udp": 1234'u, "ip": [byte 5, 6, 7, 8],
|
||||||
|
"some_list": rlpList})[]
|
||||||
|
|
||||||
|
check($r == """(123, id: "v4", ip: 0x05060708, secp256k1: 0x02E51EFA66628CE09F689BC2B82F165A75A9DDECBB6A804BE15AC3FDF41F3B34E7, some_list: (Raw RLP list) 0xCE4883000102884869207468657265, udp: 1234)""")
|
||||||
|
|
||||||
|
let encoded = rlp.encode(r)
|
||||||
|
let decoded = rlp.decode(encoded, enr.Record)
|
||||||
|
check($decoded == $r)
|
||||||
|
check(decoded.raw == r.raw)
|
||||||
|
|
Loading…
Reference in New Issue