diff --git a/eth/common/eth_types.nim b/eth/common/eth_types.nim index dca99da..92ff596 100644 --- a/eth/common/eth_types.nim +++ b/eth/common/eth_types.nim @@ -1,5 +1,5 @@ import - endians, options, times, + endians, options, times, chronicles, stint, nimcrypto, eth/rlp, eth/trie/[trie_defs, db] export @@ -329,10 +329,7 @@ proc rlpHash*[T](v: T): Hash256 = func blockHash*(h: BlockHeader): KeccakHash {.inline.} = rlpHash(h) proc notImplemented = - when defined(afl) or defined(libFuzzer): - discard - else: - doAssert false, "Method not implemented" + debug "Method not implemented" template hasData*(b: Blob): bool = b.len > 0 template hasData*(r: EthResourceRefs): bool = r != nil diff --git a/tests/fuzzing/rlpx/thunk.nim b/tests/fuzzing/rlpx/thunk.nim index 6903e45..fb2afc1 100644 --- a/tests/fuzzing/rlpx/thunk.nim +++ b/tests/fuzzing/rlpx/thunk.nim @@ -3,12 +3,6 @@ import eth/p2p/rlpx_protocols/[whisper_protocol, eth_protocol], ../fuzztest, ../p2p/p2p_test_helper -proc recvMsgMock(msg: openArray[byte]): tuple[msgId: int, msgData: Rlp] = - var rlp = rlpFromBytes(@msg.toRange) - - let msgid = rlp.read(int) - return (msgId, rlp) - var node1: EthereumNode node2: EthereumNode diff --git a/tests/p2p/p2p_test_helper.nim b/tests/p2p/p2p_test_helper.nim index cbf6004..cc4b1d5 100644 --- a/tests/p2p/p2p_test_helper.nim +++ b/tests/p2p/p2p_test_helper.nim @@ -1,5 +1,6 @@ import - unittest, chronos, nimcrypto, eth/[keys, p2p], eth/p2p/[discovery, enode] + unittest, chronos, nimcrypto, strutils, + eth/[keys, p2p], eth/p2p/[discovery, enode] var nextPort = 30303 @@ -39,3 +40,11 @@ proc packData*(payload: openArray[byte], pk: PrivateKey): seq[byte] = signature = @(pk.signMessage(payload).getRaw()) msgHash = keccak256.digest(signature & payloadSeq) result = @(msgHash.data) & signature & payloadSeq + +template sourceDir*: string = currentSourcePath.rsplit(DirSep, 1)[0] + +proc recvMsgMock*(msg: openArray[byte]): tuple[msgId: int, msgData: Rlp] = + var rlp = rlpFromBytes(@msg.toRange) + + let msgid = rlp.read(int) + return (msgId, rlp) \ No newline at end of file diff --git a/tests/p2p/test_rlpx_thunk.json b/tests/p2p/test_rlpx_thunk.json new file mode 100644 index 0000000..a424b1c --- /dev/null +++ b/tests/p2p/test_rlpx_thunk.json @@ -0,0 +1,52 @@ +{ + "Invalid list when decoding for object": { + "payload": "03", + "error": "RlpTypeMismatch", + "description": "Object parameters are expected to be encoded in an RLP list" + }, + "Message id that is not supported": { + "payload": "08", + "error": "UnsupportedMessageError", + "description": "This is a message id not used by devp2p, eth or whisper" + }, + "Message id that is negative": { + "payload": "888888888888888888", + "error": "UnsupportedMessageError", + "description": "This payload will result in a negative number as message id" + }, + "No Hash nor Status, but empty list": { + "payload": "20c1c0", + "error": "RlpTypeMismatch", + "description": "Decoding to HashOrStatus expects blob of size 1 or 32" + }, + "No Hash nor Status, list instead of blob": { + "payload": "20c2c1c0", + "error": "RlpTypeMismatch", + "description": "Decoding to HashOrStatus expects blob of size 1 or 32" + }, + "No Hash nor Status, blob of 2 bytes": { + "payload": "20c4c3820011", + "error": "RlpTypeMismatch", + "description": "Decoding to HashOrStatus expects blob of size 1 or 32" + }, + "No Hash nor Status, blob of 33 bytes": { + "payload": "20e3e2a100112233445566778899aabbccddeeff00112233445566778899aabbcceeddff33", + "error": "RlpTypeMismatch", + "description": "Decoding to HashOrStatus expects blob of size 1 or 32" + }, + "Listing elements when no data": { + "payload": "01e1", + "error": "MalformedRlpError", + "description": "listElem to error on empty list" + }, + "Listing elements when invalid length": { + "payload": "01ffdada", + "error": "MalformedRlpError", + "description": "listElem to error on invalid size encoding" + }, + "Listing elements when not a list": { + "payload": "010a", + "error": "RlpTypeMismatch", + "description": "listElem to assert on not a list" + } +} diff --git a/tests/p2p/test_rlpx_thunk.nim b/tests/p2p/test_rlpx_thunk.nim new file mode 100644 index 0000000..ad5823a --- /dev/null +++ b/tests/p2p/test_rlpx_thunk.nim @@ -0,0 +1,46 @@ +import + json, os, stew/byteutils, unittest, chronos, + eth/p2p, eth/p2p/rlpx_protocols/[whisper_protocol, eth_protocol], + ../p2p/p2p_test_helper + +var + node1: EthereumNode + node2: EthereumNode + peer: Peer + + +node1 = setupTestNode(eth, Whisper) +node2 = setupTestNode(eth, Whisper) + +node2.startListening() +peer = waitFor node1.rlpxConnect(newNode(initENode(node2.keys.pubKey, + node2.address))) + +proc testPayloads(filename: string) = + let js = json.parseFile(filename) + + suite extractFilename(filename): + for testname, testdata in js: + test testname: + let + payloadHex = testdata{"payload"} + error = testdata{"error"} + + if payloadHex.isNil or payloadHex.kind != JString: + skip() + continue + if error.isNil or error.kind != JString: + skip() + continue + + let payload = hexToSeqByte(payloadHex.str) + # TODO: can I convert the error string to an Exception type at runtime? + expect CatchableError: + try: + var (msgId, msgData) = recvMsgMock(payload) + waitFor peer.invokeThunk(msgId.int, msgData) + except CatchableError as e: + check: e.name == error.str + raise + +testPayloads(sourceDir / "test_rlpx_thunk.json")