From b5c7a1578347239933be0876b805d17b3be2e4cb Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Thu, 15 Aug 2024 11:05:19 -0600 Subject: [PATCH] Update EIP-3155: Move to Draft Merged by EIP-Bot. --- EIPS/eip-3155.md | 210 +++++++++++++++++++++++++---------------------- 1 file changed, 110 insertions(+), 100 deletions(-) diff --git a/EIPS/eip-3155.md b/EIPS/eip-3155.md index 8d55f3e2e2cbf1..2d28a2d49f8d08 100644 --- a/EIPS/eip-3155.md +++ b/EIPS/eip-3155.md @@ -1,167 +1,177 @@ --- eip: 3155 title: EVM trace specification +description: A JSON format for EVM traces author: Martin Holst Swende (@holiman), Marius van der Wijden (@MariusVanDerWijden) discussions-to: https://ethereum-magicians.org/t/eip-3155-create-evm-trace-specification/5007 -status: Stagnant +status: Draft type: Standards Track category: Interface created: 2020-12-07 --- +## Abstract -## Simple Summary -Introduce a new JSON standard for EVM traces during execution of state tests. +Introduce a new JSON standard for EVM traces during execution of state tests. ## Motivation -The Ethereum Virtual Machine executes all smart contract code on ethereum. -In order to debug smart contracts and state tests better, a common format was introduced to log every execution step of the EVM. -This format was implemented by go-ethereum, parity, nethermind and Besu. -Since the common format was not well defined, the implementations differed slightly making it hard to develop adequate tooling which reduces the usefulness of tracing significantly. -This EIP has multiple objectives: +The Ethereum Virtual Machine executes all smart contract code on ethereum. +In order to debug smart contracts and state tests better, a common format was introduced to log every execution step of the EVM. +This format was implemented by Go-Ethereum, Parity-Ethereum, Nethermind and Besu. +Since the common format was not well-defined, the implementations differed slightly, making it hard to develop adequate tooling which reduces the usefulness of tracing significantly. + +This EIP has multiple goals: + - Move the specification to a more visible place to encourage new clients to implement it - Strictly define corner cases that were not addressed in the previous version - Allow for updates to the specification in case new fields are introduced during execution - Provide sample output Implementing this EIP in all major clients allows us to create meaningful differential fuzzers that fuzz EVM implementations for the mainnet and all upcoming hardforks. -It also helps finding differences in execution quickly in the case of a chain split. +It also helps to find differences in execution quickly in the case of a chain split. -This EIP will enable users to create better differential fuzzing infrastructure to compare the EVM implementations of all major Ethereum clients against each other. -This could help to find bugs that are currently present in the client implementations. +This EIP will enable users to create better differential fuzzing infrastructure to compare the EVM implementations of all major Ethereum clients against each other. +This could help to find bugs that are currently present in the client implementations. ## Specification -Clients should be able to execute simple transactions as well as code and return traces. In the following, we will call this client CUT (client under test) and use go-ethereums `evm` binary for code examples. + +Clients should be able to execute simple transactions as well as code and return traces. In the following, we will call this client CUT (client under test) and use go-ethereum's +`evm` binary for code examples. ### Datatypes -| Type | Explanation | Example | -|---|---|---| -| Number | Plain json number | "pc":0 | -| Hex-Number | Hex-encoded number | "gas":"0x2540be400" | -| String | Plain string | "opName":"PUSH1" | -| Hex-String | Hex-encoded string | | -| Array of x | Array of x encoded values | | -| Key-Value | Key-Value structure with key and values encoded as hex strings | | -| Boolean | Json bool can either be true or false | "pass": true | +| Type | Explanation | Example | +|------------|----------------------------------------------------------------|---------------------| +| Number | Plain json number | "pc":0 | +| Hex-Number | Hex-encoded number | "gas":"0x2540be400" | +| String | Plain string | "opName":"PUSH1" | +| Hex-String | Hex-encoded string | | +| Array of x | Array of x encoded values | | +| Key-Value | Key-Value structure with key and values encoded as hex strings | | +| Boolean | Json bool can either be true or false | "pass": true | ### Output -The CUT MUST output a `json` object for EACH operation. - -Required Fields: - -| Name | Type | Explanation | -|---|---|---| -| `pc` | Number | Program Counter | -| `op` | Number | OpCode | -| `gas` | Hex-Number | Gas left before executing this operation | -| `gasCost` | Hex-Number | Gas cost of this operation | -| `stack` | Array of Hex-Numbers | Array of all values on the stack | -| `depth` | Number | Depth of the call stack | -| `returnData` | Hex-String | Data returned by function call | -| `refund` | Hex-Number | Amount of **global** gas refunded | -| `memSize` | Number | Size of memory array | - -Optional Fields: - -| Name | Type | Explanation | -|---|---|---| -| `opName` | String | Name of the operation | -| `error` | Hex-String | Description of an error (should contain revert reason if supported) | -| `memory` | Array of Hex-Strings | Array of all allocated values | -| `storage` | Key-Value | Array of all stored values | -| `returnStack` | Array of Hex-Numbers | Array of values, Stack of the called function | - -*Example:* +The CUT MUST output a `json` object for EACH operation. + +#### Required Fields + +| Name | Type | Explanation | +|--------------|----------------------|------------------------------------------| +| `pc` | Number | Program Counter | +| `op` | Number | OpCode | +| `gas` | Hex-Number | Gas left before executing this operation | +| `gasCost` | Hex-Number | Gas cost of this operation | +| `memSize` | Number | Size of memory array | +| `stack` | Array of Hex-Numbers | Array of all values on the stack | +| `depth` | Number | Depth of the call stack | +| `returnData` | Hex-String | Data returned by function call | +| `refund` | Hex-Number | Amount of **global** gas refunded | + +#### Optional Fields + +| Name | Type | Explanation | +|---------------|----------------------|---------------------------------------------------------------------| +| `opName` | String | Name of the operation | +| `error` | Hex-String | Description of an error (should contain revert reason if supported) | +| `memory` | Array of Hex-Strings | Array of all allocated values | +| `storage` | Key-Value | Array of all stored values | + +*Example:* + ``` {"pc":0,"op":96,"gas":"0x2540be400","gasCost":"0x3","memory":"0x","memSize":0,"stack":[],"depth":1,"error":null,"opName":"PUSH1"} ``` -The `stack`, `memory` and `memSize` are the values _before_ execution of the op. -All array attributes (`stack`, `returnStack`, `memory`) MUST be initialized to empty arrays ("stack":[],) NOT to null. -If the CUT will not output values for `memory` or `storage` then the `memory` and `storage` fields are omitted. -This can happen either because the CUT does not support tracing these fields or it has been configured not to trace it. -The `memSize` field MUST be present regardless of `memory` support. -Clients SHOULD implement a way to disable recording the storage as the stateroot includes all storage updates. -Clients SHOULD output the fields in the same order as listed in this EIP. +- The `stack`, `memory` and `memSize` are the values *before* execution of the op. +- All array attributes (`stack`, `memory`) MUST be initialized to empty arrays (`"stack":[]`) NOT to null. +- If the CUT will not be outputting values for `memory` or `storage` then the `memory` and `storage` fields are omitted. + This can happen either because the CUT does not support tracing these fields or it has been configured not to trace it. +- The `memSize` field MUST be present regardless of `memory` support. +- Clients SHOULD implement a way to disable recording the storage as the stateroot includes all storage updates. +- Clients SHOULD output the fields in the same order as listed in this EIP. The CUT MUST NOT output a line for the `STOP` operation if an error occurred: -*Example:* + +*Example:* + ``` {"pc":2,"op":0,"gas":"0x2540be3fd","gasCost":"0x0","memory":"0x","memSize":0,"stack":["0x40"],"depth":1,"error":null,"opName":"STOP"} ``` -### Summary and error handling +### Summary and Error Handling -At the end of execution, the CUT MUST print some summerical info, this info SHOULD have the following fields. +At the end of execution, the CUT MUST print summary info; this info SHOULD have the following fields. The summary should be a single `jsonl` object. -Required Fields: +#### Required Fields + +| Name | Type | Explanation | +|-------------|------------|--------------------------------------------------------| +| `stateRoot` | Hex-String | Root of the state trie after executing the transaction | +| `output` | | Return values of the function | +| `gasUsed` | Hex-Number | All gas used by the transaction | +| `pass` | Boolean | Bool whether transaction was executed successfully | -| Name | Type | Explanation | -|---|---|---| -| `stateRoot` | Hex-String | Root of the state trie after executing the transaction | -| `output` | | Return values of the function | -| `gasUsed` | Hex-Number | All gas used by the transaction | -| `pass` | Boolean | Bool whether transaction was executed successfully | +#### Optional Fields -OptionalFields: +| Name | Type | Explanation | +|--------|--------|-------------------------------------------------------| +| `time` | Number | Time in nanoseconds needed to execute the transaction | +| `fork` | String | Name of the fork rules used for execution | + +*Example*: -| Name | Type | Explanation | -|---|---|---| -| `time` | Number | Time in nanoseconds needed to execute the transaction | -| `fork` | String | Name of the fork rules used for execution | ``` -{"stateRoot":"0xd4c577737f5d20207d338c360c42d3af78de54812720e3339f7b27293ef195b7","output":"","gasUsed":"0x3","successful":"true","time":141485} +{"stateRoot":"0xd4c577737f5d20207d338c360c42d3af78de54812720e3339f7b27293ef195b7","output":"","gasUsed":"0x3","pass":"true","time":141485} ``` ## Rationale -This EIP is largely based on the previous non-official documentation for EVM tracing. + +This EIP is largely based on the previous non-official documentation for EVM tracing. It tries to cover as many corner cases as possible to enable true client compatibility. The datatypes and if a field is optional is chosen to be as compatible with current implementations as possible. ## Backwards Compatibility + This EIP is fully backward compatible with ethereum as it only introduces a better tracing infrastructure that is optional for clients to implement. ### Clients -This EIP is fully backward compatible with go-ethereum. OpenEthereum, Besu and Nethermind clients would have to change their JSON output of `openethereum-evm` `evmtool` and `nethtest` slightly do adhere to the new and stricter specs. New clients would need to implement this change if they want to be part of the differential fuzzing group. + +This EIP is fully backward compatible with go-ethereum. OpenEthereum, Besu and Nethermind clients would have to change their JSON output of +`openethereum-evm` `evmtool` and +`nethtest` slightly do adhere to the new and stricter specs. New clients would need to implement this change if they want to be part of the differential fuzzing group. ## Test Cases ```bash - ~/go/src/github.com/ethereum/go-ethereum/build/bin/evm --code 604080536040604055604060006040600060025afa6040f3 --json run -{"pc":0,"op":96,"gas":"0x2540be400","gasCost":"0x3","memory":"0x","memSize":0,"stack":[],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"PUSH1","error":""} -{"pc":2,"op":128,"gas":"0x2540be3fd","gasCost":"0x3","memory":"0x","memSize":0,"stack":["0x40"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"DUP1","error":""} -{"pc":3,"op":83,"gas":"0x2540be3fa","gasCost":"0xc","memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":["0x40","0x40"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"MSTORE8","error":""} -{"pc":4,"op":96,"gas":"0x2540be3ee","gasCost":"0x3","memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":[],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"PUSH1","error":""} -{"pc":6,"op":96,"gas":"0x2540be3eb","gasCost":"0x3","memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":["0x40"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"PUSH1","error":""} -{"pc":8,"op":85,"gas":"0x2540be3e8","gasCost":"0x4e20","memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":["0x40","0x40"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"SSTORE","error":""} -{"pc":9,"op":96,"gas":"0x2540b95c8","gasCost":"0x3","memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":[],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"PUSH1","error":""} -{"pc":11,"op":96,"gas":"0x2540b95c5","gasCost":"0x3","memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":["0x40"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"PUSH1","error":""} -{"pc":13,"op":96,"gas":"0x2540b95c2","gasCost":"0x3","memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":["0x40","0x0"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"PUSH1","error":""} -{"pc":15,"op":96,"gas":"0x2540b95bf","gasCost":"0x3","memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":["0x40","0x0","0x40"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"PUSH1","error":""} -{"pc":17,"op":96,"gas":"0x2540b95bc","gasCost":"0x3","memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":["0x40","0x0","0x40","0x0"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"PUSH1","error":""} -{"pc":19,"op":90,"gas":"0x2540b95b9","gasCost":"0x2","memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":["0x40","0x0","0x40","0x0","0x2"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"GAS","error":""} -{"pc":20,"op":250,"gas":"0x2540b95b7","gasCost":"0x24abb676c","memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":["0x40","0x0","0x40","0x0","0x2","0x2540b95b7"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"STATICCALL","error":""} -{"pc":21,"op":96,"gas":"0x2540b92a7","gasCost":"0x3","memory":"0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b00000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":["0x1"],"returnStack":[],"returnData":"0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b","depth":1,"refund":0,"opName":"PUSH1","error":""} -{"pc":23,"op":243,"gas":"0x2540b92a4","gasCost":"0x0","memory":"0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b00000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":["0x1","0x40"],"returnStack":[],"returnData":"0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b","depth":1,"refund":0,"opName":"RETURN","error":""} -{"stateRoot":"2eef130ec61805516c1f050720b520619787704a5dd826a39aeefb850f83acfd", "output":"40","gasUsed":"0x515c","time":350855} -``` - - -## Implementation -Implementation in [go-ethereum](https://github.com/ethereum/go-ethereum/tree/master/cmd/evm) -Implementation in [OpenEthereum](https://github.com/openethereum/openethereum/tree/main/bin/evmbin) -Implementation in [Besu](https://github.com/hyperledger/besu/tree/master/ethereum/evmtool) -Implementation in [Nethermind](https://github.com/NethermindEth/nethermind/tree/master/src/Nethermind/Nethermind.State.Test.Runner) - +${BESU_HOME}/bin/evmtool --code 0x604080536040604055604060006040600060025afa6040f3 {"pc":0,"op":96,"gas":"0x2540be400","gasCost":"0x3","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":2,"op":128,"gas":"0x2540be3fd","gasCost":"0x3","memSize":0,"stack":["0x40"],"depth":1,"refund":0,"opName":"DUP1"} +{"pc":3,"op":83,"gas":"0x2540be3fa","gasCost":"0xc","memSize":0,"stack":["0x40","0x40"],"depth":1,"refund":0,"opName":"MSTORE8"} +{"pc":4,"op":96,"gas":"0x2540be3ee","gasCost":"0x3","memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":[],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":6,"op":96,"gas":"0x2540be3eb","gasCost":"0x3","memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":["0x40"],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":8,"op":85,"gas":"0x2540be3e8","gasCost":"0x4e20","memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":["0x40","0x40"],"depth":1,"refund":0,"opName":"SSTORE"} +{"pc":9,"op":96,"gas":"0x2540b95c8","gasCost":"0x3","memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":[],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":11,"op":96,"gas":"0x2540b95c5","gasCost":"0x3","memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":["0x40"],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":13,"op":96,"gas":"0x2540b95c2","gasCost":"0x3","memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":["0x40","0x0"],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":15,"op":96,"gas":"0x2540b95bf","gasCost":"0x3","memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":["0x40","0x0","0x40"],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":17,"op":96,"gas":"0x2540b95bc","gasCost":"0x3","memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":["0x40","0x0","0x40","0x0"],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":19,"op":90,"gas":"0x2540b95b9","gasCost":"0x2","memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":["0x40","0x0","0x40","0x0","0x2"],"depth":1,"refund":0,"opName":"GAS"} +{"pc":20,"op":250,"gas":"0x2540b95b7","gasCost":"0x24abb676c","memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":["0x40","0x0","0x40","0x0","0x2","0x2540b95b7"],"depth":1,"refund":0,"opName":"STATICCALL"} +{"pc":21,"op":96,"gas":"0x2540b92a7","gasCost":"0x3","memory":"0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b00000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":["0x1"],"returnData":"0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b","depth":1,"refund":0,"opName":"PUSH1"} +{"pc":23,"op":243,"gas":"0x2540b92a4","gasCost":"0x0","memory":"0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b00000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000","memSize":96,"stack":["0x1","0x40"],"returnData":"0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b","depth":1,"refund":0,"opName":"RETURN"} +{"stateRoot":"0x8fa0dcc7f1d2383c89e5737c2843632db881c0946e80b71fe7175365e6538797","output":"0x40","gasUsed":"0x515c","pass":true,"fork":"Istanbul"} +``` ## Security Considerations -Tracing is expensive. + +Tracing is expensive. + Exposing an endpoint for creating traces publicly could open up a denial of service vector. + Clients should consider putting trace endpoints behind a separate flag from other endpoints. ## Copyright + Copyright and related rights waived via [CC0](../LICENSE.md).