Update EIP-8037: Refund state gas on all frame failures including top level#11476
Merged
eth-bot merged 2 commits intoApr 17, 2026
Merged
Conversation
Clarify that state gas is refunded on failure at every level, not just child frames. When the top-level frame reverts or halts, execution_state_gas_used is reset to zero and the reservoir is returned to the sender, consistent with child frame behavior and the principle that state gas pays exclusively for state that is actually grown. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Collaborator
|
✅ All reviewers have approved. |
The previous version had three gaps: 1. Only covered exceptional halt at top level, not revert 2. Reset execution_state_gas_used without restoring the actual gas that spilled from the reservoir into gas_left 3. Didn't explicitly describe the gas movement mechanism at top level Now the top-level restoration mirrors child frame restoration exactly: all consumed state gas (reservoir + spillover) is moved back into the state_gas_reservoir, and execution_state_gas_used is reset to zero. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
qu0b
added a commit
to qu0b/execution-specs
that referenced
this pull request
Apr 1, 2026
On top-level revert or exceptional halt, restore all execution state gas to the reservoir and reset execution_state_gas_used to zero. State changes are fully reverted so no state was actually grown — the sender should not pay for state gas. This mirrors incorporate_child_on_error for child frames, where state_gas_used is restored to the parent's state_gas_left and not accumulated into the parent's state_gas_used. Implements the spec change proposed in ethereum/EIPs#11476 (the alternative to #11468 where state gas IS counted at top level). Includes test: test_code_deposit_fail_excludes_initcode_state_gas which validates that initcode state gas does NOT count in block_state_gas_used when code deposit triggers exceptional halt. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
qu0b
added a commit
to qu0b/execution-specs
that referenced
this pull request
Apr 1, 2026
On top-level revert or exceptional halt, restore all execution state gas to the reservoir and reset execution_state_gas_used to zero. State changes are fully reverted so no state was actually grown — the sender should not pay for state gas. This mirrors incorporate_child_on_error for child frames, where state_gas_used is restored to the parent's state_gas_left and not accumulated into the parent's state_gas_used. Spec change: ethereum/EIPs#11476 Aligns with nethermind's current behavior. Includes test: test_code_deposit_fail_excludes_initcode_state_gas which validates that initcode state gas does NOT count in block_state_gas_used when code deposit triggers exceptional halt. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2 tasks
qu0b
added a commit
to qu0b/execution-specs
that referenced
this pull request
Apr 1, 2026
EELS patch: on top-level revert or exceptional halt, restore all execution state gas to the reservoir and reset execution_state_gas_used to zero. Mirrors incorporate_child_on_error for child frames. Test: 2-tx blockchain test at 100M gas limit. TX1 deploys 14 KiB contract pushing block_state above block_regular. TX2 is a failing CREATE whose initcode state gas (GAS_NEW_ACCOUNT = 131,488) becomes the observable delta in header.gas_used = max(regular, state). Unpatched EELS: gasUsed = 0x100D000 (state gas counted) Patched EELS: gasUsed = 0xFECE60 (state gas refunded) Delta: 131,488 = 112 * cpsb = GAS_NEW_ACCOUNT Spec change: ethereum/EIPs#11476 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
qu0b
added a commit
to qu0b/execution-specs
that referenced
this pull request
Apr 1, 2026
EELS patch: on top-level revert or exceptional halt, restore all execution state gas to the reservoir and reset state_gas_used to zero. Mirrors incorporate_child_on_error for child frames. Test from PR ethereum#2595: single-tx at 60M, 3 parametrized cases (oversized code x2, OOG deposit). Spec change: ethereum/EIPs#11476 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
qu0b
added a commit
to qu0b/execution-specs
that referenced
this pull request
Apr 1, 2026
EELS patch: on top-level revert or exceptional halt, restore all execution state gas to the reservoir and reset state_gas_used to zero. Mirrors incorporate_child_on_error for child frames. Test: 2-tx blockchain test at 100M where state gas is the binding dimension. TX1 deploys 14 KiB contract (high state gas). TX2 is a failing CREATE whose initcode state gas (GAS_NEW_ACCOUNT) is the observable delta in header.gas_used. This is the opposite of ethereum#2595 which tests that state gas IS counted at the top level (#11468). This test verifies state gas is NOT counted at the top level (#11476). Spec change: ethereum/EIPs#11476 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
qu0b
added a commit
to qu0b/execution-specs
that referenced
this pull request
Apr 1, 2026
EELS patch: on top-level revert or exceptional halt, restore all execution state gas to the reservoir and reset state_gas_used to zero. Mirrors incorporate_child_on_error for child frames. Test: 2-tx blockchain test at 100M where state gas is the binding dimension. TX1 deploys 14 KiB contract (high state gas). TX2 is a failing CREATE whose initcode state gas (GAS_NEW_ACCOUNT) is the observable delta in header.gas_used. This is the opposite of ethereum#2595 which tests that state gas IS counted at the top level (#11468). This test verifies state gas is NOT counted at the top level (#11476). Spec change: ethereum/EIPs#11476 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
qu0b
added a commit
to qu0b/execution-specs
that referenced
this pull request
Apr 1, 2026
EELS patch: on top-level revert or exceptional halt, restore all execution state gas to the reservoir and reset state_gas_used to zero. Mirrors incorporate_child_on_error for child frames. Test: 2-tx blockchain test at 100M where state gas is the binding dimension. TX1 deploys 14 KiB contract (high state gas). TX2 is a failing CREATE whose initcode state gas (GAS_NEW_ACCOUNT) is the observable delta in header.gas_used. This is the opposite of ethereum#2595 which tests that state gas IS counted at the top level (#11468). This test verifies state gas is NOT counted at the top level (#11476). Spec change: ethereum/EIPs#11476 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
spencer-tb
added a commit
to qu0b/execution-specs
that referenced
this pull request
Apr 1, 2026
If EIP-8037 adopts the top-level state gas refund (ethereum/EIPs#11476), block gas accounting in these tests will need updating.
spencer-tb
added a commit
to qu0b/execution-specs
that referenced
this pull request
Apr 1, 2026
If EIP-8037 adopts the top-level state gas refund (ethereum/EIPs#11476), block gas accounting in these tests will need updating.
spencer-tb
added a commit
to qu0b/execution-specs
that referenced
this pull request
Apr 1, 2026
If EIP-8037 adopts the top-level state gas refund (ethereum/EIPs#11476), block gas accounting in these tests will need updating.
spencer-tb
added a commit
to qu0b/execution-specs
that referenced
this pull request
Apr 1, 2026
If EIP-8037 adopts the top-level state gas refund (ethereum/EIPs#11476), block gas accounting in these tests will need updating.
This was referenced Apr 13, 2026
Merged
4 tasks
eth-bot
approved these changes
Apr 17, 2026
eth-bot
left a comment
Collaborator
There was a problem hiding this comment.
All Reviewers Have Approved; Performing Automatic Merge...
4 tasks
qu0b
added a commit
to qu0b/execution-specs
that referenced
this pull request
Apr 17, 2026
EELS patch: on top-level revert or exceptional halt, restore all execution state gas to the reservoir and reset state_gas_used to zero. Mirrors incorporate_child_on_error for child frames. Test: 2-tx blockchain test at 100M where state gas is the binding dimension. TX1 deploys 14 KiB contract (high state gas). TX2 is a failing CREATE whose initcode state gas (GAS_NEW_ACCOUNT) is the observable delta in header.gas_used. This is the opposite of ethereum#2595 which tests that state gas IS counted at the top level (#11468). This test verifies state gas is NOT counted at the top level (#11476). Spec change: ethereum/EIPs#11476 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
qu0b
added a commit
to qu0b/execution-specs
that referenced
this pull request
Apr 17, 2026
EELS patch: on top-level revert or exceptional halt, restore all execution state gas to the reservoir and reset state_gas_used to zero. Mirrors incorporate_child_on_error for child frames. Test: 2-tx blockchain test at 100M where state gas is the binding dimension. TX1 deploys 14 KiB contract (high state gas). TX2 is a failing CREATE whose initcode state gas (GAS_NEW_ACCOUNT) is the observable delta in header.gas_used. This is the opposite of ethereum#2595 which tests that state gas IS counted at the top level (#11468). This test verifies state gas is NOT counted at the top level (#11476). Spec change: ethereum/EIPs#11476 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Alternative to #11468. Both PRs clarify child frame behavior identically — the difference is top-level failure:
execution_state_gas_usedis preserved → counts towardblock_state_gas_usedexecution_state_gas_usedis reset to zero → sender is fully refunded state gasThis PR is a spec change, not just a clarification. It aligns top-level behavior with child frame behavior: state gas is refunded on failure at all levels because no state was actually grown.
Context from #11468 discussion
@rakita called the current top-level behavior a "spec code bug." @misilva73 (EIP author) said restoring state gas "would make more sense," noting:
block_state_gas_usedshould reflect reality — a block that reverted all state-touching txs would hit the state gas limit despite growing zero stateThe main counter-argument is pre-EIP-8037 precedent (
GAS_NEW_ACCOUNTconsumed on revert). This PR explicitly departs from that in favor of internal consistency with the stated design principle: "state gas pays for long-term state growth which does not occur on failure."Line-by-line explanation
Bullet 5 (child frame behavior) — identical to #11468
Old:
On child success, the remaining state_gas_reservoir is returned to the parent.New: Adds that the child's
execution_state_gas_usedis accumulated into the parent's counter on success, and explicitly not accumulated on failure.Old:
State gas is fully preserved on failure because state changes are reverted, so no state was actually grown.Removed. "Fully preserved" was ambiguous (preserved = still counted, or preserved = returned?). Replaced by explicit "not added" language.
Bullet 6 (top-level behavior) — WHERE THE TWO PRs DIVERGE
Old:
On exceptional halt, remaining gas_left is attributed to execution_regular_gas_used...New: Covers both revert and exceptional halt at the top level (the old spec only mentioned exceptional halt — top-level revert was unaddressed). Explicitly describes the gas movement: all state gas consumed during execution (from the reservoir AND any that spilled into
gas_left) is restored to thestate_gas_reservoir, mirroring the child frame restoration mechanism.execution_state_gas_usedis reset to zero. On exceptional halt,gas_leftis additionally zeroed.Why the spillover matters: When the reservoir is exhausted, state gas charges spill into
gas_left. Simply resettingexecution_state_gas_usedwithout moving that gas back would leave the sender paying for state gas as if it were regular gas — invisible to both counters.Compare #11468:
execution_state_gas_usedis not reset — still counts towardblock_state_gas_used. Top-level revert is also not explicitly addressed (inherits from the "State gas on frame failure" section which says state gas counts at top level).Section "State gas on frame failure" (was "Revert behavior for state gas")
Old:
State gas charged for account creation... is consumed even if the frame reverts — state changes are rolled back but gas is not refunded.New: Describes the full restoration at top level: all consumed execution state gas (reservoir + spillover from
gas_left) is moved back into the reservoir,execution_state_gas_usedreset to zero. Acknowledges departure from pre-EIP-8037 precedent.Compare #11468: Top level "has no parent to reclaim it" → state gas counts. Consistent with pre-EIP-8037 behavior.
🤖 Generated with Claude Code