go-ethereum/core
Stefan 6489aab697
core/vm: fix EIP-8037 CALL state gas ordering + code-store OOG underflow (#33972)
## Summary

Two EIP-8037 state gas accounting fixes:

1. **CALL state gas ordering** — Charge new-account state gas (112 ×
cpsb = 131,488) **before** the 63/64 child gas allocation, not after
2. **Code-store OOG underflow** — Do not inflate `TotalStateGasCharged`
when `UseGas` fails for code deposit, preventing uint64 underflow in
`blockGasUsed()`

## Bug 1: CALL state gas ordering (`operations_acl.go`)

In `makeCallVariantGasCall`, the EIP-8037 state gas for new account
creation was returned in the `GasCosts` struct and charged by the
interpreter's `UseGas`/`Sub` **after** `callGas()` had already computed
the 63/64 child gas allocation using the full (pre-state-gas)
`contract.Gas.RegularGas`.

When the state gas reservoir is empty (common case — reservoir only has
gas when `tx.gasLimit` exceeds `TX_MAX_GAS_LIMIT - intrinsic`), state
gas spills to regular gas. The spill amount (131,488) far exceeds the
1/64 retained gas (~15,600 at 1M gas), causing an underflow/OOG on CALLs
that should succeed.

**Fix:** Charge state gas directly before `callGas()` so the 63/64
calculation uses the reduced regular gas, then return `StateGas: 0` to
avoid double-charging. This matches nethermind's implementation
(`EvmInstructions.Call.cs:187-213`) and besu's approach.

**Spec basis:** EIP-8037 says "State gas charges deduct from
`state_gas_reservoir` first; when the reservoir is exhausted, from
`gas_left`." The 63/64 rule applies to `gas_left`, so state gas
spillover into `gas_left` must happen before the 63/64 computation.

## Bug 2: Code-store OOG underflow (`evm.go`)

In `initNewContract`, when `UseGas` fails for code deposit (code-store
OOG on valid code), the upstream code at `evm.go:666-672` added
`createDataGas.StateGas` to `TotalStateGasCharged` without actually
consuming any gas. For a 14KB init code output, this adds ~17.3M phantom
state gas to TSC.

This inflated TSC propagates through `blockGasUsed()`:
```
execRegularUsed := totalExecUsed - execStateUsed  // uint64 underflow when TSC > totalExecUsed
```
The underflow produces a massive `txRegular` value, causing
`ReturnGasAmsterdam` to reject the block with `gas limit reached`.

**Fix:** Remove the TSC inflation on `UseGas` failure (lines 666-672).
Also remove `ErrCodeStoreOutOfGas` from the `isCodeValidation` condition
(line 621-623), so code-store OOG follows the normal exceptional halt
path: all regular gas consumed, state gas reverted via
`RevertStateGas()`.

**Spec basis:** EIP-8037 §"Contract deployment cost calculation"
explicitly lists code-store OOG as a failure path:
> **Failure paths** (REVERT, OOG/invalid during initcode, **OOG during
code deposit**, or `L > MAX_CODE_SIZE`): Do NOT charge `GAS_CODE_DEPOSIT
* L` or `HASH_COST(L)`

And §"Transaction-level gas accounting":
> On child **exceptional halt**, all state gas consumed by the child,
both from the reservoir and any that spilled into `gas_left`, is
restored to the parent's reservoir.

## Test plan

- [x] geth+besu: 161 blocks (5+ epochs) with heavy spamoor load (eoatx
50 + evm-fuzz 25 + tx-fuzz 15), zero errors
- [x] Without Bug 2 fix: geth+besu chain-split at block ~30 under load —
`blockGasUsed` uint64 underflow
- [x] geth+nethermind: 86+ blocks no-load, 162 blocks eoatx load
(nethermind has separate BAL validation bug under fuzz)
- [x] geth+nimbus: 150+ blocks evm-fuzz with nimbus CALL fix applied —
gasUsed matches
- [x] Verified cross-client: nethermind and besu both charge CALL state
gas before 63/64

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 11:07:36 +01:00
..
filtermaps core/filtermaps: fix operator precedence in delete logging condition (#33280) 2025-12-06 04:21:38 +01:00
forkid params: set osaka and BPO1 & BPO2 mainnet dates (#33063) 2025-11-03 17:41:22 +01:00
history core: initialize history pruning in BlockChain (#31636) 2025-04-15 14:32:46 +02:00
overlay core/overlay: fix incorrect debug log key/value in LoadTransitionState (#32637) 2025-12-14 21:51:13 +01:00
rawdb all: implement eip 7928 block access lists 2026-03-04 20:03:46 -05:00
state address more lint errors 2026-03-04 21:17:43 -05:00
stateless cmd/geth: add inspect trie tool to analysis trie storage (#28892) 2026-02-24 10:56:00 -07:00
tracing all: implement eip 7928 block access lists 2026-03-04 20:03:46 -05:00
txpool core: fix rebasing issues 2026-03-05 13:55:51 +01:00
types address more lint errors 2026-03-04 21:17:43 -05:00
vm core/vm: fix EIP-8037 CALL state gas ordering + code-store OOG underflow (#33972) 2026-03-09 11:07:36 +01:00
.gitignore Renamed chain => core 2014-12-04 10:28:02 +01:00
bench_test.go core: fix rebasing issues 2026-03-05 13:55:51 +01:00
bintrie_witness_test.go core: fix rebasing issues 2026-03-05 13:55:51 +01:00
block_validator.go all: implement eip 7928 block access lists 2026-03-04 20:03:46 -05:00
block_validator_test.go eth/catalyst: add initial OpenTelemetry tracing for newPayload (#33521) 2026-02-17 17:08:57 +01:00
blockchain.go address more lint errors 2026-03-04 21:17:43 -05:00
blockchain_insert.go core: remove unused peek function in insertIterator (#33155) 2025-11-12 15:30:16 +08:00
blockchain_reader.go ethstats: report newPayload processing time to stats server (#33395) 2026-01-05 17:49:30 +01:00
blockchain_repair_test.go core: consolidate BlockChain constructor options (#31925) 2025-06-19 12:21:15 +02:00
blockchain_sethead_test.go core: consolidate BlockChain constructor options (#31925) 2025-06-19 12:21:15 +02:00
blockchain_snapshot_test.go triedb/pathdb, eth: use double-buffer mechanism in pathdb (#30464) 2025-06-22 20:40:54 +08:00
blockchain_stats.go all: implement eip 7928 block access lists 2026-03-04 20:03:46 -05:00
blockchain_test.go core: fix rebasing issues 2026-03-05 13:55:51 +01:00
chain_makers.go core: fix rebasing issues 2026-03-05 13:55:51 +01:00
chain_makers_test.go core: consolidate BlockChain constructor options (#31925) 2025-06-19 12:21:15 +02:00
dao_test.go core: consolidate BlockChain constructor options (#31925) 2025-06-19 12:21:15 +02:00
error.go core: implement eip-7778: block gas accounting without refunds (#33593) 2026-03-04 18:18:18 +08:00
eth_transfer_logs_test.go core, core/vm: implement EIP-7708 2026-03-04 19:23:37 -05:00
events.go ethstats: report newPayload processing time to stats server (#33395) 2026-01-05 17:49:30 +01:00
evm.go core: fix rebasing issues 2026-03-05 13:55:51 +01:00
gaspool.go core: fixed issues from devnet 2026-03-05 19:29:57 +01:00
gen_genesis.go all: implement eip 7928 block access lists 2026-03-04 20:03:46 -05:00
genesis.go all: implement eip 7928 block access lists 2026-03-04 20:03:46 -05:00
genesis_alloc.go params: add hoodi testnet definition (#31406) 2025-03-18 12:07:49 +01:00
genesis_test.go trie/bintrie: fix tree key hashing to match spec (#33694) 2026-01-28 11:51:02 +01:00
headerchain.go core/rawdb: reduce allocations in rawdb.ReadHeaderNumber (#31913) 2025-07-15 15:48:36 +02:00
headerchain_test.go core/state, core/tracing: new state update hook (#33490) 2026-01-08 11:07:19 +08:00
mkalloc.go accounts, cmd/geth, core: close opened files (#29598) 2024-04-30 15:47:21 +02:00
parallel_state_processor.go core: fixed issues from devnet 2026-03-05 17:26:27 +01:00
rlp_test.go crypto/keccak: vendor in golang.org/x/crypto/sha3 (#33323) 2026-02-03 14:55:27 -07:00
sender_cacher.go core: use sync.Once for SenderCacher initialization (#31029) 2025-01-16 14:36:45 +01:00
state_prefetcher.go core: implement eip-7778: block gas accounting without refunds (#33593) 2026-03-04 18:18:18 +08:00
state_processor.go core: fix rebasing issues 2026-03-05 13:55:51 +01:00
state_processor_test.go core/vm: implement eip-7843: SLOTNUM (#33589) 2026-02-26 13:53:46 +01:00
state_transition.go core/vm: fix EIP-8037 CALL state gas ordering + code-store OOG underflow (#33972) 2026-03-09 11:07:36 +01:00
stateless.go all: implement eip 7928 block access lists 2026-03-04 20:03:46 -05:00
txindexer.go core/rawdb: reduce allocations in rawdb.ReadHeaderNumber (#31913) 2025-07-15 15:48:36 +02:00
txindexer_test.go core/rawdb: integrate eradb backend for RPC (#31604) 2025-06-03 10:47:38 +02:00
types.go all: implement eip 7928 block access lists 2026-03-04 20:03:46 -05:00