From bf69a15de68bfac5f7e2a8faab24fca7016ac7ce Mon Sep 17 00:00:00 2001 From: Gary Rong Date: Thu, 21 May 2026 11:33:12 +0800 Subject: [PATCH] core/vm: change exit halt --- core/vm/evm.go | 28 +++++++++------------------- core/vm/gascosts.go | 23 ++++++++++++++++------- 2 files changed, 25 insertions(+), 26 deletions(-) diff --git a/core/vm/evm.go b/core/vm/evm.go index 76d6978a78..a16e9c8cc2 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -255,8 +255,6 @@ func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, g evm.captureEnd(evm.depth, startGas, result, ret, err) }(gas) } - initialStateGas := gas.StateGas - // Fail if we're trying to execute above the call depth limit if evm.depth > int(params.CallCreateDepth) { return nil, gas.Preserved(), ErrDepth @@ -281,7 +279,7 @@ func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, g wgas := evm.AccessEvents.CodeHashGas(addr, true, gas.RegularGas, false) if _, ok := gas.ChargeRegular(wgas); !ok { evm.StateDB.RevertToSnapshot(snapshot) - return nil, gas.ExitHalt(initialStateGas), ErrOutOfGas + return nil, gas.ExitHalt(), ErrOutOfGas } } @@ -316,7 +314,7 @@ func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, g } // Calculate the remaining gas at the end of frame - exitGas := gas.Exit(err, initialStateGas) + exitGas := gas.Exit(err) if err != nil { evm.StateDB.RevertToSnapshot(snapshot) @@ -345,8 +343,6 @@ func (evm *EVM) CallCode(caller common.Address, addr common.Address, input []byt evm.captureEnd(evm.depth, startGas, result, ret, err) }(gas) } - initialStateGas := gas.StateGas - // Fail if we're trying to execute above the call depth limit if evm.depth > int(params.CallCreateDepth) { return nil, gas.Preserved(), ErrDepth @@ -370,7 +366,7 @@ func (evm *EVM) CallCode(caller common.Address, addr common.Address, input []byt } // Calculate the remaining gas at the end of frame - exitGas := gas.Exit(err, initialStateGas) + exitGas := gas.Exit(err) if err != nil { evm.StateDB.RevertToSnapshot(snapshot) @@ -398,8 +394,6 @@ func (evm *EVM) DelegateCall(originCaller common.Address, caller common.Address, evm.captureEnd(evm.depth, startGas, result, ret, err) }(gas) } - initialStateGas := gas.StateGas - // Fail if we're trying to execute above the call depth limit if evm.depth > int(params.CallCreateDepth) { return nil, gas.Preserved(), ErrDepth @@ -417,7 +411,7 @@ func (evm *EVM) DelegateCall(originCaller common.Address, caller common.Address, } // Calculate the remaining gas at the end of frame - exitGas := gas.Exit(err, initialStateGas) + exitGas := gas.Exit(err) if err != nil { evm.StateDB.RevertToSnapshot(snapshot) @@ -443,8 +437,6 @@ func (evm *EVM) StaticCall(caller common.Address, addr common.Address, input []b evm.captureEnd(evm.depth, startGas, result, ret, err) }(gas) } - initialStateGas := gas.StateGas - // Fail if we're trying to execute above the call depth limit if evm.depth > int(params.CallCreateDepth) { return nil, gas.Preserved(), ErrDepth @@ -472,7 +464,7 @@ func (evm *EVM) StaticCall(caller common.Address, addr common.Address, input []b } // Calculate the remaining gas at the end of frame - exitGas := gas.Exit(err, initialStateGas) + exitGas := gas.Exit(err) if err != nil { evm.StateDB.RevertToSnapshot(snapshot) if err != ErrExecutionReverted { @@ -499,8 +491,6 @@ func (evm *EVM) create(caller common.Address, code []byte, gas GasBudget, value err = ErrNonceUintOverflow } } - initialStateGas := gas.StateGas - if err == nil { evm.StateDB.SetNonce(caller, nonce+1, tracing.NonceChangeContractCreator) } @@ -519,7 +509,7 @@ func (evm *EVM) create(caller common.Address, code []byte, gas GasBudget, value statelessGas := evm.AccessEvents.ContractCreatePreCheckGas(address, gas.RegularGas) prior, ok := gas.Charge(GasCosts{RegularGas: statelessGas}) if !ok { - return nil, common.Address{}, gas.ExitHalt(initialStateGas), ErrOutOfGas + return nil, common.Address{}, gas.ExitHalt(), ErrOutOfGas } if evm.Config.Tracer.HasGasHook() { evm.Config.Tracer.EmitGasChange(prior.AsTracing(), gas.AsTracing(), tracing.GasChangeWitnessContractCollisionCheck) @@ -540,7 +530,7 @@ func (evm *EVM) create(caller common.Address, code []byte, gas GasBudget, value if evm.StateDB.GetNonce(address) != 0 || (contractHash != (common.Hash{}) && contractHash != types.EmptyCodeHash) || // non-empty code isEIP7610RejectedAccount(evm.ChainConfig().ChainID, address, evm.chainRules.IsEIP158) { - halt := gas.ExitHalt(initialStateGas) + halt := gas.ExitHalt() if evm.Config.Tracer.HasGasHook() { evm.Config.Tracer.EmitGasChange(gas.AsTracing(), halt.AsTracing(), tracing.GasChangeCallFailedExecution) } @@ -568,7 +558,7 @@ func (evm *EVM) create(caller common.Address, code []byte, gas GasBudget, value if evm.chainRules.IsEIP4762 { consumed, wanted := evm.AccessEvents.ContractCreateInitGas(address, gas.RegularGas) if consumed < wanted { - return nil, common.Address{}, gas.ExitHalt(initialStateGas), ErrOutOfGas + return nil, common.Address{}, gas.ExitHalt(), ErrOutOfGas } prior, _ := gas.Charge(GasCosts{RegularGas: consumed}) if evm.Config.Tracer.HasGasHook() { @@ -593,7 +583,7 @@ func (evm *EVM) create(caller common.Address, code []byte, gas GasBudget, value if err != nil && (evm.chainRules.IsHomestead || err != ErrCodeStoreOutOfGas) { evm.StateDB.RevertToSnapshot(snapshot) - exit := contract.Gas.Exit(err, initialStateGas) + exit := contract.Gas.Exit(err) if err != ErrExecutionReverted { if evm.Config.Tracer.HasGasHook() { evm.Config.Tracer.EmitGasChange(contract.Gas.AsTracing(), exit.AsTracing(), tracing.GasChangeCallFailedExecution) diff --git a/core/vm/gascosts.go b/core/vm/gascosts.go index 83d148b6ce..63269a071b 100644 --- a/core/vm/gascosts.go +++ b/core/vm/gascosts.go @@ -251,13 +251,22 @@ func (g GasBudget) ExitRevert() GasBudget { } // ExitHalt produces the leftover form for an exceptional halt. Remaining -// regular gas is accounted as burned; the reservoir resets to initialStateGas -// (the value the caller held at the call site). UsedStateGas is zeroed -// because state-gas effects do not persist on halt. -func (g GasBudget) ExitHalt(initialStateGas uint64) GasBudget { +// regular gas is burned into UsedRegularGas; the state dimension follows the +// same revert-style formula as ExitRevert because the spec routes both halt +// and revert through incorporate_child_on_error: +// +// parent.state_gas_left = parent + child.state_gas_used + child.state_gas_left +// +// which in our model means returning `StateGas + UsedStateGas` to the parent +// and zeroing the per-frame counter. +func (g GasBudget) ExitHalt() GasBudget { + reservoir := int64(g.StateGas) + g.UsedStateGas + if reservoir < 0 { + reservoir = 0 + } return GasBudget{ RegularGas: 0, - StateGas: initialStateGas, + StateGas: uint64(reservoir), UsedRegularGas: g.UsedRegularGas + g.RegularGas, UsedStateGas: 0, } @@ -272,14 +281,14 @@ func (g GasBudget) ExitHalt(initialStateGas uint64) GasBudget { // // Soft validation failures (occurring BEFORE evm.Run) should call Preserved // directly instead of going through this dispatcher. -func (g GasBudget) Exit(err error, initialStateGas uint64) GasBudget { +func (g GasBudget) Exit(err error) GasBudget { switch { case err == nil: return g.ExitSuccess() case err == ErrExecutionReverted: return g.ExitRevert() default: - return g.ExitHalt(initialStateGas) + return g.ExitHalt() } }