Latest Results
feat(amsterdam): glam devnet-6 gas accounting & EIP alignment (#3782)
* feat(eip8038): implement state-access gas cost update
Adds EIP-8038 parameters (gated at AMSTERDAM alongside EIP-7904/EIP-8037).
Per the user-supplied rule, every TBD value in the draft spec is set to
`previous_value + 1`:
WARM_ACCESS 100 -> 101
COLD_ACCOUNT_ACCESS 2,600 -> 2,601
ACCOUNT_WRITE 6,700 -> 6,701
COLD_STORAGE_ACCESS 2,100 -> 2,101
STORAGE_WRITE 2,800 -> 2,801
STORAGE_CLEAR_REFUND 4,800 -> 4,801
CREATE_ACCESS 7,000 -> 7,001
ACCESS_LIST_ADDRESS_COST 2,400 -> 2,401
ACCESS_LIST_STORAGE_KEY_COST 1,900 -> 1,901
Wires the new values through the GasParams table (account/storage access,
SSTORE charges and refunds, CREATE/CREATE2, EIP-7702 per-auth regular cost,
access-list per-item costs) and bumps the static gas table for warm-access
opcodes. EXTCODESIZE and EXTCODECOPY get an extra WARM_ACCESS baked into
their static cost per the EIP "EXT* family update" rule. Existing EIP-8037
snapshot tests refreshed; one Amsterdam access-list unit test updated.
* feat(eip2780): reduce intrinsic transaction gas
Adds EIP-2780 (Reduce intrinsic transaction gas) on top of EIP-8037 /
EIP-8038, tracking the
https://github.com/misilva73/EIPs/blob/update-eip-2780/EIPS/eip-2780.md
draft. Replaces the legacy 21,000 stipend with a decomposed model:
TX_BASE_COST 12,300 (sender base + ECDSA + sender access/write)
+ to-based (per recipient kind)
- cold EOA/contract COLD_ACCOUNT_ACCESS (sourced from eip8038)
- create CREATE_ACCESS (sourced from eip8038)
+ value-based
- zero 0
- create with value TRANSFER_LOG_COST
- other TRANSFER_LOG_COST + ACCOUNT_WRITE
The current draft's self-transfer and precompile zero-charge carve-outs
are intentionally not implemented — a future revision is expected to
drop them, so self-transfers and precompile transfers pay the same
to/value charges as any other recipient.
Adds an `enable_amsterdam_eip2780` config flag (auto-enabled at AMSTERDAM,
paired with `Cfg::is_amsterdam_eip2780_enabled`) and `Eip2780TxInfo`
(just the transferred value) plumbed into `GasParams::initial_tx_gas`.
Validation in the handler builds the info when EIP-2780 is enabled.
`tx_transfer_log_cost`, `tx_account_write_cost`, and
`tx_create_access_cost` GasIds are added and populated in the AMSTERDAM
block.
Implements the top-level execution charges from EIP-2780 in
`EthFrame::make_call_frame` (depth == 0):
- If recipient is EIP-7702-delegated, charge an additional
`COLD_ACCOUNT_ACCESS` of regular gas.
- If recipient is empty per EIP-161 and `tx.value > 0`, charge
`new_account_state_gas(cpsb)` of state gas. The existing
`last_frame_result` reservoir reconciliation refunds it on revert.
Existing EIP-8037 helpers in `eip8037.rs` explicitly disable EIP-2780
so the state-gas-reservoir tests stay focused. Bumps one EIP-7708 test's
gas limit to fit the new ~207k intrinsic for value transfer creating a
new account. Adds an `eip2780.rs` ee-tests module covering self-transfer,
EOA, empty-with-value, create with/without value, and the
legacy-fallback path.
* feat(eip7954): bump max code size to 64 KiB and initcode to 128 KiB (#3707)
Raises EIP-7954 limits for the glam devnet: MAX_CODE_SIZE from
0x8000 → 0x10000 (65,536 bytes) and MAX_INITCODE_SIZE from
0x10000 → 0x20000 (131,072 bytes). Updates the affected validation
test to push the new oversize threshold and refreshes related
comments.
* feat(context): implement EIP-8246 (remove SELFDESTRUCT burn) (#3717)
Replace the EIP-7708 burn-log mechanism with EIP-8246 semantics: at
transaction finalization, self-destructed accounts that still hold a
balance keep it and have their code, storage and nonce cleared instead
of the balance being burned. Self-destruct to self no longer burns the
balance either.
- Rename `eip7708_emit_burn_remaining_balance_logs` to
`eip8246_clear_selfdestructed_accounts`; clear accounts (code,
storage, nonce) and drop the self-destruct flag instead of emitting
burn logs, preserving the balance.
- Stop zeroing the balance / emitting a burn log for self-destruct to
self under Amsterdam.
- Remove the now-dead `eip7708_burn_log` helper.
- Rename the `eip7708_delayed_burn_disabled` flag to
`eip8246_delayed_clear_disabled` (CfgEnv field, Cfg accessor and
JournalCfg field).
* fix(eip-8037): exclude floor and refund from block_regular_gas_used (#3719)
* fix(eip-8037): apply EIP-7778 branching to block_regular_gas_used
Replace `max(total_gas_spent - state_gas_spent, floor_gas)` with the
conditional formula from EIP-8037 + EIP-7778 (PR ethereum/EIPs#11706):
- Floor-dominant (floor_gas >= total_gas_spent - refunded):
block_regular = tx_gas_used - state_gas_spent
- Refund-dominant: block_regular = total_gas_spent - state_gas_spent
(pre-refund, since refunds are excluded from block accounting)
Floor gas no longer participates as a `max(...)` against the regular
component; it only contributes through `tx_gas_used` when it dominates
the post-refund total.
* fix(eip-8037): exclude floor and refund from block_regular_gas_used
Per EIP-8037 + EIP-7778, block-level regular gas accounting is the
pre-refund regular component of execution. Refund and floor are scalar
adjustments on the combined `state + regular` total and only affect the
receipt's `tx_gas_used`, not the block-level split.
block_regular_gas_used = total_gas_spent - state_gas_spent
* feat(amsterdam): align gas accounting & test runners to devnet-6 (v6.1.0) (#3778)
* feat(eip8038): finalize gas parameters per ethereum/EIPs#11802 (#3771)
* feat(eip8038): finalize gas parameters to ethereum/EIPs#11802 values
Replaces the `previous_value + 1` placeholders introduced in #3697 with the
parameters proposed in ethereum/EIPs#11802:
COLD_ACCOUNT_ACCESS 2,600 -> 3,000 STORAGE_WRITE 2,800 -> 10,000
COLD_STORAGE_ACCESS 2,100 -> 3,000 STORAGE_CLEAR_REFUND 4,800 -> 12,480
ACCOUNT_WRITE 6,700 -> 8,000 CREATE_ACCESS 7,000 -> 11,000
ACCESS_LIST_ADDRESS 2,400 -> 3,000 ACCESS_LIST_KEY 1,900 -> 3,000
- WARM_ACCESS is restored to 100; the placeholder bumped it to 101 but the spec
leaves it unchanged.
- CREATE_ACCESS, the access-list costs and CALL_VALUE now use the spec's
derivations (ACCOUNT_WRITE + COLD_STORAGE_ACCESS, COLD_*_ACCESS, and
ACCOUNT_WRITE + CALL_STIPEND).
- EIP7702_PER_EMPTY_ACCOUNT_REGULAR is recomputed from the EIP-8037 base plus
the EIP-8038 deltas (ACCOUNT_WRITE, COLD_ACCOUNT_ACCESS); the ecRecover and
calldata terms are unchanged by EIP-8038.
- Adds constant and gas-table conformance tests.
ethereum/EIPs#11802 is still an open draft, so these values are preliminary.
* test(eip8038): regenerate eip8037 snapshots for finalized values
The eip8037 ee-test snapshots run at SpecId::AMSTERDAM and therefore bake in the
EIP-8038 parameters. Regenerated for the finalized values: state gas is
unchanged; regular gas reflects the new access/write costs (e.g. CREATE +3,999,
SELFDESTRUCT-to-empty +1,698, SSTORE clear now hitting the 20% refund cap).
* feat(amsterdam): align EIP-2780/8037/8038/7702 gas with devnet-6 (v6.1.0)
Fixes near-universal Amsterdam state-test failures by correcting gas
parameters to the finalized glamsterdam-devnet-6 (EELS v6.1.0) values,
matching the reference implementation:
- EIP-8038: cherry-pick finalized parameters (#3771): COLD_*_ACCESS 3000,
ACCOUNT_WRITE 8000, STORAGE_WRITE 10000, etc.
- EIP-8038: cold SSTORE folds warm base into cold cost - cold_storage_cost
uses the additional (2900) since sstore_static (warm 100) is charged
separately, fixing a 100-gas overcharge on nearly every SSTORE.
- EIP-8038: new_account_cost is 0 (value CALL already pays ACCOUNT_WRITE via
CALL_VALUE); SELFDESTRUCT keeps the separate ACCOUNT_WRITE.
- EIP-2780: TX_BASE 12300->12000, add TX_VALUE_COST (4244) for value calls,
implement the self-transfer carve-out (base only), floor base ->12000.
- EIP-7702: per-auth regular gas 15816 (incl. ACCOUNT_WRITE), refund
ACCOUNT_WRITE (8000) per existing auth, and refund rejected auths under
EIP-8037 (regular + state).
- Update eip2780 ee-tests and regenerate eip8037 snapshots.
Amsterdam state-test failures: 2289 -> 204.
* fix(eip8037): track spilled state gas so halts consume it (reservoir model)
revm's GasTracker did not distinguish state gas drawn from the reservoir
from state gas that spilled into regular gas when the reservoir was empty.
On an exceptional halt the spilled portion was wrongly credited back to the
reservoir (and refunded via the gas_used = spent - reservoir formula)
instead of consumed, so every revert/halt/OOG test that charged state gas
computed too little gas.
Mirror evm2's GasTracker: add a state_gas_spilled counter, credit it back to
remaining (LIFO) on rollback via rollback_state_gas, and propagate it to the
parent on success. handle_reservoir_remaining_gas and the top-level
last_frame_result now settle a failing frame (rollback state gas, drop the
refund counter) and, on halt, additionally spend_all the regular gas — so
the spilled state gas is consumed while the reservoir is restored to its
inherited value. refill_reservoir credits remaining-before-reservoir to match.
Update the spend_all ee-test and regenerate snapshots.
Amsterdam state-test failures: 204 -> 68.
* fix(revme): map modern fork names, skip unknown specs in statetest
State-test fixtures key the post section by fork name, and newer EEST
fixtures use the descriptive names 'TangerineWhistle' / 'SpuriousDragon'
instead of 'EIP150' / 'EIP158'. These deserialized to SpecName::Unknown,
whose to_spec_id() panics, aborting the runner thread (observed running
the glam-v601 fixtures with stest --keep-going).
- Add serde aliases so TangerineWhistle->EIP150 and SpuriousDragon->EIP158
map to the correct spec and those tests actually run.
- Skip SpecName::Unknown in the statetest runner (alongside the existing
Constantinople skip) so any genuinely unmapped fork is skipped instead
of panicking.
* fix(eip2780): apply depth-0 delegate/state-gas charges to the executing frame
The EIP-2780 top-level (depth-0) charges — the extra COLD_ACCOUNT_ACCESS for a
7702-delegated recipient and the new_account state gas for an empty value
recipient — were applied to a local Gas only used on early-return paths (empty
bytecode, precompile, halt). When the recipient executed code, EthFrame::clear
rebuilt the interpreter's gas from the raw gas_limit, discarding the charges.
- Load the recipient with code so the 7702 designator is read.
- Carry the charged Gas into the interpreter after clear() so the charges affect
remaining/reservoir/state gas during execution.
Amsterdam state-test failures: 68 -> 32.
* fix(eip8037): refund upfront new_account_state_gas when a CALL fails
A CALL transferring value to an empty recipient charges new_account_state_gas
upfront on the parent's tracker. When the call does not create the account
(revert, halt, or early failure such as insufficient balance), that charge must
be refunded to the parent's reservoir. The child-frame rollback in
handle_reservoir_remaining_gas cannot do it because the charge lives on the
parent. Mirror the CREATE path's create_state_gas refill using the propagated
charged_new_account_state_gas flag.
Amsterdam state-test failures: 32 -> 23.
* fix(eip8037): refund create_state_gas when CREATE targets an already-alive account
Per EIP-8037 (execution-specs created_target_alive), a CREATE/CREATE2 that
succeeds at a pre-existing alive (non-empty, e.g. balance-only) address does
not create a new account leaf, so the upfront create_state_gas must be
refunded — the same refill the create-failed path already performs.
Track target_was_alive (captured before the create checkpoint) through
CreateFrame and CreateOutcome, and refund create_state_gas when the create
failed OR the target was already alive.
Amsterdam state-test failures: 23 -> 8 (clears CREATE-to-existing-account
cases across eip7997 factory, stCreate2 collisions, selfdestruct, etc.).
* fix(eip7702): mirror execution-specs auth-base refund (delegated_before_tx + double-refill)
revm's apply_auth_list only refunded the per-auth AUTH_BASE state gas when the
authority was currently delegated or being cleared. Execution-specs (and evm2)
also refund it when the authority was delegated at the start of the transaction
(delegated_before_tx, using the account's original code), and refund it twice
when clearing a delegation that was freshly installed earlier in the same tx.
Recompute existed/delegated_now/delegated_before_tx/clearing per authorization
and apply the spec's refund rules.
Amsterdam state-test failures: 8 -> 4.
* fix(eip8037): refund create_state_gas for top-level CREATE at an alive target
Extend the create_state_gas refund to the top-level CREATE transaction: when
the create succeeds at a pre-existing alive (balance-only) address, no new
account leaf is created, so the intrinsic create_state_gas charged at tx entry
is refunded — matching the nested-create path. Threads target_was_alive from
the CreateOutcome into last_frame_result.
Amsterdam state-test failures: 4 -> 0. The full glam-v601 state-test suite
now passes (all forks).
* feat(revme): print an error for unknown post-state spec instead of skipping silently
An unmapped post-state fork (SpecName::Unknown) is still skipped to avoid
panicking in to_spec_id, but now reports the offending test path on stderr so
unsupported specs are visible rather than silently ignored.
* feat(revme): EIP-8282 builder system calls in btest + ForkSpec fork aliases
- Add the EIP-8282 builder execution-request system calls (builder deposit
0x..884d type 0x03, builder exit 0x..14574a type 0x04) to the blockchain-test
post-block transition, gated on Amsterdam, so they are warmed and appear in
the Block Access List (EIP-7928) as the v6.1.0 fixtures expect.
- Map the modern ForkSpec names TangerineWhistle->EIP150 and
SpuriousDragon->EIP158 (serde aliases) so those blockchain-test fixtures decode.
Blockchain-test failures: 2852 -> 7.
* fix(eip7928): record SSTORE slot access in BAL even when the cold load OOGs
SSTORE skipped the cold storage load when there was not enough gas to pay the
cold cost (an optimization to avoid a DB read before a certain out-of-gas).
That also skipped warming the slot, so EIP-7928 block access lists omitted the
accessed slot. Always cold-load the slot for SSTORE: the out-of-gas outcome is
unchanged (the cold charge still fails), but the access is now recorded. The
skip is retained for CALL, where EIP-7928 defers EIP-7702 delegation warming.
Blockchain-test failures: 7 -> 6.
* fix(eip7928): preserve self-destructed slot accesses in BAL under EIP-8246
When EIP-8246 preserves a self-destructed account's balance, it cleared the
account's storage map (storage.clear()) before the block access list was
captured, dropping the slot accesses that occurred during execution. EIP-7928
records those accesses, so the BAL was missing read-only (and write-to-zero)
slots on created-then-self-destructed accounts.
Wipe the storage values in place (present_value = 0) instead of dropping the
entries: the committed state is still an empty balance-only account, but the
slot accesses survive into the BAL — read-only slots stay read-only and written
slots become writes-to-zero.
Blockchain-test failures: 6 -> 0. The full glam-v601 blockchain-test and
state-test suites now pass.
* fix(eip2780): charge new_account_state_gas for value transfers to precompiles
The glamsterdam v6.1.0 fixtures (glam-v610) charge the EIP-8037
new_account_state_gas when a top-level transaction transfers value to an empty
precompile/special address. revm skipped the EIP-2780 depth-0 charges entirely
for precompile recipients, so the state gas was missing.
- Remove the precompile carve-out from the depth-0 EIP-2780 charge so an empty
precompile recipient with value is charged new_account_state_gas (matching
evm2's eip2780_call_charges, which has no precompile exception).
- The precompile path returns its own result gas (not the local depth-0 gas), so
re-apply the state-gas charge to result.gas. Gate it on depth == 0: a precompile
reached by a CALL opcode already had the charge applied on the parent's tracker
(avoiding a double charge).
glam-v610 blockchain-test failures: 7 -> 0. State tests and full workspace pass.
---------
* ci: fix failing checks on glam-devnet-6
- run-tests.sh: download glamsterdam-devnet@v6.1.0 fixtures instead of
tests-bal@v7.1.1, which predates the Amsterdam consensus changes in
this branch and expected stale intrinsic-gas values.
- gas_params.rs: drop private intra-doc link to fix `cargo doc` under
-D rustdoc::private_intra_doc_links.
- Cargo.lock: bump anyhow 1.0.102 -> 1.0.103 to clear RUSTSEC-2026-0190.
* docs: fix unescaped backtick from multi-line code span in eip8038 Latest Branches
-4%
rakita/eip2780-runtime-gas-phase 0%
dependabot/github_actions/taiki-e/install-action-2.82.7 0%
dependabot/github_actions/crate-ci/typos-1.48.0 © 2026 CodSpeed Technology