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:
Kim De Mey 2021-10-19 09:26:14 +02:00 committed by GitHub
parent 6fbf129ba9
commit f101c83626
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 45 additions and 3 deletions

View File

@ -46,7 +46,8 @@ type
FieldKind = enum
kString,
kNum,
kBytes
kBytes,
kList
Field = object
case kind: FieldKind
@ -56,6 +57,9 @@ type
num: BiggestUInt
of kBytes:
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]
@ -68,6 +72,8 @@ template toField[T](v: T): Field =
Field(kind: kBytes, bytes: v)
elif T is SomeUnsignedInt:
Field(kind: kNum, num: BiggestUInt(v))
elif T is object|tuple:
Field(kind: kList, listRaw: rlp.encode(v))
else:
{.error: "Unsupported field type".}
@ -80,6 +86,8 @@ proc `==`(a, b: Field): bool =
return a.num == b.num
of kBytes:
return a.bytes == b.bytes
of kList:
return a.listRaw == b.listRaw
else:
return false
@ -96,6 +104,7 @@ proc makeEnrRaw(seqNum: uint64, pk: PrivateKey,
of kString: w.append(v.str)
of kNum: w.append(v.num)
of kBytes: w.append(v.bytes)
of kList: w.appendRawBytes(v.listRaw) # No encoding needs to happen
w.finish()
let toSign = block:
@ -419,7 +428,16 @@ proc fromBytesAux(r: var Record): bool {.raises: [RlpError, Defect].} =
let v = rlp.read(uint16)
r.pairs.add((k, Field(kind: kNum, num: v)))
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)
@ -463,6 +481,8 @@ proc `$`(f: Field): string =
"0x" & f.bytes.toHex
of kString:
"\"" & f.str & "\""
of kList:
"(Raw RLP list) " & "0x" & f.listRaw.toHex
proc `$`*(r: Record): string =
result = "("

View File

@ -37,7 +37,7 @@ suite "ENR":
var r: Record
check not fromBytes(r, [])
test "Base64 dserialsation without data":
test "Base64 deserialsation without data":
var r: Record
let sigValid = r.fromURI("enr:")
check(not sigValid)
@ -243,3 +243,25 @@ suite "ENR":
typedEnr.udp.get() == 9001
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)