core/vm: check that we have enough gas to pay for state gas before charge

This commit is contained in:
MariusVanDerWijden 2026-06-14 14:35:03 +02:00
parent ee951fe471
commit 9e04883a85
No known key found for this signature in database

View file

@ -506,12 +506,16 @@ func gasCallIntrinsic(evm *EVM, contract *Contract, stack *Stack, mem *Memory, m
if evm.chainRules.IsAmsterdam { if evm.chainRules.IsAmsterdam {
// EIP-8037: the cost of creating a new account via a value-bearing // EIP-8037: the cost of creating a new account via a value-bearing
// CALL is metered as state gas (NEW_ACCOUNT * CostPerStateByte), // CALL is metered as state gas (NEW_ACCOUNT * CostPerStateByte),
// not the legacy regular CallNewAccountGas. Charge it directly here // not the legacy regular CallNewAccountGas. It drains the state
// so it drains the state reservoir (spilling into regular gas only // reservoir, spilling into regular gas only when the reservoir is
// when the reservoir is exhausted), mirroring the spec's inline // exhausted, mirroring the spec's inline charge_state_gas in
// charge_state_gas call in system.call. // system.call.
if transfersValue && evm.StateDB.Empty(address) { if transfersValue && evm.StateDB.Empty(address) {
stateGas := params.AccountCreationSize * evm.Context.CostPerStateByte stateGas := params.AccountCreationSize * evm.Context.CostPerStateByte
regularAfterCall := contract.Gas.RegularGas - gas
if stateGas > contract.Gas.StateGas && stateGas-contract.Gas.StateGas > regularAfterCall {
return 0, ErrOutOfGas
}
if !contract.chargeState(stateGas, evm.Config.Tracer, tracing.GasChangeAccountCreation) { if !contract.chargeState(stateGas, evm.Config.Tracer, tracing.GasChangeAccountCreation) {
return 0, ErrOutOfGas return 0, ErrOutOfGas
} }