From e07898f94937c4e8c617639b52eae4ae61675ff8 Mon Sep 17 00:00:00 2001 From: jangko Date: Thu, 15 Dec 2022 13:30:18 +0700 Subject: [PATCH] add more test cases to txparse tool --- nimbus/graphql/ethapi.nim | 4 +- nimbus/rpc/p2p.nim | 2 +- nimbus/rpc/rpc_utils.nim | 2 +- nimbus/transaction.nim | 6 ++ tools/txparse/testdata/rlp.json | 54 +++++++++++++++++ tools/txparse/testdata/sample.json | 38 ++++++++++++ tools/txparse/testdata/values.json | 22 +++++++ tools/txparse/txparse.nim | 11 +++- tools/txparse/txparse_test.nim | 94 ++++++++++++++++++++++++++++++ 9 files changed, 227 insertions(+), 6 deletions(-) create mode 100644 tools/txparse/testdata/rlp.json create mode 100644 tools/txparse/testdata/sample.json create mode 100644 tools/txparse/testdata/values.json create mode 100644 tools/txparse/txparse_test.nim diff --git a/nimbus/graphql/ethapi.nim b/nimbus/graphql/ethapi.nim index c6e2f86ad..9217f9225 100644 --- a/nimbus/graphql/ethapi.nim +++ b/nimbus/graphql/ethapi.nim @@ -260,7 +260,7 @@ proc getTxs(ctx: GraphqlContextRef, header: BlockHeader): RespResult = var list = respList() var index = 0 for n in getBlockTransactionData(ctx.chainDB, header.txRoot): - let tx = rlp.decode(n, Transaction) + let tx = decodeTx(n) list.add txNode(ctx, tx, index, header.blockNumber, header.fee) inc index @@ -1224,7 +1224,7 @@ proc sendRawTransaction(ud: RootRef, params: Args, parent: Node): RespResult {.a let ctx = GraphqlContextRef(ud) try: let data = hexToSeqByte(params[0].val.stringVal) - let _ = rlp.decode(data, Transaction) # we want to know if it is a valid tx blob + let _ = decodeTx(data) # we want to know if it is a valid tx blob let txHash = keccakHash(data) resp(txHash) except Exception as em: diff --git a/nimbus/rpc/p2p.nim b/nimbus/rpc/p2p.nim index 6336ac163..7120a08e9 100644 --- a/nimbus/rpc/p2p.nim +++ b/nimbus/rpc/p2p.nim @@ -268,7 +268,7 @@ proc setupEthRpc*( ## Note: Use eth_getTransactionReceipt to get the contract address, after the transaction was mined, when you created a contract. let txBytes = hexToSeqByte(data.string) - signedTx = rlp.decode(txBytes, Transaction) + signedTx = decodeTx(txBytes) txPool.add(signedTx) result = keccakHash(txBytes).ethHashStr diff --git a/nimbus/rpc/rpc_utils.nim b/nimbus/rpc/rpc_utils.nim index a2b47468f..3221685df 100644 --- a/nimbus/rpc/rpc_utils.nim +++ b/nimbus/rpc/rpc_utils.nim @@ -59,7 +59,7 @@ proc calculateMedianGasPrice*(chain: ChainDBRef): GasInt = var prices = newSeqOfCap[GasInt](64) let header = chain.getCanonicalHead() for encodedTx in chain.getBlockTransactionData(header.txRoot): - let tx = rlp.decode(encodedTx, Transaction) + let tx = decodeTx(encodedTx) prices.add(tx.gasPrice) if prices.len > 0: diff --git a/nimbus/transaction.nim b/nimbus/transaction.nim index 61452c8bf..15c572611 100644 --- a/nimbus/transaction.nim +++ b/nimbus/transaction.nim @@ -177,3 +177,9 @@ func effectiveGasTip*(tx: Transaction; baseFee: Option[UInt256]): GasInt = maxFee = tx.gasPrice min(maxPriorityFee, maxFee - baseFee) + +proc decodeTx*(bytes: openArray[byte]): Transaction = + var rlp = rlpFromBytes(bytes) + result = rlp.read(Transaction) + if rlp.hasData: + raise newException(RlpError, "rlp: input contains more than one value") diff --git a/tools/txparse/testdata/rlp.json b/tools/txparse/testdata/rlp.json new file mode 100644 index 000000000..bd447bf13 --- /dev/null +++ b/tools/txparse/testdata/rlp.json @@ -0,0 +1,54 @@ +[ +{ + "input": "0xc3303030", + "error": true +}, +{ + "input": "0xf85f030182520894b94f5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca098ff921201554726367d2be8c804a7ff898af285ebc57dffcce4c44b9c19ac4aa01887321be536891275ec75c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3", + "error": true +}, +{ + "input": "0xf85f030182520894b94f5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca098ff921201554726367d2be8c804a7ff898af285ebc57dffcce4c44b9c19ac4aa01887321be536891275ec75c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3", + "error": true +}, +{ + "input": "0xf85f030182520894b94f5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca098ff921201554726367d2be8c804a7ff898af285ebc57dffcce4c44b9c19ac4aa01887321be536891275ec75c8095f789dd4c743dfe42c1820f9231f98a962b210e3", + "error": true +}, +{ + "input": "0xf85f011082520894f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f001801ca06f0010ff4c31c2a6d0526c0d414e6cd01ad5d22e15bfff98af23867366b94d87a05413392d556119132da7056f8fb56a91384848484848484848484848484848484848484848484848a36446a8a4ad7159c9d892d9f32284", + "error": true +}, +{ + "input": "0xf85f011082520894f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f001801ca06f0010ff4c31c2a6d0526c0d414e6cd01ad5d22e15bfff98af23867366b94d87a05413392d556119132da7056f8fb56a91384848484848484848484848484848484848484848484848a36446a8a4ad7159c9d892d9f32284", + "error": true +}, +{ + "input": "0xf85f011082520894f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f001801ca06f0010ff4c31c2a6d0526c0d414e6cd01ad5d22e15bfff98af23867366b94d87a05413392d556119132da7056f8fb56a913848484848484848484848484848484848484848484848", + "error": true +}, +{ + "input": "0xf85f011082520894f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f001801ca06f0010ff4c31c2a6d0526c0d414e6cd01ad5d22e15bfff98af23867366b94d87a05413392d556119132da7056f8fb56a9138484848484848484848484848484848484848", + "error": true +}, +{ + "input": "0xf85f011082520894f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f001801ca06f0010ff4c31c2a6d0526c0d414e6cd01ad5d22e15bfff98af23867366b94d87a05413392d556119132da7056f8fb56a913848484848484848484848484848484848", + "error": true +}, +{ + "input": "0xf867078504a817c807830290409435353535353535353535353535353535353535358201578025a052f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021a044444452f1a9b320cab34e4ea8a8f97989383aab0a49165fc91c737310e4f7e9821021", + "error": true +}, +{ + "input": "0xf867078504a817c807830290409435353535353535353535353535353535353535358201578025a052f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021a044444452f1a9b320cab34e4ea8a8f97989383aab0a49165fc91c737310e4f7e9821021", + "error": true +}, +{ + "input": "0xf867078504a817c807830290409435353535353535353535353535353535353535358201578025a052f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021a044444452f1a9b320cab34e4ea8a8f97989383aab0a49165fc91c737310e4f7e982", + "error": true +}, +{ + "input": "0xf85f300182520894b94f5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca098ff921201554726367d2be8c804a7ff898af285ebc57dffcce4c44b9c19ac4aa01887321be536891275ec75c8095f789dd4c743dfe42c1820f9231f98a962b210e3", + "error": true +} +] \ No newline at end of file diff --git a/tools/txparse/testdata/sample.json b/tools/txparse/testdata/sample.json new file mode 100644 index 000000000..df4f84b7f --- /dev/null +++ b/tools/txparse/testdata/sample.json @@ -0,0 +1,38 @@ +[ +{ + "input": "test", + "error": true +}, +{ + "input": "monkey", + "error": true +}, +{ + "input": "0x1", + "error": true +}, +{ + "input": "0x112391201239129312392139123 123 12 312 312 3", + "error": true +}, +{ + "input": "0xdead", + "error": true +}, +{ + "input": "0xf8d2b86702f864010180820fa08284d09411111111111111111111111111111111111111118080c001a0b7dfab36232379bb3d1497a4f91c1966b1f932eae3ade107bf5d723b9cb474e0a06261c359a10f2132f126d250485b90cf20f30340801244a08ef6142ab33d1904b86702f864010280820fa08284d09411111111111111111111111111111111111111118080c080a0d4ec563b6568cd42d998fc4134b36933c6568d01533b5adf08769270243c6c7fa072bf7c21eac6bbeae5143371eef26d5e279637f3bd73482b55979d76d935b1e9", + "error": true +}, +{ + "input": "02f864010180820fa08284d09411111111111111111111111111111111111111118080c001a0b7dfab36232379bb3d1497a4f91c1966b1f932eae3ade107bf5d723b9cb474e0a06261c359a10f2132f126d250485b90cf20f30340801244a08ef6142ab33d1904", + "error": false +}, +{ + "input": "0x02f864010180820fa08284d09411111111111111111111111111111111111111118080c001a0b7dfab36232379bb3d1497a4f91c1966b1f932eae3ade107bf5d723b9cb474e0a06261c359a10f2132f126d250485b90cf20f30340801244a08ef6142ab33d1904", + "error": false +}, +{ + "input": "deadest", + "error": true +} +] \ No newline at end of file diff --git a/tools/txparse/testdata/values.json b/tools/txparse/testdata/values.json new file mode 100644 index 000000000..7071e142a --- /dev/null +++ b/tools/txparse/testdata/values.json @@ -0,0 +1,22 @@ +[ +{ + "input": "0xf8638080830f424094095e7baea6a6c7c4c2dfeb977efac326af552d87830186a0801ba0ffffffffffc771bcbc70778d6effffffffffffffffffffffffffffffffffffffa0badf00d70ec28c94a3b55ec771bcbc70778d6ee0b51ca7ea9514594c861b1884", + "error": true +}, +{ + "input": "0xf8638080830f424094095e7baea6a6c7c4c2dfeb977ed8c326af552d87830186a0801ba0ffffffffffc771bcbc70778d6effffffffffffffffffffffffffffffffffffffa0badf00d70ec28c94a3b55ec771bcbc70778d6ee0b51ca7ea9514594c861b1884", + "error": true +}, +{ + "input": "0xf8638080830f424094095e7baea68000c4c2dfeb977efac326af552d87830186a0801ba0ffffffffffffff20ffffffffffffffffffffffffffffffffffffffffffffffffa0badf00d70ee08c94a3b55ec771bcbc70778d6ee0b51ca7ea9514594c861b1884", + "error": true +}, +{ + "input": "0xf8638080830f424094095e7baea6a6c7c4c2dfeb977efac326af552d87830186a0801ba0ffffffffff181818181818ffffffffffffffffffffffffffffffffffffffffffa0badf00d70ec28c94a3b55ec771bcbc70778d6ee0b51ca7ea9514594c861b1884", + "error": true +}, +{ + "input": "0xf85f030182520894b94f5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca098ff921201554726367d2be8c804a7ff898af285ebc57dffcce4c44b9c19ac4aa087321be536891275ec75c8095f789dd4c743dfe42c1820f9231f98a962b210e3", + "error": true +} +] \ No newline at end of file diff --git a/tools/txparse/txparse.nim b/tools/txparse/txparse.nim index 5b2830b81..a0780b65f 100644 --- a/tools/txparse/txparse.nim +++ b/tools/txparse/txparse.nim @@ -11,15 +11,18 @@ import eth/[common, rlp], stew/byteutils, - ../../nimbus/transaction + ../../nimbus/transaction, + ../../nimbus/common/evmforks proc parseTx(hexLine: string) = try: let bytes = hexToSeqByte(hexLine) - tx = rlp.decode(bytes, Transaction) + tx = decodeTx(bytes) address = tx.getSender() + tx.validate(FkLondon) + # everything ok echo "0x", address.toHex @@ -29,6 +32,10 @@ proc parseTx(hexLine: string) = echo "err: ", ex.msg except ValidationError as ex: echo "err: ", ex.msg + except Exception: + # TODO: rlp.hasData assertion should be + # changed into RlpError + echo "err: malformed rlp" proc main() = for hexLine in stdin.lines: diff --git a/tools/txparse/txparse_test.nim b/tools/txparse/txparse_test.nim new file mode 100644 index 000000000..73dd9e1ab --- /dev/null +++ b/tools/txparse/txparse_test.nim @@ -0,0 +1,94 @@ +# Nimbus +# Copyright (c) 2022 Status Research & Development GmbH +# Licensed under either of +# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or +# http://www.apache.org/licenses/LICENSE-2.0) +# * MIT license ([LICENSE-MIT](LICENSE-MIT) or +# http://opensource.org/licenses/MIT) +# at your option. This file may not be copied, modified, or distributed except +# according to those terms. + +import + std/[os, osproc, strutils, json, streams], + unittest2 + +type + TestFile = object + fullPath: string + dispName: string + +const + testData = "tools" / "txparse" / "testdata" + +proc runTest(n: JsonNode): bool = + let + appDir = getAppDir() + cmd = appDir / "txparse" + input = n["input"].getStr + p = startProcess(cmd, options = + {poStdErrToStdOut, poUsePath, poEvalCommand}) + inp = inputStream(p) + outp = outputStream(p) + + inp.write(input) + inp.close() + + var + exitCode = -1 + line = newStringOfCap(120).TaintedString + res = "" + + while true: + if outp.readLine(line): + res.add(line.string) + res.add("\n") + else: + exitCode = peekExitCode(p) + if exitCode != -1: break + + close(p) + + if exitCode != QuitSuccess: + echo "txparse execution error: ", res + return false + + let mustError = n["error"].getBool + if mustError: + if "err:" notin res: + echo "txparse result error: ", res + return false + else: + let cleanRes = strip(res) + if not cleanRes.startsWith("0x") and cleanRes.len != 42: + echo "txparse result error: ", res + return false + + true + +proc runTest(fileName: string): bool = + let n = json.parseFile(fileName) + result = true + for x in n: + let res = runTest(x) + result = result and res + +proc collectFileNames(inputPath: string, fileNames: var seq[TestFile]) = + for filename in walkDirRec(inputPath): + if not fileName.endsWith(".json"): + continue + + fileNames.add TestFile( + fullPath: filename, + dispName: substr(filename, inputPath.len+1) + ) + +proc main() = + suite "txparse test suite": + var filenames: seq[TestFile] = @[] + collectFileNames(testData, filenames) + + for input in filenames: + test input.dispName: + let res = runTest(input.fullPath) + check true == res +main()