Skip to content

feat(spec-specs): EIP-8037 - move CREATE state gas charge after initcode size validation#2608

Merged
spencer-tb merged 2 commits into
ethereum:eips/amsterdam/eip-8037from
spencer-tb:fix/eip8037-create-state-gas-ordering
Apr 2, 2026
Merged

feat(spec-specs): EIP-8037 - move CREATE state gas charge after initcode size validation#2608
spencer-tb merged 2 commits into
ethereum:eips/amsterdam/eip-8037from
spencer-tb:fix/eip8037-create-state-gas-ordering

Conversation

@spencer-tb

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

Copy link
Copy Markdown
Contributor

🗒️ Description

Spec Fix 1: State gas after initcode size check

Move charge_state_gas(STATE_BYTES_PER_NEW_ACCOUNT) from create()/create2() into generic_create(), after the MAX_INIT_CODE_SIZE validation.

Previously, state gas was charged before the initcode size check, so a CREATE with oversized initcode would persist state_gas_used equal to the account creation state gas cost (STATE_BYTES_PER_NEW_ACCOUNT * cost_per_state_byte) even though no account was ever created and no state was touched.

Spec Fix 2: Static context check before gas charging

Move the is_static check from generic_create() into create() and create2(), before stack pops and charge_gas(). Previously, regular and state gas were charged before checking static context. This is now consistent with SSTORE, CALL, and SELFDESTRUCT which all check static context before any gas charging.

Tests

Existing test_max_initcode_size_via_create[over_max] cases (CREATE and CREATE2) in tests/amsterdam/eip7954_increase_max_contract_size/test_max_initcode_size.py already cover the state gas ordering fix. They only need a re-fill after this spec fix, no test code changes required.

🔗 Related Issues or PRs

N/A.

✅ Checklist

  • All: Ran fast tox checks to avoid unnecessary CI fails, see also Code Standards and Enabling Pre-commit Checks:
    uvx tox -e 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-bug Category: this is a bug, deviation, or other problem C-feat Category: an improvement or new feature labels Apr 1, 2026
@spencer-tb spencer-tb requested a review from kclowes April 1, 2026 17:10
Move charge_state_gas(STATE_BYTES_PER_NEW_ACCOUNT) from create()/create2()
into generic_create(), after the MAX_INIT_CODE_SIZE check.

Previously, state gas was charged before the initcode size check, so a
CREATE with oversized initcode would persist state_gas_used equal to the
account creation state gas cost (STATE_BYTES_PER_NEW_ACCOUNT *
cost_per_state_byte) even though no account was ever created and no state
was touched.

Reported by @AskDragan (reth): ethereum#2578 (comment)
Move the is_static check from generic_create() into create() and
create2(), before stack pops and charge_gas(). This is consistent
with SSTORE, CALL, and SELFDESTRUCT which all check static context
before any gas charging.
@spencer-tb spencer-tb force-pushed the fix/eip8037-create-state-gas-ordering branch from cec523c to bb76ce3 Compare April 1, 2026 18:10
@codecov

codecov Bot commented Apr 1, 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@5e7832a). Learn more about missing BASE report.

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

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.

@kclowes kclowes left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This code lgtm! 🚀 Is the test fail expected?

@spencer-tb spencer-tb merged commit b9f0afa into ethereum:eips/amsterdam/eip-8037 Apr 2, 2026
19 of 20 checks passed
@spencer-tb

Copy link
Copy Markdown
Contributor Author

This code lgtm! 🚀 Is the test fail expected?

Thanks! Yeah its expected :D

