diff --git a/eth/p2p/rlpx.nim b/eth/p2p/rlpx.nim index bc0bb33..fe67874 100644 --- a/eth/p2p/rlpx.nim +++ b/eth/p2p/rlpx.nim @@ -43,6 +43,32 @@ type DisconnectionReasonList = object value: DisconnectionReason +proc read(rlp: var Rlp; T: type DisconnectionReasonList): T + {.raises: [Defect, RlpError].} = + ## Rlp mixin: `DisconnectionReasonList` parser + if rlp.isList: + # Be strict here: The expression `rlp.read(DisconnectionReasonList)` + # accepts lists with at least one item. The array expression wants + # exactly one item. + let a = rlp.read(array[1, DisconnectionReason]) + return DisconnectionReasonList(value: a[0]) + + # Also accepted: a single byte reason code. Is is typically used + # by variants of the reference implementation `Geth` + if rlp.blobLen <= 1: + let n = rlp.read(int) + return DisconnectionReasonList(value: n.DisconnectionReason) + + # Also accepted: a blob of a list (aka object) of reason code. It is + # used by `bor`, a `geth` fork + var subList = rlp.toBytes.rlpFromBytes + if subList.isList: + # Ditto, see above. + let a = subList.read(array[1,DisconnectionReason]) + return DisconnectionReasonList(value: a[0]) + raise newException(RlpTypeMismatch, "Single entry list expected") + + const devp2pVersion* = 4 maxMsgSize = 1024 * 1024 * 10 @@ -518,7 +544,7 @@ proc checkedRlpRead(peer: Peer, r: var Rlp, MsgType: type): peer = peer, dataType = MsgType.name, exception = e.msg - # rlpData = r.inspect + # rlpData = r.inspect -- don't use (might crash) raise e diff --git a/tests/p2p/test_rlpx_thunk.json b/tests/p2p/test_rlpx_thunk.json index f0eb323..a57e77f 100644 --- a/tests/p2p/test_rlpx_thunk.json +++ b/tests/p2p/test_rlpx_thunk.json @@ -49,10 +49,15 @@ "error": "MalformedRlpError", "description": "listElem to error on invalid size encoding" }, - "Listing elements when not a list": { - "payload": "010a", + "Listing single element list when having more entries": { + "payload": "01c20420", "error": "RlpTypeMismatch", - "description": "listElem to assert on not a list" + "description": "listElem to assert on not a single entry list" + }, + "Listing single element list when having empty list": { + "payload": "01c0", + "error": "RlpTypeMismatch", + "description": "listElem to assert on not a single entry list" }, "devp2p hello packet version 22 + additional list elements for EIP-8": { "payload": "00f87137916b6e6574682f76302e39312f706c616e39cdc5836574683dc6846d6f726b1682270fb840fda1cff674c90c9a197539fe3dfb53086ace64f83ed7c6eabec741f7f381cc803e52ab2cd55d5569bce4347107a310dfd5f88a010cd2ffd1005ca406f1842877c883666f6f836261720304"