Skip to content

Commit

Permalink
Automatically merged updates to draft EIP(s) 3155 (ethereum#3159)
Browse files Browse the repository at this point in the history
Hi, I'm a bot! This change was automatically merged because:

 - It only modifies existing Draft or Last Call EIP(s)
 - The PR was approved or written by at least one author of each modified EIP
 - The build is passing
  • Loading branch information
MariusVanDerWijden authored Dec 9, 2020
1 parent caac1a8 commit fa6bfb2
Showing 1 changed file with 37 additions and 129 deletions.
166 changes: 37 additions & 129 deletions EIPS/eip-3155.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ created: 2020-12-07
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 and nethermind and Besu. Since the common format was not well defined, the implementations differed slightly making it hard to develop adequate tooling.
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:
- 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
Expand All @@ -24,26 +28,12 @@ This EIP has multiple objectives:
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.

Due to the slight differences in output the following fields currently need to be dropped when comparing tracing outputs: $GasCost$, $MemorySize$, $RefundCounter$, $ReturnStack$, and $ReturnData$. This reduces the usefulness of tracing significantly. Creating a common standard would allow to add these fields thus increasing the surface that can be tested by a fuzzer.

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 new unforeseen 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.

### Inputs

The CUT MUST be able to execute a statetest as described [here](https://www.ethdocs.org/en/latest/contracts-and-transactions/ethereum-tests/state_tests/index.html).
Example :
```
evm --json --nomemory statetest foobar.json
```
The CUT MUST spit out jsonl as defined below, and it MUST also report the final `stateRoot` hash after executing the test. The CUT SHOULD report whether the tests succeeded or failed.

If the statetest contains a Fork identifier (e.g. `Berlin` or `Istanbul`) the CUT MUST run the statetest under the chain rules of this fork.

The CUT SHOULD executed statetests if the filenames are written to STDIN. This allows to execute multiple tests on the same instance without having to set up and tear down the client.

### Datatypes

| Type | Explanation | Example |
Expand All @@ -58,7 +48,7 @@ The CUT SHOULD executed statetests if the filenames are written to STDIN. This a

### Output

The CUT MUST output a `json` object for EACH operation. The output SHOULD to be printed to STDERR.
The CUT MUST output a `json` object for EACH operation.

Required Fields:

Expand All @@ -70,18 +60,19 @@ Required Fields:
| `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 |
| `returnStack` | Array of Hex-Numbers | Array of values, Stack of the called function |
| `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:*
```
Expand All @@ -104,10 +95,11 @@ The CUT MUST NOT output a line for the `STOP` operation if an error occurred:

### Summary and error handling

At the end of execution, the CUT MUST print some summerical info, this info SHOULD have the following fields. The summary SHOULD be printed to STDOUT.
The summary should be a single jsonl object.
At the end of execution, the CUT MUST print some summerical info, this info SHOULD have the following fields.
The summary should be a single `jsonl` object.

Required Fields:

| Name | Type | Explanation |
|---|---|---|
| `stateRoot` | Hex-String | Root of the state trie after executing the transaction |
Expand All @@ -116,6 +108,7 @@ Required Fields:
| `pass` | Boolean | Bool whether transaction was executed successfully |

OptionalFields:

| Name | Type | Explanation |
|---|---|---|
| `time` | Number | Time in nanoseconds needed to execute the transaction |
Expand All @@ -124,14 +117,10 @@ OptionalFields:
{"stateRoot":"0xd4c577737f5d20207d338c360c42d3af78de54812720e3339f7b27293ef195b7","output":"","gasUsed":"0x3","successful":"true","time":141485}
```

The state test format allows for multiple `postStates` for different forks.
If different `postStates` are present the CUT MUST execute the test according to the rules of the fork sequentially.
It MUST print a trace for each execution as well as an individual summary for each test.


## Rationale
This EIP is created to enable easier testing of EVM implementations to create a safer ecosystem. It 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.
This proposal is heavily influenced by the requirements for [goevmlab](https://github.com/holiman/goevmlab) and our effort to create differential fuzzers for the EVM.
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.
Expand All @@ -140,110 +129,27 @@ This EIP is fully backward compatible with ethereum as it only introduces a bett
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
<details><summary>Test cases</summary>

```bash
$evm --code 6040 --json run
{"pc":0,"op":96,"gas":"0x2540be400","gasCost":"0x3","memory":"0x","memSize":0,"stack":[],"depth":1,"error":null,"opName":"PUSH1"}
{"pc":2,"op":0,"gas":"0x2540be3fd","gasCost":"0x0","memory":"0x","memSize":0,"stack":["0x40"],"depth":1,"error":null,"opName":"STOP"}
{"output":"","gasUsed":"0x3","time":141485}
~/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}
```

```json
{
"TraceTest": {
"env": {
"currentCoinbase": "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"currentDifficulty": "0x20000",
"currentGasLimit": "0x26e1f476fe1e22",
"currentNumber": "0x1",
"currentTimestamp": "0x3e8",
"previousHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
},
"pre": {
"0x00000000000000000000000000000ca1100b1a7e": {
"code": "0x6040",
"storage": {},
"balance": "0x0",
"nonce": "0x0"
},
"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": {
"code": "0x",
"storage": {},
"balance": "0xffffffff",
"nonce": "0x0"
}
},
"transaction": {
"gasPrice": "0x1",
"nonce": "0x0",
"to": "0x00000000000000000000000000000Ca1100b1A7E",
"data": [
"0x80e3193e421154d1de1cd3a0b425cc21eaa184eb2ec89a756a8e4624"
],
"gasLimit": [
"0x7a1200"
],
"value": [
"0x4862"
],
"secretKey": "0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8"
},
"out": "0x",
"post": {
"Istanbul": [
{
"hash": "3f7878bb9cd21378f7eb0a2d26e24f11abca4709482cc92e31c1a8a9e4aeeed5",
"logs": "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"indexes": {
"data": 0,
"gas": 0,
"value": 0
}
}
],
"Berlin": [
{
"hash": "3f7878bb9cd21378f7eb0a2d26e24f11abca4709482cc92e31c1a8a9e4aeeed5",
"logs": "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"indexes": {
"data": 0,
"gas": 0,
"value": 0
}
}
]
}
}
}
```

```bash
$evm --nomemory --json statetest test.json
{"pc":0,"op":96,"gas":"0x79be38","gasCost":"0x3","memory":"0x","memSize":0,"stack":[],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"PUSH1","error":""}
{"pc":2,"op":0,"gas":"0x79be35","gasCost":"0x0","memory":"0x","memSize":0,"stack":["0x40"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"STOP","error":""}
{"output":"","gasUsed":"0x3","time":166351}
{"stateRoot": "3f7878bb9cd21378f7eb0a2d26e24f11abca4709482cc92e31c1a8a9e4aeeed5"}
{"pc":0,"op":96,"gas":"0x79be38","gasCost":"0x3","memory":"0x","memSize":0,"stack":[],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"PUSH1","error":""}
{"pc":2,"op":0,"gas":"0x79be35","gasCost":"0x0","memory":"0x","memSize":0,"stack":["0x40"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"STOP","error":""}
{"output":"","gasUsed":"0x3","time":50655}
{"stateRoot": "3f7878bb9cd21378f7eb0a2d26e24f11abca4709482cc92e31c1a8a9e4aeeed5"}
[
{
"name": "TraceTest",
"pass": true,
"fork": "Istanbul"
},
{
"name": "TraceTest",
"pass": true,
"fork": "Berlin"
}
]
```

</details>


## Implementation
Implementation in [go-ethereum](https://github.com/ethereum/go-ethereum/tree/master/cmd/evm)
Expand All @@ -253,7 +159,9 @@ Implementation in [Nethermind](https://github.com/NethermindEth/nethermind/tree/


## Security Considerations
Creating better infrastructure might enable attackers to find consensus issues easier.
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](https://creativecommons.org/publicdomain/zero/1.0/).

0 comments on commit fa6bfb2

Please sign in to comment.