EIP-7756 - EOF/EVM Trace Specification

Created 2024-08-13
Status Draft
Category Interface
Type Standards Track
Authors
Requires

Abstract

Updates the EIP-3155 JSON tracing specification to support EOF features.

Motivation

EIP-3155 defined a tracing standard for Legacy EVM operations. However, the EVM Object Format (EIP-7692) adds a number of features that need to be reflected in debugging traces.

The use of these traces has also moved out from state testing, including live block tracing and differential fuzzing, increasing the need to keep tracing up to date.

This EIP has multiple goals:

Specification

To promote clarity and provide a cohesive specification, the entire tracing specification will be presented with alterations in-line rather than as a set of diffs on top of EIP-3155. Differences will be highlighted in the Backwards Compatibility section.

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", " RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174.

Datatypes

Type Explanation JSON member example
Number JSON number "pc":0
Hex-Number Hex-encoded number "gas":"0x2540be400"
String Plain string "opName":"PUSH1"
Hex-String Hex-encoded string "returnData":"0x60616203"
Array Array of Hex-Strings "stack":["0x0", "0x0"]
Key-Value Key-Value structure with key and values encoded as hex strings "storage":{"0x0":"0x1", "0x1":"0x1"}
Boolean Json bool can either be true or false "pass": true

Output

Required Fields

Each trace line MUST have these fields.

Name Type Explanation
pc Number Program Counter
op Hex-Number OpCode
opName String Name of the operation
gas Number Gas left before executing this operation
stack Array of Hex-Numbers Array of all values on the stack
depth Number Depth of the call stack
error Hex-String Description of an error (SHOULD contain revert reason if supported)

Recommended Fields

Each trace line SHOULD have these fields in the conditions they are indicated for.

Name Type Explanation
gasCost Number Gas cost of this operation
memSize Number Size of memory array
returnData Hex-String Data returned by function call
refund Hex-Number Amount of global gas refunded

Optional Fields

Each trace line MAY have these fields in the conditions they are indicated for. If a field is to be omitted within a trace, it MUST always be omitted within the same trace.

Name Type Explanation
section Number Current EOF section being executed
immediate Hex-String Immediate argument of the Opcode
functionDepth Number Depth of the EIP-4750 CALLF return stack
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"}

Summary Line

At the end of execution, the client SHOULD print summary info. This summary MUST be a single JSON object.

This info SHOULD have the following members.

Name Type Explanation
stateRoot Hex-String Root of the state trie after executing the transaction
output Hex-String Return values of the function
gasUsed Number All gas used by the transaction
pass Boolean If the tx was successful, or if the test passed
time Number Time in nanoseconds needed to execute the transaction
fork String Name of the fork rules used for execution

Example:

{"stateRoot":"0xd4c577737f5d20207d338c360c42d3af78de54812720e3339f7b27293ef195b7","output":"","gasUsed":"0x3","pass":"true","time":141485}

Rationale

This EIP is an extension of the EIP-3155 tracing features that has been in use for years. Rather than dramatically re-boot the feature, the information was added to the existing traces.

A "mini" trace was contemplated to allow for tracing to be included in tools such as t8n and to allow for more efficient RPC tracing calls, but that seemed sufficiently different that it would be a stand-alone EIP rather than an EIP that adds features to the existing tracing capabilities.

The idea of moving to a JSON Schema was rejected to ensure maximum compatibility with existing clients.

Backwards Compatibility

Clients emitting tracing JSON for uncontained "legacy" contracts will produce a compatible trace, except as outlined below

Changes from EIP-3155

Additions to EIP-3155

Clients

Besu, evmone, EthereumJS, Geth, Nethermind, and Reth already produce these standard traces in various tools. Adding the new fields will align with work needed to support the EOF EIPs enumerated in EIP-7692.

Test Cases

This is the trace output from the Ethereum Execution Specification Test from one of the parameterized executions of test_eof_functions_contract_call_succeed. Memory and return data is disabled.

json lines {"pc":0,"op":"0x60","gas":49979000,"gasCost":3,"memSize":0,"stack":[],"depth":1,"refund":0,"opName":"PUSH1"} {"pc":2,"op":"0x60","gas":49978997,"gasCost":3,"memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"PUSH1"} {"pc":4,"op":"0x60","gas":49978994,"gasCost":3,"memSize":0,"stack":["0x0","0x0"],"depth":1,"refund":0,"opName":"PUSH1"} {"pc":6,"op":"0x60","gas":49978991,"gasCost":3,"memSize":0,"stack":["0x0","0x0","0x0"],"depth":1,"refund":0,"opName":"PUSH1"} {"pc":8,"op":"0x60","gas":49978988,"gasCost":3,"memSize":0,"stack":["0x0","0x0","0x0","0x0"],"depth":1,"refund":0,"opName":"PUSH1"} {"pc":10,"op":"0x61","gas":49978985,"gasCost":3,"memSize":0,"stack":["0x0","0x0","0x0","0x0","0x0"],"depth":1,"refund":0,"opName":"PUSH2"} {"pc":13,"op":"0x5a","gas":49978982,"gasCost":2,"memSize":0,"stack":["0x0","0x0","0x0","0x0","0x0","0x1000"],"depth":1,"refund":0,"opName":"GAS"} {"pc":14,"op":"0xf1","gas":49978980,"gasCost":49198100,"memSize":0,"stack":["0x0","0x0","0x0","0x0","0x0","0x1000","0x2fa9e64"],"depth":1,"refund":0,"opName":"CALL"} {"pc":25,"section":0,"op":"0xe3","immediate":"0x0001","gas":49195500,"gasCost":5,"memSize":0,"stack":[],"depth":2,"refund":0,"opName":"CALLF"} {"pc":29,"section":1,"op":"0xe4","gas":49195495,"gasCost":3,"memSize":0,"stack":[],"depth":2,"functionDepth":2,"refund":0,"opName":"RETF"} {"pc":28,"section":0,"op":"0x00","gas":49195492,"gasCost":0,"memSize":0,"stack":[],"depth":2,"refund":0,"opName":"STOP"} {"pc":15,"op":"0x60","gas":49976372,"gasCost":3,"memSize":0,"stack":["0x1"],"depth":1,"refund":0,"opName":"PUSH1"} {"pc":17,"op":"0x55","gas":49976369,"gasCost":22100,"memSize":0,"stack":["0x1","0x0"],"depth":1,"refund":0,"opName":"SSTORE"} {"pc":18,"op":"0x00","gas":49954269,"gasCost":0,"memSize":0,"stack":[],"depth":1,"refund":0,"opName":"STOP"} {"output":"","gasUsed":45731,"fork":"Osaka","postHash":"0x2c47b4070c1eef501d9548959c3abde2d8dc78ed1d819697c61d2b0861cc78cf","pass":true}

Security Considerations

Clients should be aware that tracing can be expensive both in terms of CPU overhead and network bandwidth. Tracing endpoints should not be enabled by default, and when they are enabled should have access restrictions on the network level. Failure to do so could result in a client being overwhelmed with requests and, if operating as a validator, cause the client to fail to provide execution attestations in a timely manner.

Differential fuzzing is also a double-edged sword. While it allows client teams the ability to identify consensus splits, the client teams need to be prompt in fixing any issues that are discovered.

Copyright

Copyright and related rights waived via CC0.