From 69846a6019114eef57566b59952cb19c22470ecc Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Mon, 9 Dec 2024 10:05:39 -0700 Subject: [PATCH] EIP-7756 Trace updates Update tracing for EIP-7756 changes, mostly swapping hex format and numbers for opcode and gas members. Signed-off-by: Danno Ferrin --- .../internal/processor/TransactionTracer.java | 4 +- .../besu/evmtool/EvmToolCommand.java | 10 +- .../besu/evmtool/StateTestSubCommand.java | 9 +- .../besu/evmtool/T8nServerSubCommand.java | 3 +- .../besu/evmtool/T8nSubCommand.java | 3 +- .../state-test/all-trace-flags-disabled.json | 50 ++++---- .../evmtool/state-test/all-trace-flags.json | 1 + .../besu/evmtool/state-test/blockhash.json | 52 ++++----- .../besu/evmtool/state-test/create-eof.json | 22 ++-- .../state-test/create-invalid-eof.json | 6 +- .../besu/evmtool/state-test/no-memory.json | 50 ++++---- .../state-test/shanghai-blockhash.json | 28 ++--- .../besu/evmtool/trace/badcode.json | 4 +- .../besu/evmtool/trace/charge-intrinsic.json | 108 +++++++++--------- .../besu/evmtool/trace/coinbase-cold.json | 6 +- .../besu/evmtool/trace/coinbase-warm.json | 6 +- .../besu/evmtool/trace/create-eof.json | 16 +-- .../besu/evmtool/trace/eof-section.json | 14 +-- .../hyperledger/besu/evmtool/trace/eof.json | 2 +- .../besu/evmtool/trace/revert.json | 12 +- .../besu/evmtool/trace/warm-contract.json | 108 +++++++++--------- .../besu/evm/tracing/StandardJsonTracer.java | 93 ++++++++++++--- .../besu/evm/StandardJsonTracerTest.java | 77 ++++++++++--- 23 files changed, 402 insertions(+), 282 deletions(-) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/TransactionTracer.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/TransactionTracer.java index 6524109ac6f..460ee2a6427 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/TransactionTracer.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/TransactionTracer.java @@ -136,7 +136,9 @@ public List traceTransactionToFile( stackedUpdater, transaction, transactionProcessor, - new StandardJsonTracer(out, showMemory, true, true, false), + // FIXME // REVIEWME do we want to change the JSON + // debug calls to use EIP-7756 values for gas and opcode? + new StandardJsonTracer(out, showMemory, true, true, false, true), blobGasPrice); out.println( summaryTrace( diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EvmToolCommand.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EvmToolCommand.java index 2574d4b8e39..607d7cf6626 100644 --- a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EvmToolCommand.java +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EvmToolCommand.java @@ -200,6 +200,13 @@ void setBytes(final String optionValue) { scope = INHERIT) final Boolean showJsonAlloc = false; + @Option( + names = {"--eip-3155", "--trace.eip-3155"}, + description = "Produce a trace with types strictly compatible with EIP-3155.", + scope = INHERIT, + negatable = true) + final Boolean eip3155strict = false; + @Option( names = {"--memory", "--trace.memory"}, description = @@ -441,7 +448,8 @@ public void run() { final OperationTracer tracer = // You should have picked Mercy. lastLoop && showJsonResults - ? new StandardJsonTracer(out, showMemory, !hideStack, showReturnData, showStorage) + ? new StandardJsonTracer( + out, showMemory, !hideStack, showReturnData, showStorage, eip3155strict) : OperationTracer.NO_TRACING; WorldUpdater updater = component.getWorldUpdater(); diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/StateTestSubCommand.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/StateTestSubCommand.java index f6e05b5a498..9e99eae4986 100644 --- a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/StateTestSubCommand.java +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/StateTestSubCommand.java @@ -208,7 +208,8 @@ private void traceTestSpecs(final String test, final List stack; - private String gas; + private long gas; private Bytes memory; private int memorySize; private int depth; - private int subdepth; + private int functionDepth; private String storageString; /** @@ -65,11 +66,32 @@ public StandardJsonTracer( final boolean showStack, final boolean showReturnData, final boolean showStorage) { + this(out, showMemory, showStack, showReturnData, showStorage, false); + } + + /** + * Instantiates a new Standard json tracer. + * + * @param out the out + * @param showMemory show memory in trace lines + * @param showStack show the stack in trace lines + * @param showReturnData show return data in trace lines + * @param showStorage show the updated storage + * @param eip3155strict Output EIP-3155 compatible traces + */ + public StandardJsonTracer( + final PrintWriter out, + final boolean showMemory, + final boolean showStack, + final boolean showReturnData, + final boolean showStorage, + final boolean eip3155strict) { this.out = out; this.showMemory = showMemory; this.showStack = showStack; this.showReturnData = showReturnData; this.showStorage = showStorage; + this.eip3155strict = eip3155strict; } /** @@ -95,6 +117,32 @@ public StandardJsonTracer( showStorage); } + /** + * Instantiates a new Standard json tracer. + * + * @param out the out + * @param showMemory show memory in trace lines + * @param showStack show the stack in trace lines + * @param showReturnData show return data in trace lines + * @param showStorage show updated storage + * @param eip3155strict Output eip-3155 compatible traces + */ + public StandardJsonTracer( + final PrintStream out, + final boolean showMemory, + final boolean showStack, + final boolean showReturnData, + final boolean showStorage, + final boolean eip3155strict) { + this( + new PrintWriter(out, true, StandardCharsets.UTF_8), + showMemory, + showStack, + showReturnData, + showStorage, + eip3155strict); + } + /** * Short as hex string. * @@ -125,9 +173,9 @@ public void tracePreExecution(final MessageFrame messageFrame) { for (int i = messageFrame.stackSize() - 1; i >= 0; i--) { stack.add("\"" + shortBytes(messageFrame.getStackItem(i)) + "\""); } - pc = messageFrame.getPC() - messageFrame.getCode().getCodeSection(0).getEntryPoint(); + pc = messageFrame.getPC(); section = messageFrame.getSection(); - gas = shortNumber(messageFrame.getRemainingGas()); + gas = messageFrame.getRemainingGas(); memorySize = messageFrame.memoryWordSize() * 32; if (showMemory && memorySize > 0) { memory = messageFrame.readMemory(0, messageFrame.memoryWordSize() * 32L); @@ -135,7 +183,7 @@ public void tracePreExecution(final MessageFrame messageFrame) { memory = null; } depth = messageFrame.getMessageStackSize(); - subdepth = messageFrame.returnStackSize(); + functionDepth = messageFrame.returnStackSize() + 1; StringBuilder sb = new StringBuilder(); if (showStorage) { @@ -186,20 +234,23 @@ public void tracePostExecution( if (eofContract) { sb.append("\"section\":").append(section).append(","); } - sb.append("\"op\":").append(opcode).append(","); + if (eip3155strict) { + sb.append("\"op\":").append(opcode).append(","); + } else { + sb.append("\"op\":\"").append(fastHexByte(opcode)).append("\","); + } OpcodeInfo opInfo = OpcodeInfo.getOpcode(opcode); if (eofContract && opInfo.pcAdvance() > 1) { - var immediate = - messageFrame - .getCode() - .getBytes() - .slice( - pc + messageFrame.getCode().getCodeSection(0).getEntryPoint() + 1, - opInfo.pcAdvance() - 1); + var immediate = messageFrame.getCode().getBytes().slice(pc + 1, opInfo.pcAdvance() - 1); sb.append("\"immediate\":\"").append(immediate.toHexString()).append("\","); } - sb.append("\"gas\":\"").append(gas).append("\","); - sb.append("\"gasCost\":\"").append(shortNumber(thisGasCost)).append("\","); + if (eip3155strict) { + sb.append("\"gas\":\"").append(shortNumber(gas)).append("\","); + sb.append("\"gasCost\":\"").append(shortNumber(thisGasCost)).append("\","); + } else { + sb.append("\"gas\":").append(Long.toUnsignedString(gas)).append(","); + sb.append("\"gasCost\":").append(Long.toUnsignedString(thisGasCost)).append(","); + } if (memory != null) { sb.append("\"memory\":\"").append(memory.toHexString()).append("\","); } @@ -211,8 +262,8 @@ public void tracePostExecution( sb.append("\"returnData\":\"").append(returnData.toHexString()).append("\","); } sb.append("\"depth\":").append(depth).append(","); - if (subdepth >= 1) { - sb.append("\"functionDepth\":").append(subdepth).append(","); + if (functionDepth > 1) { + sb.append("\"functionDepth\":").append(functionDepth).append(","); } sb.append("\"refund\":").append(messageFrame.getGasRefund()).append(","); sb.append("\"opName\":\"").append(currentOp.getName()).append("\""); @@ -241,4 +292,12 @@ public void traceAccountCreationResult( final MessageFrame frame, final Optional haltReason) { // precompile calls are not part of the standard trace } + + private String fastHexByte(final int b) { + char[] result = new char[] {'0', 'x', '-', '-'}; + result[2] = "0123456789abcdef".charAt(b >> 4 & 15); + result[3] = "0123456789abcdef".charAt(b & 15); + + return new String(result); + } } diff --git a/evm/src/test/java/org/hyperledger/besu/evm/StandardJsonTracerTest.java b/evm/src/test/java/org/hyperledger/besu/evm/StandardJsonTracerTest.java index 4f18f582d1a..8b18d70ac8e 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/StandardJsonTracerTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/StandardJsonTracerTest.java @@ -30,12 +30,12 @@ class StandardJsonTracerTest { @Test - void eip3155ModifiedTestCase() { + void eip3155ModifiedTestCaseStrictTypes() { ByteArrayOutputStream baos = new ByteArrayOutputStream(); PrintStream out = new PrintStream(baos); var executor = EVMExecutor.evm(EvmSpecVersion.ISTANBUL); - StandardJsonTracer tracer = new StandardJsonTracer(out, true, true, true, false); + StandardJsonTracer tracer = new StandardJsonTracer(out, true, true, true, false, true); executor.tracer(tracer); executor.gas(10_000_000_000L); @@ -72,6 +72,49 @@ void eip3155ModifiedTestCase() { """); } + @Test + void eip3155ModifiedTestCase() { + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PrintStream out = new PrintStream(baos); + var executor = EVMExecutor.evm(EvmSpecVersion.ISTANBUL); + StandardJsonTracer tracer = new StandardJsonTracer(out, true, true, true, false); + executor.tracer(tracer); + executor.gas(10_000_000_000L); + + var codeBytes = Bytes.fromHexString("0x604080536040604055604060006040600060025afa6040f3"); + executor.execute(codeBytes, Bytes.EMPTY, Wei.ZERO, Address.ZERO); + + // differences from the EIP-3155 test case + // (a) the test case was written when EIP-2315 was part of the pending hard fork, so + // returnStack was a valid field. It no longer appears in any traces. + // (b) the summary line is omitted + // (c) pc:3 is in error, the size of the memory before the first MSTORE8 is zero. + // (d) if memory is zero length, it is not included even if `showMemory` is true + // (e) if return data is zero length or null, it is not included even if `showReturnData` is + // true + // (f) if error is zero length or null it is not included. + assertThat(baos) + .hasToString( + """ + {"pc":0,"op":"0x60","gas":10000000000,"gasCost":3,"memSize":0,"stack":[],"depth":1,"refund":0,"opName":"PUSH1"} + {"pc":2,"op":"0x80","gas":9999999997,"gasCost":3,"memSize":0,"stack":["0x40"],"depth":1,"refund":0,"opName":"DUP1"} + {"pc":3,"op":"0x53","gas":9999999994,"gasCost":12,"memSize":0,"stack":["0x40","0x40"],"depth":1,"refund":0,"opName":"MSTORE8"} + {"pc":4,"op":"0x60","gas":9999999982,"gasCost":3,"memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":[],"depth":1,"refund":0,"opName":"PUSH1"} + {"pc":6,"op":"0x60","gas":9999999979,"gasCost":3,"memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":["0x40"],"depth":1,"refund":0,"opName":"PUSH1"} + {"pc":8,"op":"0x55","gas":9999999976,"gasCost":20000,"memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":["0x40","0x40"],"depth":1,"refund":0,"opName":"SSTORE"} + {"pc":9,"op":"0x60","gas":9999979976,"gasCost":3,"memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":[],"depth":1,"refund":0,"opName":"PUSH1"} + {"pc":11,"op":"0x60","gas":9999979973,"gasCost":3,"memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":["0x40"],"depth":1,"refund":0,"opName":"PUSH1"} + {"pc":13,"op":"0x60","gas":9999979970,"gasCost":3,"memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":["0x40","0x0"],"depth":1,"refund":0,"opName":"PUSH1"} + {"pc":15,"op":"0x60","gas":9999979967,"gasCost":3,"memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":["0x40","0x0","0x40"],"depth":1,"refund":0,"opName":"PUSH1"} + {"pc":17,"op":"0x60","gas":9999979964,"gasCost":3,"memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":["0x40","0x0","0x40","0x0"],"depth":1,"refund":0,"opName":"PUSH1"} + {"pc":19,"op":"0x5a","gas":9999979961,"gasCost":2,"memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":["0x40","0x0","0x40","0x0","0x2"],"depth":1,"refund":0,"opName":"GAS"} + {"pc":20,"op":"0xfa","gas":9999979959,"gasCost":9843730284,"memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":["0x40","0x0","0x40","0x0","0x2","0x2540b95b7"],"depth":1,"refund":0,"opName":"STATICCALL"} + {"pc":21,"op":"0x60","gas":9999979175,"gasCost":3,"memory":"0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b00000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":["0x1"],"returnData":"0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b","depth":1,"refund":0,"opName":"PUSH1"} + {"pc":23,"op":"0xf3","gas":9999979172,"gasCost":0,"memory":"0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b00000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":["0x1","0x40"],"returnData":"0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b","depth":1,"refund":0,"opName":"RETURN"} + """); + } + @Test void updatedStorageTestCase() { @@ -88,21 +131,21 @@ void updatedStorageTestCase() { assertThat(baos) .hasToString( """ - {"pc":0,"op":96,"gas":"0x2540be400","gasCost":"0x3","memSize":0,"depth":1,"refund":0,"opName":"PUSH1"} - {"pc":2,"op":128,"gas":"0x2540be3fd","gasCost":"0x3","memSize":0,"depth":1,"refund":0,"opName":"DUP1"} - {"pc":3,"op":83,"gas":"0x2540be3fa","gasCost":"0xc","memSize":0,"depth":1,"refund":0,"opName":"MSTORE8"} - {"pc":4,"op":96,"gas":"0x2540be3ee","gasCost":"0x3","memSize":96,"depth":1,"refund":0,"opName":"PUSH1"} - {"pc":6,"op":96,"gas":"0x2540be3eb","gasCost":"0x3","memSize":96,"depth":1,"refund":0,"opName":"PUSH1"} - {"pc":8,"op":85,"gas":"0x2540be3e8","gasCost":"0x4e20","memSize":96,"depth":1,"refund":0,"opName":"SSTORE"} - {"pc":9,"op":96,"gas":"0x2540b95c8","gasCost":"0x3","memSize":96,"depth":1,"refund":0,"opName":"PUSH1","storage":{"0x40":"0x40"}} - {"pc":11,"op":96,"gas":"0x2540b95c5","gasCost":"0x3","memSize":96,"depth":1,"refund":0,"opName":"PUSH1","storage":{"0x40":"0x40"}} - {"pc":13,"op":96,"gas":"0x2540b95c2","gasCost":"0x3","memSize":96,"depth":1,"refund":0,"opName":"PUSH1","storage":{"0x40":"0x40"}} - {"pc":15,"op":96,"gas":"0x2540b95bf","gasCost":"0x3","memSize":96,"depth":1,"refund":0,"opName":"PUSH1","storage":{"0x40":"0x40"}} - {"pc":17,"op":96,"gas":"0x2540b95bc","gasCost":"0x3","memSize":96,"depth":1,"refund":0,"opName":"PUSH1","storage":{"0x40":"0x40"}} - {"pc":19,"op":90,"gas":"0x2540b95b9","gasCost":"0x2","memSize":96,"depth":1,"refund":0,"opName":"GAS","storage":{"0x40":"0x40"}} - {"pc":20,"op":250,"gas":"0x2540b95b7","gasCost":"0x24abb676c","memSize":96,"depth":1,"refund":0,"opName":"STATICCALL","storage":{"0x40":"0x40"}} - {"pc":21,"op":96,"gas":"0x2540b92a7","gasCost":"0x3","memSize":96,"depth":1,"refund":0,"opName":"PUSH1","storage":{"0x40":"0x40"}} - {"pc":23,"op":243,"gas":"0x2540b92a4","gasCost":"0x0","memSize":96,"depth":1,"refund":0,"opName":"RETURN","storage":{"0x40":"0x40"}} + {"pc":0,"op":"0x60","gas":10000000000,"gasCost":3,"memSize":0,"depth":1,"refund":0,"opName":"PUSH1"} + {"pc":2,"op":"0x80","gas":9999999997,"gasCost":3,"memSize":0,"depth":1,"refund":0,"opName":"DUP1"} + {"pc":3,"op":"0x53","gas":9999999994,"gasCost":12,"memSize":0,"depth":1,"refund":0,"opName":"MSTORE8"} + {"pc":4,"op":"0x60","gas":9999999982,"gasCost":3,"memSize":96,"depth":1,"refund":0,"opName":"PUSH1"} + {"pc":6,"op":"0x60","gas":9999999979,"gasCost":3,"memSize":96,"depth":1,"refund":0,"opName":"PUSH1"} + {"pc":8,"op":"0x55","gas":9999999976,"gasCost":20000,"memSize":96,"depth":1,"refund":0,"opName":"SSTORE"} + {"pc":9,"op":"0x60","gas":9999979976,"gasCost":3,"memSize":96,"depth":1,"refund":0,"opName":"PUSH1","storage":{"0x40":"0x40"}} + {"pc":11,"op":"0x60","gas":9999979973,"gasCost":3,"memSize":96,"depth":1,"refund":0,"opName":"PUSH1","storage":{"0x40":"0x40"}} + {"pc":13,"op":"0x60","gas":9999979970,"gasCost":3,"memSize":96,"depth":1,"refund":0,"opName":"PUSH1","storage":{"0x40":"0x40"}} + {"pc":15,"op":"0x60","gas":9999979967,"gasCost":3,"memSize":96,"depth":1,"refund":0,"opName":"PUSH1","storage":{"0x40":"0x40"}} + {"pc":17,"op":"0x60","gas":9999979964,"gasCost":3,"memSize":96,"depth":1,"refund":0,"opName":"PUSH1","storage":{"0x40":"0x40"}} + {"pc":19,"op":"0x5a","gas":9999979961,"gasCost":2,"memSize":96,"depth":1,"refund":0,"opName":"GAS","storage":{"0x40":"0x40"}} + {"pc":20,"op":"0xfa","gas":9999979959,"gasCost":9843730284,"memSize":96,"depth":1,"refund":0,"opName":"STATICCALL","storage":{"0x40":"0x40"}} + {"pc":21,"op":"0x60","gas":9999979175,"gasCost":3,"memSize":96,"depth":1,"refund":0,"opName":"PUSH1","storage":{"0x40":"0x40"}} + {"pc":23,"op":"0xf3","gas":9999979172,"gasCost":0,"memSize":96,"depth":1,"refund":0,"opName":"RETURN","storage":{"0x40":"0x40"}} """); } }