go-ethereum/core/vm
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
..
program all: fix problematic function name in comment (#32513) 2025-08-29 08:54:23 +08:00
runtime core: fix rebasing issues 2026-03-05 13:55:51 +01:00
testdata core/vm: switch modexp gas computation to uint64 (#32527) 2025-09-08 13:33:10 +02:00
analysis_legacy.go core/vm: add configurable jumpdest analysis cache (#32143) 2025-08-01 13:57:38 +02:00
analysis_legacy_test.go core/vm: using testing.B.Loop (#32660) 2025-09-19 17:06:55 -06:00
common.go core: implement eip 7954 increase Maximum Contract Size 2026-03-04 20:03:50 -05:00
contract.go core: fix rebasing issues 2026-03-05 13:55:51 +01:00
contracts.go core/vm: touch precompile object with Amsterdam enabled (#33742) 2026-02-24 21:55:10 +08:00
contracts_fuzz_test.go core/vm: touch precompile object with Amsterdam enabled (#33742) 2026-02-24 21:55:10 +08:00
contracts_test.go core/vm: touch precompile object with Amsterdam enabled (#33742) 2026-02-24 21:55:10 +08:00
doc.go core/vm: remove JIT VM codes (#16362) 2018-03-26 13:48:04 +03:00
eips.go core: fix rebasing issues 2026-03-05 13:55:51 +01:00
errors.go build: update to golangci-lint 1.61.0 (#30587) 2024-10-14 19:25:22 +02:00
evm.go core/vm: fix EIP-8037 CALL state gas ordering + code-store OOG underflow (#33972) 2026-03-09 11:07:36 +01:00
gas.go core/vm, cmd/evm: implement eof validation (#30418) 2024-10-02 15:05:50 +02:00
gas_table.go core: fixed issues from devnet 2026-03-05 19:29:57 +01:00
gas_table_test.go core: fix rebasing issues 2026-03-05 13:55:51 +01:00
gascosts.go core: fixed issues from devnet 2026-03-05 19:29:57 +01:00
instructions.go core: fixed issues from devnet 2026-03-05 19:29:57 +01:00
instructions_test.go core: fix rebasing issues 2026-03-05 13:55:51 +01:00
interface.go all: implement eip 7928 block access lists 2026-03-04 20:03:46 -05:00
interpreter.go core: fix rebasing issues 2026-03-05 13:55:51 +01:00
interpreter_test.go core: fix rebasing issues 2026-03-05 13:55:51 +01:00
jump_table.go core: fix rebasing issues 2026-03-05 13:55:51 +01:00
jump_table_export.go core/vm: use amsterdam jump table in lookup (#33947) 2026-03-04 13:42:25 +08:00
jump_table_test.go all: update license comments and AUTHORS (#31133) 2025-02-05 23:01:17 +01:00
jumpdests.go core/vm: add configurable jumpdest analysis cache (#32143) 2025-08-01 13:57:38 +02:00
memory.go core/vm: improve memory resize (#33056) 2025-11-26 16:50:16 +01:00
memory_table.go core/vm, cmd/evm: remove EOF (#32000) 2025-06-11 14:50:46 +02:00
memory_test.go core/vm: improve memory resize (#33056) 2025-11-26 16:50:16 +01:00
opcodes.go core/vm: implement eip-7843: SLOTNUM (#33589) 2026-02-26 13:53:46 +01:00
operations_acl.go core/vm: fix EIP-8037 CALL state gas ordering + code-store OOG underflow (#33972) 2026-03-09 11:07:36 +01:00
operations_verkle.go core: fix rebasing issues 2026-03-05 13:55:51 +01:00
stack.go core/vm: improved stack swap performance (#30249) 2024-08-06 14:38:47 +02:00
stack_table.go core/vm: 64 bit memory and gas calculations (#19210) 2019-03-12 11:40:05 +02:00