Skip to content

feat(spec-specs, tests): EIP-8037 - 0 to x to 0 SSTORE refunds to state gas#2698

Merged
spencer-tb merged 3 commits into
ethereum:eips/amsterdam/eip-8037from
spencer-tb:eips/amsterdam/eip-8037-sstore-reservoir-refund
Apr 19, 2026
Merged

feat(spec-specs, tests): EIP-8037 - 0 to x to 0 SSTORE refunds to state gas#2698
spencer-tb merged 3 commits into
ethereum:eips/amsterdam/eip-8037from
spencer-tb:eips/amsterdam/eip-8037-sstore-reservoir-refund

Conversation

@spencer-tb

@spencer-tb spencer-tb commented Apr 16, 2026

Copy link
Copy Markdown
Contributor

🗒️ Description

Implements SSTORE 0 to x to 0 refunds state gas directly to state_gas_reservoir instead of refund_counter, with frame scoped rollback on revert or exceptional halt (mirrors refund_counter semantics). Extends the journaling to the CREATE silent failure refunds introduced in #2704.

EIP text change: ethereum/EIPs#11532 (merged) + ethereum/EIPs#11548 (clarification).

Spec change: 1628020

When a storage slot is restored to its original zero value (0 to x to 0), the net state growth is zero. Refund 32 * cost_per_state_byte directly to the reservoir instead of through refund_counter. The regular gas write cost refund still goes through refund_counter. The refund happens immediately after the x to 0 change.

A new state_gas_refund counter on the Evm tracks inline reservoir refunds so they can be unwound with the frame:

  • sstore increments state_gas_refund alongside the state_gas_left += ... / state_gas_used -= ... mutations.
  • generic_create also increments state_gas_refund at all three silent-failure sites (insufficient balance / nonce / depth, address collision, child error) so feat(spec-specs, tests): EIP-8037 - CREATE failure refunds state gas to reservoir #2704's CREATE refunds follow the same rollback rule.
  • incorporate_child_on_success propagates state_gas_refund to the parent (refund is recursively inheritable up the call stack on clean returns).
  • incorporate_child_on_error subtracts state_gas_refund from the amount returned to the parent's reservoir and does not propagate it (refund is dropped with any reverting ancestor).

Net state growth is zero so block_state_gas_used excludes the refunded state gas.

Existing test update: fd49b8a

test_block_gas_refund_eip7778_no_block_reduction, expected block header gas_used now reflects the state gas refund reducing block_state_gas_used. Regular gas refund still excluded from block accounting per EIP-7778.

New tests: e001d16

Twelve tests in test_state_gas_sstore.py covering happy-path accounting, cross-frame propagation, and the rollback semantics on revert / exceptional halt:

  • test_sstore_restoration_block_state_gas_zero, parametrized num_cycles=[1, 50]. Verifies block state gas is zero for 0 to x to 0 cycles.
  • test_sstore_restoration_mixed_with_genuine_sstore, parametrized num_cycles=[1, 10]. Mixes restoration cycles with a genuine 0 to x, block state gas reflects only the genuine SSTORE.
  • test_sstore_restoration_intermediate_values, 0 to x to y to 0 still triggers refund, independent of intermediate values.
  • test_sstore_restoration_then_reset, 0 to 1 to 0 to 1 correctly charges once net (refund then re-charge).
  • test_sstore_restoration_reservoir_replenished_inline, inline refund at x to 0 allows a subsequent 0 to x to succeed.
  • test_sstore_restoration_reservoir_spillover, tx gas at the cap (reservoir zero), 0 to x state gas spills into gas_left, x to 0 refund goes to reservoir.
  • test_sstore_restoration_cross_frame, parametrized over CALL / CALLCODE / DELEGATECALL via with_all_call_opcodes. Callee performs the full 0 to x to 0 cycle; slot lives in callee's storage for CALL and in caller's for CALLCODE / DELEGATECALL; the tx-level reservoir is refunded in every case.
  • test_sstore_restoration_sub_frame_revert, same call-opcode parametrization. Sub-call does 0 to x to 0 then REVERT; a single-SSTORE probe sized to OOG by 1 detects any leaked refund.
  • test_sstore_restoration_ancestor_revert, inner frame applies the refund and returns successfully, middle frame REVERTs; exercises the recursive propagation rule (success incorporate_child_on_success then ancestor incorporate_child_on_error).
  • test_sstore_restoration_create_init_revert, parametrized over CREATE / CREATE2 via with_all_create_opcodes. CREATE init does 0 to x to 0 then REVERT, wrapped in an outer reverting frame so both the SSTORE refund and the feat(spec-specs, tests): EIP-8037 - CREATE failure refunds state gas to reservoir #2704 CREATE silent-failure refund must unwind together.
  • test_sstore_restoration_create_init_success, parametrized over CREATE / CREATE2. Positive mirror: init writes and clears slot 0, returns empty runtime, CREATE succeeds.

