From 05b723954805f1f621e96edd27fb38c8692ecb53 Mon Sep 17 00:00:00 2001 From: MariusVanDerWijden Date: Wed, 29 Apr 2026 23:10:30 +0200 Subject: [PATCH] core: misc fixes (claude) --- core/state/journal.go | 8 +++----- core/state_transition.go | 18 +++++++++++------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/core/state/journal.go b/core/state/journal.go index cb54858305..3d8a3193e2 100644 --- a/core/state/journal.go +++ b/core/state/journal.go @@ -288,16 +288,14 @@ func (j *journal) stateChangedBytes(revid int, stateObjects map[common.Address]* var totalBytes int64 // Per EIP-8037 spec compute_state_byte_diff: only count +112 for accounts - // that exist at frame exit. Per EIP-161, accounts that end up with - // nonce=0, balance=0, and empty code are considered non-existent and - // pruned — these don't count even though we created the object record - // (e.g. AddBalance(addr, 0) for a zero-value SELFDESTRUCT to a - // non-existent beneficiary). for addr := range created { obj := stateObjects[addr] if obj == nil { continue } + if obj.origin != nil { + continue + } if obj.empty() { continue } diff --git a/core/state_transition.go b/core/state_transition.go index 61663e26d4..d0458ed397 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -649,16 +649,20 @@ func (st *stateTransition) execute() (*ExecutionResult, error) { // EIP-8037: charge state gas for the outer call frame's own state changes. if rules.IsAmsterdam { if vmerr == nil { - outerBytes := st.state.StateChangedBytes(outerSnapshot, false) - // For contract-creation txs the intrinsic already paid for the - // account creation; subtract it so we don't double-charge. + // Only contract-creation txs need an outer charge: the intrinsic + // pre-paid for the +112 account creation, but inner evm.Create's + // frame-end excludes it (post-create diff snapshot), so the outer + // charge reconciles. CALL txs don't need any outer charge — the + // inner evm.Call's apply-frame already handles everything via its + // post-value-transfer diff snapshot, matching spec semantics for + // the outermost frame. if contractCreation { + outerBytes := st.state.StateChangedBytes(outerSnapshot, false) outerBytes -= int64(params.AccountCreationSize) + alreadyPaid := st.gasRemaining.StateGasUsed + thisCallCost := outerBytes*int64(st.evm.Context.CostPerStateByte) - alreadyPaid + st.gasRemaining.Charge(vm.GasCosts{StateGas: thisCallCost}) } - // EIP-8037 spec: this_call_cost = growth_cost - already_paid. - alreadyPaid := st.gasRemaining.StateGasUsed - thisCallCost := outerBytes*int64(st.evm.Context.CostPerStateByte) - alreadyPaid - st.gasRemaining.Charge(vm.GasCosts{StateGas: thisCallCost}) // EIP-8037 + EIP-6780: refund state gas for accounts created and // selfdestructed in the same tx. Per spec interpreter.py:200-201,