debug: specify callTracer output and add EIP-8037 two-dimensional gas to tracing - #852
debug: specify callTracer output and add EIP-8037 two-dimensional gas to tracing#852qu0b wants to merge 2 commits into
Conversation
… to tracing Adds the EIP-8037 regular/state gas breakdown (and the EIP-3529 gasRefund) to the debug tracing schemas, and specifies the previously-undefined callTracer output. - schemas/call-tracer.yaml (new): CallFrame/CallLog. Defines the callTracer result, including regularGasUsed and stateGasUsed (gross, pre-refund, the EIP-7778 per-transaction block contributions) and gasRefund on the top frame. Top-frame invariant (Amsterdam+): regularGasUsed + stateGasUsed == gasUsed + gasRefund, unless the EIP-7623 calldata floor binds. - schemas/opcode-tracer.yaml: per-step stateGasCost/stateGasReservoir; per-tx regularGasUsed/stateGasUsed/gasRefund; TraceConfig note updated. - debug/trace.yaml: wire CallFrame into the result unions of the three trace methods, reconcile the now-outdated "named tracers are out of scope" prose, and add a post-Amsterdam callTracer example. Notes: CallFrame.calls is typed as a generic object because the reference tooling (specgen -deref) does not dereference recursive schemas; the recursion is documented in prose. Passes make build, make test (speccheck) and make lint (no new warnings).
Restructured after a survey of all seven EL clients' tracer
implementations on their glamsterdam-devnet-6 branches (geth, erigon,
reth, besu, nethermind, ethrex, nimbus-eth1):
- New StateGasTrace schema: a named stateGasTracer returning the
per-transaction {gasUsed, regularGasUsed, stateGasUsed, gasRefund}.
Every surveyed client already computes and carries these values on
its transaction-result type for block-level accounting; exposure is
60-300 LOC per client, and for nimbus-eth1 (which has no callTracer
at all) this is the only practical compliance path.
- CallFrame shrunk to a partial schema covering only the gas-related
properties (additionalProperties: true). Full call-frame shapes
already diverge between clients (sub-frame gas semantics differ in
erigon and besu), so enshrining one client's frame layout would make
others non-compliant at birth. This also removes the recursive
calls.items workaround. The three new fields are SHOULD on the
top-level frame for clients that implement the callTracer.
- Per-step stateGasCost downgraded from MUST-when-nonzero to MAY and
made signed: three independent implementations (ethrex, reth,
erigon) track per-step state gas as a signed value that can go
negative under EIP-8037 source-based refunds, and intrinsic,
code-deposit and EIP-7702 state gas is charged outside opcode steps
in every surveyed client, so per-step sums cannot reconstruct the
transaction total. The scalar gasCost is now pinned as the
regular-dimension charge including reservoir spillover.
|
I was working on a spec for callTracer too, but I was waiting for other work in this repo before publishing a draft PR. Current blockers:
The only real part where my spec/fixtures differ from yours is the callFrame. You've kept it loose (additionalProperties: true) on the assumption that clients diverge too much to pin down. I went the other way with a full frame shape with presence rules, validated by fixtures generated against real clients and so far they mostly agree, so I don't think it needs to stay open-ended. I'd rather start with trying to get full spec output agreement and only loosen the rules if we can't come to an agreement. We had some luck when we spec'd the opcode tracer, so I'd like to try to keep it tight. cc @fjl for guidance on how we can get hive updated all the way to Glamsterdam |
|
I have two hive PRs that are needed to ensure that we can properly spec and test callTracer: ethereum/hive#1587 Tracking: |
Replaces #475. Implements the EIP-8037 tracing additions from ethereum/execution-apis#852: two-dimensional gas fields on default and call traces, signed per-opcode state-gas accounting, `stateGasTracer`, and mux tracer support. Fork gating uses the actual execution spec, including Amsterdam transactions with zero net state gas and empty-code calls, while pre-Amsterdam responses and legacy builder behavior remain unchanged. Upstream support landed in alloy-rs/alloy#4113 and is now consumed from the released `alloy-rpc-types-trace` crate. Prompted by: @onbjerg --------- Co-authored-by: Derek Cofausper <256792747+decofe@users.noreply.github.com> Co-authored-by: onbjerg <8862627+onbjerg@users.noreply.github.com>
Adds the EIP-8037 regular/state gas breakdown (and the EIP-3529
gasRefund) to the debug tracing schemas, specifies the previously-undefinedcallTraceroutput, and introduces astateGasTraceras the normative core for EIP-8037 tracing.What's included
schemas/state-gas-tracer.yaml(new) — a namedstateGasTracerreturning the per-transaction{gasUsed, regularGasUsed, stateGasUsed, gasRefund}. A survey of all seven EL clients' tracer implementations on their glamsterdam-devnet-6 branches (geth, erigon, reth, besu, nethermind, ethrex, nimbus-eth1) showed every client already computes and carries these values on its transaction-result type for block-level accounting; exposure is 60–300 LOC per client, and for nimbus-eth1 (which has nocallTracerat all) this is the only practical compliance path.schemas/call-tracer.yaml(new) —CallFrame/CallLog, defining thecallTracerresult.CallFrameis deliberately a partial schema covering only the gas-related properties (additionalProperties: true): full call-frame shapes already diverge between clients (sub-frame gas semantics differ in erigon and besu), so enshrining one client's frame layout would make others non-compliant at birth. The new fields —regularGasUsedandstateGasUsed(gross, pre-refund, the EIP-7778 per-transaction block contributions) andgasRefund— are SHOULD on the top-level frame for clients that implement thecallTracer.Top-frame invariant (Amsterdam+):
regularGasUsed + stateGasUsed == gasUsed + gasRefund, unless the EIP-7623 calldata floor binds.schemas/opcode-tracer.yaml— per-stepstateGasCost/stateGasReservoirand per-transactionregularGasUsed/stateGasUsed/gasRefund. Per-stepstateGasCostis MAY and signed: three independent implementations (ethrex, reth, erigon) track per-step state gas as a signed value that can go negative under EIP-8037 source-based refunds, and intrinsic, code-deposit and EIP-7702 state gas is charged outside opcode steps in every surveyed client, so per-step sums cannot reconstruct the transaction total. The scalargasCostis pinned as the regular-dimension charge including reservoir spillover.debug/trace.yaml— wires the new result schemas into the result unions of the three trace methods, reconciles the now-outdated "named tracers are out of scope" prose, and adds a post-AmsterdamcallTracerexample.Notes
CallFrame.callsis typed as a generic object because the reference tooling (specgen -deref) does not dereference recursive schemas; the recursion is documented in prose.make build,make test(speccheck) andmake lint(no new warnings).