🔗 Related Issues or PRs

✅ Checklist

  • All: Ran fast static checks to avoid unnecessary CI fails, see also Code Standards and Enabling Pre-commit Checks:
    just static
  • All: PR title adheres to the repo standard - it will be used as the squash commit message and should start type(scope):.
  • All: Considered updating the online docs in the ./docs/ directory.
  • All: Set appropriate labels for the changes (only maintainers can apply labels).

@spencer-tb spencer-tb added A-spec-specs Area: Specification—The Ethereum specification itself (eg. `src/ethereum/*`) C-feat Category: an improvement or new feature A-tests Area: Consensus tests. labels Apr 16, 2026
@spencer-tb spencer-tb force-pushed the eips/amsterdam/eip-8037-sstore-reservoir-refund branch 2 times, most recently from e2d1f15 to 5eae4df Compare April 16, 2026 17:26
@spencer-tb spencer-tb requested a review from kclowes April 16, 2026 17:27
@codecov

codecov Bot commented Apr 16, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
⚠️ Please upload report for BASE (eips/amsterdam/eip-8037@e723e7d). Learn more about missing BASE report.

Additional details and impacted files
@@                    Coverage Diff                     @@
##             eips/amsterdam/eip-8037    #2698   +/-   ##
==========================================================
  Coverage                           ?   88.18%           
==========================================================
  Files                              ?      524           
  Lines                              ?    31120           
  Branches                           ?     3036           
==========================================================
  Hits                               ?    27444           
  Misses                             ?     3161           
  Partials                           ?      515           
Flag Coverage Δ
unittests 88.18% <ø> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@spencer-tb spencer-tb force-pushed the eips/amsterdam/eip-8037-sstore-reservoir-refund branch 3 times, most recently from 3f40123 to 3b0e0c4 Compare April 19, 2026 12:24
@spencer-tb spencer-tb force-pushed the eips/amsterdam/eip-8037-sstore-reservoir-refund branch from 3b0e0c4 to e001d16 Compare April 19, 2026 12:27
@spencer-tb spencer-tb merged commit 5450513 into ethereum:eips/amsterdam/eip-8037 Apr 19, 2026
11 of 16 checks passed
new_value=0,
)(i, 0)
tx_regular = (
intrinsic_gas + code.gas_cost(fork) - num_cycles * sstore_state_gas

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this won´t work as the refund max will be hit (1/5 refund max) 🤔

spencer-tb added a commit to spencer-tb/execution-specs that referenced this pull request Apr 21, 2026
spencer-tb added a commit to spencer-tb/execution-specs that referenced this pull request Apr 21, 2026
@jangko jangko mentioned this pull request Apr 21, 2026
9 tasks
spencer-tb added a commit to spencer-tb/execution-specs that referenced this pull request May 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-spec-specs Area: Specification—The Ethereum specification itself (eg. `src/ethereum/*`) A-tests Area: Consensus tests. C-feat Category: an improvement or new feature P-high

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants