Skip to content

Implement EIP-8037: "State Creation Gas Cost Increase" - #1672

Open
chfast wants to merge 1 commit into
masterfrom
amsterdam/8037
Open

Implement EIP-8037: "State Creation Gas Cost Increase"#1672
chfast wants to merge 1 commit into
masterfrom
amsterdam/8037

Conversation

@chfast

@chfast chfast commented Aug 23, 2026

Copy link
Copy Markdown
Member

Implement EIP-8037: "State Creation Gas Cost Increase"

Introduce the Amsterdam two-dimensional gas model: state-creation costs move
out of regular gas into a separate state-gas dimension, priced at
COST_PER_STATE_BYTE (1530) per byte of new state.

  • evmc: add state_gas to the message and state_gas_left/state_gas_spilled
    to the result, threading a per-frame state-gas reservoir through the VM.
  • StateGas (state_gas.hpp): a (reservoir-left, spilled) pair. Charges draw
    from the reservoir first and spill into regular gas_left; refunds refill in
    LIFO order; a frame's net use derives as initial - left + spilled. Frames
    roll their state gas back on revert/halt (make_execution_result).
  • Charges at state-creation sites: new account by CREATE/CREATE2 (at the
    deployment-address access), by value-CALL — including the depth-0
    value-transfer charge the EIP-2780 decomposition later builds on — and by
    SELFDESTRUCT to a new beneficiary (NEW_ACCOUNT = 120 bytes); SSTORE
    0->non-zero slot allocation (64 bytes, with the 0->Y->0 LIFO refill; the
    regular set cost drops to its 2900 component); code deposit per byte.
    Failed creations refund the charge. Opcode CREATE and the create
    transaction keep the legacy 32000 execution cost here: EIP-8037 defers its
    execution component to EIP-8038's CREATE_ACCESS, and EIP-8038 states that
    the flat GAS_CREATE is what CREATE_ACCESS replaces, so the reprice lands
    with it.
  • Transaction processing: execution gas splits into a regular budget (capped
    by TX_MAX_GAS_LIMIT - intrinsic) and the state-gas reservoir. Amsterdam
    lifts the Osaka per-tx gas cap; validation instead caps the regular
    intrinsic and applies the per-dimension block-inclusion rules against the
    new block state-gas budget.
  • Block accounting: per-tx receipts carry regular/state components;
    block gas_used = max(sum_regular, sum_state) (EIP-7778 2D formula).
  • System calls get a separate 16-SSTORE state-gas reservoir so the state
    dimension cannot OOG them.

The intrinsic cost otherwise keeps the pre-Amsterdam formula; the EIP-2780
resource decomposition lands separately.

The EIP-7702 per-authorization state charges (AUTH_BASE and the authority's
NEW_ACCOUNT) are not part of this commit: they are only expressible through
the top-frame charging model that the EIP-2780 intrinsic decomposition
introduces, so they land with it. The intrinsic keeps the pre-Amsterdam
formula here.

Includes the state-gas unit tests and the GAS_ALLOWANCE_EXCEEDED /
BlockException.GAS_USED_OVERFLOW acceptance, which exists because the
per-dimension inclusion checks keep an over-block-gas transaction a
transaction-level rule.

@codspeed-hq

codspeed-hq Bot commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 129 untouched benchmarks


Comparing amsterdam/8037 (6dc7d64) with master (20c5b22)

Open in CodSpeed

@codecov

codecov Bot commented Aug 23, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 88.93281% with 28 lines in your changes missing coverage. Please review.
✅ Project coverage is 97.85%. Comparing base (20c5b22) to head (6dc7d64).

Files with missing lines Patch % Lines
lib/evmone/instructions_calls.cpp 77.41% 3 Missing and 4 partials ⚠️
test/state/host.cpp 86.00% 3 Missing and 4 partials ⚠️
test/state/state.cpp 86.36% 3 Missing and 3 partials ⚠️
lib/evmone/instructions_storage.cpp 20.00% 2 Missing and 2 partials ⚠️
lib/evmone/instructions.hpp 80.00% 1 Missing and 1 partial ⚠️
lib/evmone/state_gas.hpp 90.00% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1672      +/-   ##
==========================================
- Coverage   98.00%   97.85%   -0.15%     
==========================================
  Files         180      182       +2     
  Lines       16288    16474     +186     
  Branches     3736     3771      +35     
==========================================
+ Hits        15963    16121     +158     
- Misses        247      260      +13     
- Partials       78       93      +15     
Flag Coverage Δ
eest-develop 86.66% <58.63%> (-0.98%) ⬇️
eest-develop-gmp 25.97% <39.92%> (+0.07%) ⬆️
eest-legacy 17.02% <40.31%> (+0.18%) ⬆️
eest-libsecp256k1 28.13% <39.92%> (+0.05%) ⬆️
eest-stable 86.63% <58.63%> (-0.98%) ⬇️
evmone-unittests 94.19% <87.74%> (-0.10%) ⬇️

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

Components Coverage Δ
core 95.75% <84.18%> (-0.44%) ⬇️
tooling 93.97% <100.00%> (+0.01%) ⬆️
tests 99.81% <100.00%> (+<0.01%) ⬆️
Files with missing lines Coverage Δ
lib/evmone/execution_state.hpp 90.90% <100.00%> (+2.53%) ⬆️
test/state/account.hpp 100.00% <100.00%> (ø)
test/state/state.hpp 100.00% <ø> (ø)
test/state/system_contracts.cpp 100.00% <100.00%> (ø)
test/state/transaction.hpp 100.00% <ø> (ø)
test/unittests/state_transition.cpp 98.86% <100.00%> (+0.04%) ⬆️
test/unittests/state_transition_create_test.cpp 100.00% <100.00%> (ø)
test/unittests/state_transition_eip8037_test.cpp 100.00% <100.00%> (ø)
test/unittests/state_tx_test.cpp 98.85% <100.00%> (+<0.01%) ⬆️
test/utils/block_transition.cpp 100.00% <100.00%> (ø)
... and 10 more
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Introduce the Amsterdam two-dimensional gas model: state-creation costs move
out of regular gas into a separate state-gas dimension, priced at
COST_PER_STATE_BYTE (1530) per byte of new state.

- evmc: add `state_gas` to the message and `state_gas_left`/`state_gas_spilled`
  to the result, threading a per-frame state-gas reservoir through the VM.
- StateGas (state_gas.hpp): a (reservoir-left, spilled) pair. Charges draw
  from the reservoir first and spill into regular gas_left; refunds refill in
  LIFO order; a frame's net use derives as `initial - left + spilled`. Frames
  roll their state gas back on revert/halt (make_execution_result).
- Charges at state-creation sites: new account by CREATE/CREATE2 (at the
  deployment-address access), by value-CALL — including the depth-0
  value-transfer charge the EIP-2780 decomposition later builds on — and by
  SELFDESTRUCT to a new beneficiary (NEW_ACCOUNT = 120 bytes); SSTORE
  0->non-zero slot allocation (64 bytes, with the 0->Y->0 LIFO refill; the
  regular set cost drops to its 2900 component); code deposit per byte.
  Failed creations refund the charge. Opcode CREATE and the create
  transaction keep the legacy 32000 execution cost here: EIP-8037 defers its
  execution component to EIP-8038's CREATE_ACCESS, and EIP-8038 states that
  the flat GAS_CREATE is what CREATE_ACCESS replaces, so the reprice lands
  with it.
- Transaction processing: execution gas splits into a regular budget (capped
  by TX_MAX_GAS_LIMIT - intrinsic) and the state-gas reservoir. Amsterdam
  lifts the Osaka per-tx gas cap; validation instead caps the regular
  intrinsic and applies the per-dimension block-inclusion rules against the
  new block state-gas budget.
- Block accounting: per-tx receipts carry regular/state components;
  block gas_used = max(sum_regular, sum_state) (EIP-7778 2D formula).
- System calls get a separate 16-SSTORE state-gas reservoir so the state
  dimension cannot OOG them.

The intrinsic cost otherwise keeps the pre-Amsterdam formula; the EIP-2780
resource decomposition lands separately.

The EIP-7702 per-authorization state charges (AUTH_BASE and the authority's
NEW_ACCOUNT) are not part of this commit: they are only expressible through
the top-frame charging model that the EIP-2780 intrinsic decomposition
introduces, so they land with it. The intrinsic keeps the pre-Amsterdam
formula here.

Includes the state-gas unit tests and the GAS_ALLOWANCE_EXCEEDED /
BlockException.GAS_USED_OVERFLOW acceptance, which exists because the
per-dimension inclusion checks keep an over-block-gas transaction a
transaction-level rule.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant