Alert Source Discuss
⚠️ Draft Standards Track: Interface

EIP-7756: EOF/EVM Trace Specification

Updates EIP-3155 tracing to add EOF support

Authors Martin Holst Swende (@holiman), Marius van der Wijden (@MariusVanDerWijden), Danno Ferrin (@shemnon)
Created 2024-08-13
Discussion Link https://ethereum-magicians.org/t/eip-7756-eof-evm-trace-specification/20806
Requires EIP-3155, EIP-4750

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:

  • Add members to the trace object to support new EOF features.
  • Support tracing contracts contained in an EOF container as well as uncontained “legacy” contracts in the same trace.
  • Clarify any previous ambiguities in the EIP-3155 specification.

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.

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

  • The client outputs one JSON object per EVM operation executed.
  • The client MUST NOT output multiple lines for the same operation execution.
  • The client MUST NOT output a line for the STOP operation if an error occurred, or if the contract runs out of instructions.

Each object contains the following members.

Name Type Required Explanation
pc Number Yes Program Counter
section Number Yes if EOF EOF Code Section
op Number Yes Opcode
immediate Hex-String see below Immediate argument of the Opcode
gas Hex-Number Yes Gas left before executing this operation
gasCost Hex-Number Yes Gas cost of this operation
memory Array No Array of all allocated values
memSize Number Yes Size of memory array
stack Array Yes Array of all values on the stack
depth Number Yes Depth of the contract call stack (non-CALLF)
functionDepth Number Yes if not zero Depth of the EIP-4750 CALLF return stack
returnData Hex-String No Data returned by contract calls
refund Hex-Number Yes Amount of global gas refunded
opName String No Name of the operation
error Hex-String No Description of an error or revert data
storage Map No Array of all stored values
  • The pc value is zero indexed either from the beginning of the contract when the contract is not in an EOF container, or from the beginning of the code section when it is a contract contained in an EOF container.
  • The section member must only be present when tracing a contract that is contained in an EOF container. In cases where legacy and EOF contracts are in the same call trace the presence and absence of the section member indicates if the contract at that step is EOF or legacy.
  • The immediate member is optional for PUSH series instructions, and mandatory for all other operations that have immediate arguments.
    • For RJUMPV this would include the table length and the entire table. Clients MAY instead store just the table length.
  • The gas, stack, memory and memSize, depth, and functionDepth members are the values before execution of the op.
  • The gasCost is the sum of all gas costs, including dynamic costs such as memory expansion, call stipend, and account warming costs.
  • All array attributes (stack, memory) MUST be initialized to empty arrays (“stack”:[] NOT “stack”:null`).
  • The memory or storage members may be omitted if they are empty or the client does not produce them.
  • The memSize member MUST be present regardless of memory support. Even when memSize is zero.
  • The functionDepth member may be omitted when zero. It must be omitted if the contract is legacy EVM.
  • The error and returnData members can be omitted if they are empty.
  • If the prior operation failed with an exceptional halt, error should identify the halt. Otherwise, if the prior operation was a REVERT operation error should contain the hex-encoded revert data.
  • The storage member should only include items read or written via SSTORE or SLOAD, and not the account’s entire storage.
  • Clients SHOULD implement a way to disable recording the storage as the stateroot includes all storage updates.
  • Clients SHOULD output the members in the same order as listed in this EIP.

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 Required Explanation
stateRoot Hex-String Yes Root of the state trie after executing the transaction
output Hex-String Yes Return values of the function
gasUsed Hex-Number Yes All gas used by the transaction
pass Boolean Yes If the tx was successful, or if the test passed
time Number No Time in nanoseconds needed to execute the transaction
fork String No 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

  • The term Client Under Test or CUT has been replaced simply with “client.”

Additions to EIP-3155

  • The immediate member was added to support the large number of instructions that contain immediate operations. Without this change, users would need bytes of the contracts being executed to rationalize the traces.
  • The section and functionDepth members were added to support EIP-4750 EOF Functions.
  • Added clarification around where pc indexes when run in an EOF container.

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":96,"gas":"0x2fa9e78","gasCost":"0x3","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"PUSH1"} {"pc":2,"op":96,"gas":"0x2fa9e75","gasCost":"0x3","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"PUSH1"} {"pc":4,"op":96,"gas":"0x2fa9e72","gasCost":"0x3","memSize":0,"stack":["0x0","0x0"],"depth":1,"refund":0,"opName":"PUSH1"} {"pc":6,"op":96,"gas":"0x2fa9e6f","gasCost":"0x3","memSize":0,"stack":["0x0","0x0","0x0"],"depth":1,"refund":0,"opName":"PUSH1"} {"pc":8,"op":96,"gas":"0x2fa9e6c","gasCost":"0x3","memSize":0,"stack":["0x0","0x0","0x0","0x0"],"depth":1,"refund":0,"opName":"PUSH1"} {"pc":10,"op":97,"gas":"0x2fa9e69","gasCost":"0x3","memSize":0,"stack":["0x0","0x0","0x0","0x0","0x0"],"depth":1,"refund":0,"opName":"PUSH2"} {"pc":13,"op":90,"gas":"0x2fa9e66","gasCost":"0x2","memSize":0,"stack":["0x0","0x0","0x0","0x0","0x0","0x1000"],"depth":1,"refund":0,"opName":"GAS"} {"pc":14,"op":241,"gas":"0x2fa9e64","gasCost":"0x2eeb414","memSize":0,"stack":["0x0","0x0","0x0","0x0","0x0","0x1000","0x2fa9e64"],"depth":1,"refund":0,"opName":"CALL"} {"pc":0,"section":0,"op":227,"immediate":"0x0001","gas":"0x2eea9ec","gasCost":"0x5","memSize":0,"stack":[],"depth":2,"refund":0,"opName":"CALLF"} {"pc":0,"section":1,"op":228,"gas":"0x2eea9e7","gasCost":"0x3","memSize":0,"stack":[],"depth":2,"functionDepth":1,"refund":0,"opName":"RETF"} {"pc":3,"section":0,"op":0,"gas":"0x2eea9e4","gasCost":"0x0","memSize":0,"stack":[],"depth":2,"refund":0,"opName":"STOP"} {"pc":15,"op":96,"gas":"0x2fa9434","gasCost":"0x3","memSize":0,"stack":["0x1"],"depth":1,"refund":0,"opName":"PUSH1"} {"pc":17,"op":85,"gas":"0x2fa9431","gasCost":"0x5654","memSize":0,"stack":["0x1","0x0"],"depth":1,"refund":0,"opName":"SSTORE"} {"pc":18,"op":0,"gas":"0x2fa3ddd","gasCost":"0x0","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"STOP"}

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 and related rights waived via CC0.

Citation

Please cite this document as:

Martin Holst Swende (@holiman), Marius van der Wijden (@MariusVanDerWijden), Danno Ferrin (@shemnon), "EIP-7756: EOF/EVM Trace Specification [DRAFT]," Ethereum Improvement Proposals, no. 7756, August 2024. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-7756.