github-merge-queue Bot pushed a commit to erigontech/erigon that referenced this pull request Apr 7, 2026
…s ordering (#20290)

- Fix two uint64 underflow bugs in EIP-8037 multidimensional gas
accounting that caused incorrect receipt `gasUsed` when child frames
reverted with a state gas reservoir that grew beyond its initial value
(via sub-child reverts)
- Move CREATE/CREATE2 state gas charge (account creation) from the
dynamic gas functions into opCreate/opCreate2, after the static-context
and initcode-size checks, so state gas is not consumed on early failures
where no state is created (aligns with
ethereum/execution-specs#2608)
- Update execution-spec-tests submodule to
[bal@v5.6.1](https://github.com/ethereum/execution-spec-tests/releases/tag/bal%40v5.6.1)
- Skip 2 BAL tests where coinbase==target exposes a separate `TxIn` bug
in exec3_parallel finalize (TODO)

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: info@weblogix.biz <admin@10gbps.weblogix.it>
github-merge-queue Bot pushed a commit to erigontech/erigon that referenced this pull request Apr 8, 2026
…s ordering (#20290)

- Fix two uint64 underflow bugs in EIP-8037 multidimensional gas
accounting that caused incorrect receipt `gasUsed` when child frames
reverted with a state gas reservoir that grew beyond its initial value
(via sub-child reverts)
- Move CREATE/CREATE2 state gas charge (account creation) from the
dynamic gas functions into opCreate/opCreate2, after the static-context
and initcode-size checks, so state gas is not consumed on early failures
where no state is created (aligns with
ethereum/execution-specs#2608)
- Update execution-spec-tests submodule to
[bal@v5.6.1](https://github.com/ethereum/execution-spec-tests/releases/tag/bal%40v5.6.1)
- Skip 2 BAL tests where coinbase==target exposes a separate `TxIn` bug
in exec3_parallel finalize (TODO)

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: info@weblogix.biz <admin@10gbps.weblogix.it>
github-merge-queue Bot pushed a commit to erigontech/erigon that referenced this pull request Apr 8, 2026
…s ordering (#20290)

- Fix two uint64 underflow bugs in EIP-8037 multidimensional gas
accounting that caused incorrect receipt `gasUsed` when child frames
reverted with a state gas reservoir that grew beyond its initial value
(via sub-child reverts)
- Move CREATE/CREATE2 state gas charge (account creation) from the
dynamic gas functions into opCreate/opCreate2, after the static-context
and initcode-size checks, so state gas is not consumed on early failures
where no state is created (aligns with
ethereum/execution-specs#2608)
- Update execution-spec-tests submodule to
[bal@v5.6.1](https://github.com/ethereum/execution-spec-tests/releases/tag/bal%40v5.6.1)
- Skip 2 BAL tests where coinbase==target exposes a separate `TxIn` bug
in exec3_parallel finalize (TODO)

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: info@weblogix.biz <admin@10gbps.weblogix.it>
marioevz pushed a commit that referenced this pull request Apr 9, 2026
…ode size validation (#2608)

* fix(spec): charge CREATE state gas after initcode size validation

Move charge_state_gas(STATE_BYTES_PER_NEW_ACCOUNT) from create()/create2()
into generic_create(), after the MAX_INIT_CODE_SIZE check.

Previously, state gas was charged before the initcode size check, so a
CREATE with oversized initcode would persist state_gas_used equal to the
account creation state gas cost (STATE_BYTES_PER_NEW_ACCOUNT *
cost_per_state_byte) even though no account was ever created and no state
was touched.

Reported by @AskDragan (reth): #2578 (comment)

* fix(spec): check static context before gas in CREATE/CREATE2

Move the is_static check from generic_create() into create() and
create2(), before stack pops and charge_gas(). This is consistent
with SSTORE, CALL, and SELFDESTRUCT which all check static context
before any gas charging.
github-merge-queue Bot pushed a commit to lambdaclass/ethrex that referenced this pull request Apr 10, 2026
…ing (#6447)

Bump BAL fixtures from v5.5.1 to v5.6.1 across Makefile, CI workflows,
docs, and fixture URL files.

Fix two EIP-8037 correctness issues in `system.rs`: move the `is_static`
check to CREATE/CREATE2 handlers (Amsterdam+ only) before stack pops and
gas charging, matching ethereum/execution-specs#2608; move
`increase_state_gas(STATE_GAS_NEW_ACCOUNT)` into `generic_create()`
after `MAX_INIT_CODE_SIZE` validation so oversized CREATE doesn't burn
state gas for an account never created.

Fix per-tx gas check in `levm/mod.rs` to use `block_regular_gas_used`
instead of `max(regular, state)` per ethereum/execution-specs#2583, and
apply `min(TX_MAX_GAS_LIMIT, tx.gas)` cap per EIP-7825. Applied across
`execute_block`, `execute_block_pipeline`, and `execute_block_parallel`.

Update `payload.rs` to track `remaining_gas` using regular gas capacity
only for Amsterdam. All 1103 BAL consume-engine tests pass.

Along with ethereum/execution-specs#2632
marioevz pushed a commit that referenced this pull request Apr 10, 2026
…ode size validation (#2608)

* fix(spec): charge CREATE state gas after initcode size validation

Move charge_state_gas(STATE_BYTES_PER_NEW_ACCOUNT) from create()/create2()
into generic_create(), after the MAX_INIT_CODE_SIZE check.

Previously, state gas was charged before the initcode size check, so a
CREATE with oversized initcode would persist state_gas_used equal to the
account creation state gas cost (STATE_BYTES_PER_NEW_ACCOUNT *
cost_per_state_byte) even though no account was ever created and no state
was touched.

Reported by @AskDragan (reth): #2578 (comment)

* fix(spec): check static context before gas in CREATE/CREATE2

Move the is_static check from generic_create() into create() and
create2(), before stack pops and charge_gas(). This is consistent
with SSTORE, CALL, and SELFDESTRUCT which all check static context
before any gas charging.
chfast pushed a commit to ipsilon/evmone that referenced this pull request Apr 13, 2026
charge_state_gas(STATE_BYTES_PER_NEW_ACCOUNT) was called before
MAX_INIT_CODE_SIZE validation. A CREATE with oversized initcode
would persist state_gas_used for an account that was never created.

Also moved is_static check before gas charging, consistent with
SSTORE, CALL, and SELFDESTRUCT.

Matches spec fix ethereum/execution-specs#2608.
Ported from erigontech/zevmone@amsterdam-giulio.
felix314159 pushed a commit to felix314159/execution-specs that referenced this pull request Apr 14, 2026
…ode size validation (ethereum#2608)

* fix(spec): charge CREATE state gas after initcode size validation

Move charge_state_gas(STATE_BYTES_PER_NEW_ACCOUNT) from create()/create2()
into generic_create(), after the MAX_INIT_CODE_SIZE check.

Previously, state gas was charged before the initcode size check, so a
CREATE with oversized initcode would persist state_gas_used equal to the
account creation state gas cost (STATE_BYTES_PER_NEW_ACCOUNT *
cost_per_state_byte) even though no account was ever created and no state
was touched.

Reported by @AskDragan (reth): ethereum#2578 (comment)

* fix(spec): check static context before gas in CREATE/CREATE2

Move the is_static check from generic_create() into create() and
create2(), before stack pops and charge_gas(). This is consistent
with SSTORE, CALL, and SELFDESTRUCT which all check static context
before any gas charging.
chfast pushed a commit to ipsilon/evmone that referenced this pull request Apr 15, 2026
charge_state_gas(STATE_BYTES_PER_NEW_ACCOUNT) was called before
MAX_INIT_CODE_SIZE validation. A CREATE with oversized initcode
would persist state_gas_used for an account that was never created.

Also moved is_static check before gas charging, consistent with
SSTORE, CALL, and SELFDESTRUCT.

Matches spec fix ethereum/execution-specs#2608.
Ported from erigontech/zevmone@amsterdam-giulio.
felix314159 pushed a commit that referenced this pull request Apr 16, 2026
…ode size validation (#2608)

* fix(spec): charge CREATE state gas after initcode size validation

Move charge_state_gas(STATE_BYTES_PER_NEW_ACCOUNT) from create()/create2()
into generic_create(), after the MAX_INIT_CODE_SIZE check.

Previously, state gas was charged before the initcode size check, so a
CREATE with oversized initcode would persist state_gas_used equal to the
account creation state gas cost (STATE_BYTES_PER_NEW_ACCOUNT *
cost_per_state_byte) even though no account was ever created and no state
was touched.

Reported by @AskDragan (reth): #2578 (comment)

* fix(spec): check static context before gas in CREATE/CREATE2

Move the is_static check from generic_create() into create() and
create2(), before stack pops and charge_gas(). This is consistent
with SSTORE, CALL, and SELFDESTRUCT which all check static context
before any gas charging.
spencer-tb added a commit that referenced this pull request Apr 17, 2026
…ode size validation (#2608)

* fix(spec): charge CREATE state gas after initcode size validation

Move charge_state_gas(STATE_BYTES_PER_NEW_ACCOUNT) from create()/create2()
into generic_create(), after the MAX_INIT_CODE_SIZE check.

Previously, state gas was charged before the initcode size check, so a
CREATE with oversized initcode would persist state_gas_used equal to the
account creation state gas cost (STATE_BYTES_PER_NEW_ACCOUNT *
cost_per_state_byte) even though no account was ever created and no state
was touched.

Reported by @AskDragan (reth): #2578 (comment)

* fix(spec): check static context before gas in CREATE/CREATE2

Move the is_static check from generic_create() into create() and
create2(), before stack pops and charge_gas(). This is consistent
with SSTORE, CALL, and SELFDESTRUCT which all check static context
before any gas charging.
spencer-tb added a commit to spencer-tb/execution-specs that referenced this pull request Apr 19, 2026
Ported from closed PR ethereum#2639. Covers the PR ethereum#2608 ordering
requirement: the MAX_INITCODE_SIZE check must run before the
account-creation state gas charge.

  test_oversized_initcode_tx_no_state_gas (parametrized
    `at_max`, `over_max`)
    Creation tx whose initcode is exactly MAX_INITCODE_SIZE
    (accepted) or one byte over (rejected with
    INITCODE_SIZE_EXCEEDED). If state gas were charged before
    the size check, block_state_gas_used would include a
    spurious GAS_NEW_ACCOUNT for an account never created.

  test_oversized_initcode_opcode_no_state_gas (parametrized
    `at_max`, `over_max`, `CREATE`, `CREATE2`)
    Factory calls CREATE/CREATE2 opcode with initcode exceeding
    the limit; the opcode returns 0 with no state gas consumed.
marioevz pushed a commit that referenced this pull request Apr 20, 2026
…ode size validation (#2608)

* fix(spec): charge CREATE state gas after initcode size validation

Move charge_state_gas(STATE_BYTES_PER_NEW_ACCOUNT) from create()/create2()
into generic_create(), after the MAX_INIT_CODE_SIZE check.

Previously, state gas was charged before the initcode size check, so a
CREATE with oversized initcode would persist state_gas_used equal to the
account creation state gas cost (STATE_BYTES_PER_NEW_ACCOUNT *
cost_per_state_byte) even though no account was ever created and no state
was touched.

Reported by @AskDragan (reth): #2578 (comment)

* fix(spec): check static context before gas in CREATE/CREATE2

Move the is_static check from generic_create() into create() and
create2(), before stack pops and charge_gas(). This is consistent
with SSTORE, CALL, and SELFDESTRUCT which all check static context
before any gas charging.
spencer-tb added a commit to spencer-tb/execution-specs that referenced this pull request Apr 20, 2026
Ported from closed PR ethereum#2639. Covers the PR ethereum#2608 ordering
requirement: the MAX_INITCODE_SIZE check must run before the
account-creation state gas charge.

  test_oversized_initcode_tx_no_state_gas (parametrized
    `at_max`, `over_max`)
    Creation tx whose initcode is exactly MAX_INITCODE_SIZE
    (accepted) or one byte over (rejected with
    INITCODE_SIZE_EXCEEDED). If state gas were charged before
    the size check, block_state_gas_used would include a
    spurious GAS_NEW_ACCOUNT for an account never created.

  test_oversized_initcode_opcode_no_state_gas (parametrized
    `at_max`, `over_max`, `CREATE`, `CREATE2`)
    Factory calls CREATE/CREATE2 opcode with initcode exceeding
    the limit; the opcode returns 0 with no state gas consumed.
spencer-tb added a commit that referenced this pull request Apr 20, 2026
…ode size validation (#2608)

* fix(spec): charge CREATE state gas after initcode size validation

Move charge_state_gas(STATE_BYTES_PER_NEW_ACCOUNT) from create()/create2()
into generic_create(), after the MAX_INIT_CODE_SIZE check.

Previously, state gas was charged before the initcode size check, so a
CREATE with oversized initcode would persist state_gas_used equal to the
account creation state gas cost (STATE_BYTES_PER_NEW_ACCOUNT *
cost_per_state_byte) even though no account was ever created and no state
was touched.

Reported by @AskDragan (reth): #2578 (comment)

* fix(spec): check static context before gas in CREATE/CREATE2

Move the is_static check from generic_create() into create() and
create2(), before stack pops and charge_gas(). This is consistent
with SSTORE, CALL, and SELFDESTRUCT which all check static context
before any gas charging.
spencer-tb added a commit that referenced this pull request Apr 21, 2026
…ode size validation (#2608)

* fix(spec): charge CREATE state gas after initcode size validation

Move charge_state_gas(STATE_BYTES_PER_NEW_ACCOUNT) from create()/create2()
into generic_create(), after the MAX_INIT_CODE_SIZE check.

Previously, state gas was charged before the initcode size check, so a
CREATE with oversized initcode would persist state_gas_used equal to the
account creation state gas cost (STATE_BYTES_PER_NEW_ACCOUNT *
cost_per_state_byte) even though no account was ever created and no state
was touched.

Reported by @AskDragan (reth): #2578 (comment)

* fix(spec): check static context before gas in CREATE/CREATE2

Move the is_static check from generic_create() into create() and
create2(), before stack pops and charge_gas(). This is consistent
with SSTORE, CALL, and SELFDESTRUCT which all check static context
before any gas charging.
chfast pushed a commit to ipsilon/evmone that referenced this pull request Apr 28, 2026
charge_state_gas(STATE_BYTES_PER_NEW_ACCOUNT) was called before
MAX_INIT_CODE_SIZE validation. A CREATE with oversized initcode
would persist state_gas_used for an account that was never created.

Also moved is_static check before gas charging, consistent with
SSTORE, CALL, and SELFDESTRUCT.

Matches spec fix ethereum/execution-specs#2608.
Ported from erigontech/zevmone@amsterdam-giulio.
fselmo pushed a commit that referenced this pull request May 5, 2026
…ode size validation (#2608)

* fix(spec): charge CREATE state gas after initcode size validation

Move charge_state_gas(STATE_BYTES_PER_NEW_ACCOUNT) from create()/create2()
into generic_create(), after the MAX_INIT_CODE_SIZE check.

Previously, state gas was charged before the initcode size check, so a
CREATE with oversized initcode would persist state_gas_used equal to the
account creation state gas cost (STATE_BYTES_PER_NEW_ACCOUNT *
cost_per_state_byte) even though no account was ever created and no state
was touched.

Reported by @AskDragan (reth): #2578 (comment)

* fix(spec): check static context before gas in CREATE/CREATE2

Move the is_static check from generic_create() into create() and
create2(), before stack pops and charge_gas(). This is consistent
with SSTORE, CALL, and SELFDESTRUCT which all check static context
before any gas charging.
spencer-tb added a commit to spencer-tb/execution-specs that referenced this pull request May 22, 2026
…ode size validation (ethereum#2608)

* fix(spec): charge CREATE state gas after initcode size validation

Move charge_state_gas(STATE_BYTES_PER_NEW_ACCOUNT) from create()/create2()
into generic_create(), after the MAX_INIT_CODE_SIZE check.

Previously, state gas was charged before the initcode size check, so a
CREATE with oversized initcode would persist state_gas_used equal to the
account creation state gas cost (STATE_BYTES_PER_NEW_ACCOUNT *
cost_per_state_byte) even though no account was ever created and no state
was touched.

Reported by @AskDragan (reth): ethereum#2578 (comment)

* fix(spec): check static context before gas in CREATE/CREATE2

Move the is_static check from generic_create() into create() and
create2(), before stack pops and charge_gas(). This is consistent
with SSTORE, CALL, and SELFDESTRUCT which all check static context
before any gas charging.
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/*`) C-bug Category: this is a bug, deviation, or other problem C-feat Category: an improvement or new feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants