core/vm: pre-charge account creation in Create family unconditionally

This commit is contained in:
Gary Rong 2026-06-15 11:50:52 +08:00
parent 7d74166d3d
commit 0b3dffcf00
11 changed files with 259 additions and 44 deletions

View file

@ -686,12 +686,13 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
return nil, err
}
// Execute the transaction's creation.
ret, _, result, vmerr = st.evm.Create(msg.From, msg.Data, st.gasRemaining.ForwardAll(), value)
var creation bool
ret, _, result, creation, vmerr = st.evm.Create(msg.From, msg.Data, st.gasRemaining.ForwardAll(), value)
st.gasRemaining.Absorb(result, forwarded)
// If the contract creation failed, refund the account-creation state
// gas pre-charged in IntrinsicGas.
if rules.IsAmsterdam && vmerr != nil {
// If the contract creation failed, or the destination was pre-existing,
// refund the account-creation state gas pre-charged in IntrinsicGas.
if rules.IsAmsterdam && !creation {
st.gasRemaining.RefundState(params.AccountCreationSize * st.evm.Context.CostPerStateByte)
}
} else {

View file

@ -28,17 +28,17 @@ func _() {
_ = x[GasChangeWitnessCodeChunk-17]
_ = x[GasChangeWitnessContractCollisionCheck-18]
_ = x[GasChangeTxDataFloor-19]
_ = x[GasChangeAccountCreation-20]
_ = x[GasChangeRefundAccountCreation-20]
_ = x[GasChangeIgnored-255]
}
const (
_GasChangeReason_name_0 = "UnspecifiedTxInitialBalanceTxIntrinsicGasTxRefundsTxLeftOverReturnedCallInitialBalanceCallLeftOverReturnedCallLeftOverRefundedCallContractCreationCallContractCreation2CallCodeStorageCallOpCodeCallPrecompiledContractCallStorageColdAccessCallFailedExecutionWitnessContractInitWitnessContractCreationWitnessCodeChunkWitnessContractCollisionCheckTxDataFloorAccountCreation"
_GasChangeReason_name_0 = "UnspecifiedTxInitialBalanceTxIntrinsicGasTxRefundsTxLeftOverReturnedCallInitialBalanceCallLeftOverReturnedCallLeftOverRefundedCallContractCreationCallContractCreation2CallCodeStorageCallOpCodeCallPrecompiledContractCallStorageColdAccessCallFailedExecutionWitnessContractInitWitnessContractCreationWitnessCodeChunkWitnessContractCollisionCheckTxDataFloorRefundAccountCreation"
_GasChangeReason_name_1 = "Ignored"
)
var (
_GasChangeReason_index_0 = [...]uint16{0, 11, 27, 41, 50, 68, 86, 106, 126, 146, 167, 182, 192, 215, 236, 255, 274, 297, 313, 342, 353, 368}
_GasChangeReason_index_0 = [...]uint16{0, 11, 27, 41, 50, 68, 86, 106, 126, 146, 167, 182, 192, 215, 236, 255, 274, 297, 313, 342, 353, 374}
)
func (i GasChangeReason) String() string {

View file

@ -472,9 +472,9 @@ const (
// transaction data. This change will always be a negative change.
GasChangeTxDataFloor GasChangeReason = 19
// GasChangeAccountCreation represents the state gas charging for account
// creation inside the call/create frame.
GasChangeAccountCreation GasChangeReason = 20
// GasChangeRefundAccountCreation represents the cancellation of a
// pre-charged account-creation cost when no account is created.
GasChangeRefundAccountCreation GasChangeReason = 20
// GasChangeIgnored is a special value that can be used to indicate that the gas change should be ignored as
// it will be "manually" tracked by a direct emit of the gas change event.

View file

@ -152,6 +152,16 @@ func (c *Contract) chargeState(s uint64, logger *tracing.Hooks, reason tracing.G
return true
}
// refundState refunds the pre-charged state gas back to state reservoir.
func (c *Contract) refundState(s uint64, logger *tracing.Hooks, reason tracing.GasChangeReason) {
prior := c.Gas
c.Gas.RefundState(s)
if s != 0 && logger.HasGasHook() && reason != tracing.GasChangeIgnored {
logger.EmitGasChange(prior.AsTracing(), c.Gas.AsTracing(), reason)
}
}
// refundGas absorbs a sub-call's leftover GasBudget into this contract's gas state.
func (c *Contract) refundGas(child GasBudget, forwarded uint64, logger *tracing.Hooks, reason tracing.GasChangeReason) {
prior := c.Gas

View file

@ -595,7 +595,10 @@ func enable7843(jt *JumpTable) {
// enable8037 enables the multidimensional-metering as specified in EIP-8037.
func enable8037(jt *JumpTable) {
jt[CREATE].constantGas = params.CreateGasAmsterdam
jt[CREATE].dynamicGas = gasCreateEip8037
jt[CREATE2].constantGas = params.CreateGasAmsterdam
jt[CREATE2].dynamicGas = gasCreate2Eip8037
jt[CALL].dynamicGas = gasCallEIP8037
jt[SELFDESTRUCT].dynamicGas = gasSelfdestruct8037
jt[SSTORE].dynamicGas = gasSStore8037
}

View file

@ -289,16 +289,6 @@ func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, g
}
evm.StateDB.CreateAccount(addr)
}
if evm.chainRules.IsAmsterdam && !value.IsZero() && evm.StateDB.Empty(addr) {
prev, ok := gas.ChargeState(params.AccountCreationSize * evm.Context.CostPerStateByte)
if !ok {
evm.StateDB.RevertToSnapshot(snapshot)
return nil, gas.ExitHalt(reservoir), ErrOutOfGas
}
if evm.Config.Tracer.HasGasHook() {
evm.Config.Tracer.EmitGasChange(prev.AsTracing(), gas.AsTracing(), tracing.GasChangeAccountCreation)
}
}
// Perform the value transfer only in non-syscall mode.
// Calling this is required even for zero-value transfers,
// to ensure the state clearing mechanism is applied.
@ -484,7 +474,7 @@ func (evm *EVM) StaticCall(caller common.Address, addr common.Address, input []b
}
// create creates a new contract using code as deployment code.
func (evm *EVM) create(caller common.Address, code []byte, gas GasBudget, value *uint256.Int, address common.Address, typ OpCode) (ret []byte, createAddress common.Address, result GasBudget, err error) {
func (evm *EVM) create(caller common.Address, code []byte, gas GasBudget, value *uint256.Int, address common.Address, typ OpCode) (ret []byte, createAddress common.Address, result GasBudget, creation bool, err error) {
// Depth check execution. Fail if we're trying to execute above the
// limit.
var nonce uint64
@ -505,7 +495,7 @@ func (evm *EVM) create(caller common.Address, code []byte, gas GasBudget, value
}(gas)
}
if err != nil {
return nil, common.Address{}, gas, err
return nil, common.Address{}, gas, false, err
}
// Increment the caller's nonce after passing all validations
evm.StateDB.SetNonce(caller, nonce+1, tracing.NonceChangeContractCreator)
@ -516,7 +506,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(reservoir), ErrOutOfGas
return nil, common.Address{}, gas.ExitHalt(reservoir), false, ErrOutOfGas
}
if evm.Config.Tracer.HasGasHook() {
evm.Config.Tracer.EmitGasChange(prior.AsTracing(), gas.AsTracing(), tracing.GasChangeWitnessContractCollisionCheck)
@ -543,7 +533,7 @@ func (evm *EVM) create(caller common.Address, code []byte, gas GasBudget, value
}
// EIP-8037 collision rule: the state reservoir is fully preserved on
// address collision while regular gas is burnt.
return nil, common.Address{}, halt, ErrContractAddressCollision
return nil, common.Address{}, halt, false, ErrContractAddressCollision
}
// Create a new account on the state only if the object was not present.
// It might be possible the contract code is deployed to a pre-existent
@ -551,18 +541,7 @@ func (evm *EVM) create(caller common.Address, code []byte, gas GasBudget, value
snapshot := evm.StateDB.Snapshot()
if !evm.StateDB.Exist(address) {
evm.StateDB.CreateAccount(address)
if evm.chainRules.IsAmsterdam && evm.depth > 0 {
// Only charge state gas if we are not doing a create transaction.
// Prevents double charging with IntrinsicGas.
prev, ok := gas.ChargeState(params.AccountCreationSize * evm.Context.CostPerStateByte)
if !ok {
return nil, common.Address{}, gas.ExitHalt(reservoir), ErrOutOfGas
}
if evm.Config.Tracer.HasGasHook() {
evm.Config.Tracer.EmitGasChange(prev.AsTracing(), gas.AsTracing(), tracing.GasChangeAccountCreation)
}
}
creation = true
}
// CreateContract means that regardless of whether the account previously existed
// in the state trie or not, it _now_ becomes created as a _contract_ account.
@ -577,7 +556,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(reservoir), ErrOutOfGas
return nil, common.Address{}, gas.ExitHalt(reservoir), false, ErrOutOfGas
}
prior, _ := gas.Charge(GasCosts{RegularGas: consumed})
if evm.Config.Tracer.HasGasHook() {
@ -608,11 +587,11 @@ func (evm *EVM) create(caller common.Address, code []byte, gas GasBudget, value
evm.Config.Tracer.EmitGasChange(contract.Gas.AsTracing(), exit.AsTracing(), tracing.GasChangeCallFailedExecution)
}
}
return ret, address, exit, err
return ret, address, exit, false, err
}
// Either success, or pre-Homestead ErrCodeStoreOutOfGas (gas preserved).
// Both packaged as a success-form GasBudget.
return ret, address, contract.Gas.ExitSuccess(), err
return ret, address, contract.Gas.ExitSuccess(), creation, err
}
// initNewContract runs a new contract's creation code, performs checks on the
@ -668,7 +647,7 @@ func (evm *EVM) initNewContract(contract *Contract, address common.Address) ([]b
}
// Create creates a new contract using code as deployment code.
func (evm *EVM) Create(caller common.Address, code []byte, gas GasBudget, value *uint256.Int) (ret []byte, contractAddr common.Address, result GasBudget, err error) {
func (evm *EVM) Create(caller common.Address, code []byte, gas GasBudget, value *uint256.Int) (ret []byte, contractAddr common.Address, result GasBudget, creation bool, err error) {
contractAddr = crypto.CreateAddress(caller, evm.StateDB.GetNonce(caller))
return evm.create(caller, code, gas, value, contractAddr, CREATE)
}
@ -677,7 +656,7 @@ func (evm *EVM) Create(caller common.Address, code []byte, gas GasBudget, value
//
// The different between Create2 with Create is Create2 uses keccak256(0xff ++ msg.sender ++ salt ++ keccak256(init_code))[12:]
// instead of the usual sender-and-nonce-hash as the address where the contract is initialized at.
func (evm *EVM) Create2(caller common.Address, code []byte, gas GasBudget, endowment *uint256.Int, salt *uint256.Int) (ret []byte, contractAddr common.Address, result GasBudget, err error) {
func (evm *EVM) Create2(caller common.Address, code []byte, gas GasBudget, endowment *uint256.Int, salt *uint256.Int) (ret []byte, contractAddr common.Address, result GasBudget, creation bool, err error) {
inithash := crypto.Keccak256Hash(code)
contractAddr = crypto.CreateAddress2(caller, salt.Bytes32(), inithash[:])
return evm.create(caller, code, gas, endowment, contractAddr, CREATE2)

View file

@ -519,6 +519,117 @@ func gasSelfdestruct(evm *EVM, contract *Contract, stack *Stack, mem *Memory, me
return GasCosts{RegularGas: gas}, nil
}
func gasCreateEip8037(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) {
if evm.readOnly {
return GasCosts{}, ErrWriteProtection
}
gas, err := memoryGasCost(mem, memorySize)
if err != nil {
return GasCosts{}, err
}
size, overflow := stack.back(2).Uint64WithOverflow()
if overflow {
return GasCosts{}, ErrGasUintOverflow
}
if err := CheckMaxInitCodeSize(&evm.chainRules, size); err != nil {
return GasCosts{}, err
}
// Since size <= MaxInitCodeSizeAmsterdam, these multiplications cannot overflow
words := (size + 31) / 32
wordGas := params.InitCodeWordGas * words
// Unconditionally pre-charge the account creation and refunds if the creation
// doesn't happen after the create-frame.
return GasCosts{
RegularGas: gas + wordGas,
StateGas: params.AccountCreationSize * evm.Context.CostPerStateByte,
}, nil
}
func gasCreate2Eip8037(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) {
if evm.readOnly {
return GasCosts{}, ErrWriteProtection
}
gas, err := memoryGasCost(mem, memorySize)
if err != nil {
return GasCosts{}, err
}
size, overflow := stack.back(2).Uint64WithOverflow()
if overflow {
return GasCosts{}, ErrGasUintOverflow
}
if err := CheckMaxInitCodeSize(&evm.chainRules, size); err != nil {
return GasCosts{}, err
}
// Since size <= MaxInitCodeSizeAmsterdam, these multiplications cannot overflow
words := (size + 31) / 32
// CREATE2 charges both InitCodeWordGas (EIP-3860) and Keccak256WordGas
// (for address hashing).
wordGas := (params.InitCodeWordGas + params.Keccak256WordGas) * words
// Unconditionally pre-charge the account creation and refunds if the creation
// doesn't happen after the create-frame.
return GasCosts{
RegularGas: gas + wordGas,
StateGas: params.AccountCreationSize * evm.Context.CostPerStateByte,
}, nil
}
// regularGasCall8037 is the intrinsic gas calculator for CALL in Amsterdam.
// It computes memory expansion + value transfer gas but excludes new account
// creation, which is handled as state gas by the wrapper.
func regularGasCall8037(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
var (
gas uint64
transfersValue = !stack.back(2).IsZero()
)
if evm.readOnly && transfersValue {
return 0, ErrWriteProtection
}
memoryGas, err := memoryGasCost(mem, memorySize)
if err != nil {
return 0, err
}
var transferGas uint64
if transfersValue && !evm.chainRules.IsEIP4762 {
transferGas = params.CallValueTransferGas
}
var overflow bool
if gas, overflow = math.SafeAdd(memoryGas, transferGas); overflow {
return 0, ErrGasUintOverflow
}
return gas, nil
}
// stateGasCall8037 is the stateful gas calculator for CALL in Amsterdam (EIP-8037).
// It only returns the state-dependent gas (account creation as state gas).
// Memory gas, transfer gas, and callGas are handled by gasCallStateless and
// makeCallVariantGasCall.
func stateGasCall8037(evm *EVM, contract *Contract, stack *Stack) (uint64, error) {
var (
gas uint64
transfersValue = !stack.back(2).IsZero()
address = common.Address(stack.back(1).Bytes20())
)
// TODO(rjl, marius), can EIP8037 implicitly means the EIP158 is also activated?
// It's technically possible to skip the EIP158 but very unlikely in practice.
if evm.chainRules.IsEIP158 {
// Important: use StateDB.Empty instead of !StateDB.Exist. An account may exist
// in the current state yet still be considered non-existent by EIP-161 if its
// nonce, balance, and code are all zero. Such accounts can appear temporarily
// during execution (e.g. via SELFDESTRUCT) and are removed at tx end.
//
// Funding such an account makes it permanent state growth and must be charged.
if transfersValue && evm.StateDB.Empty(address) {
gas += params.AccountCreationSize * evm.Context.CostPerStateByte
}
} else if !evm.StateDB.Exist(address) {
gas += params.AccountCreationSize * evm.Context.CostPerStateByte
}
return gas, nil
}
func gasSelfdestruct8037(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) {
if evm.readOnly {
return GasCosts{}, ErrWriteProtection

View file

@ -662,7 +662,7 @@ func opCreate(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
stackvalue := size
child := scope.Contract.forwardGas(forward, evm.Config.Tracer, tracing.GasChangeCallContractCreation)
res, addr, result, suberr := evm.Create(scope.Contract.Address(), input, child, &value)
res, addr, result, creation, suberr := evm.Create(scope.Contract.Address(), input, child, &value)
// Push item on the stack based on the returned error. If the ruleset is
// homestead we must check for CodeStoreOutOfGasError (homestead only
// rule) and treat as an error, if the ruleset is frontier we must
@ -679,6 +679,10 @@ func opCreate(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
// Refund the leftover gas back to current frame
scope.Contract.refundGas(result, forward, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
// Refund the state gas of account-creation if creation doesn't happen
if evm.GetRules().IsAmsterdam && !creation {
scope.Contract.refundState(params.AccountCreationSize*evm.Context.CostPerStateByte, evm.Config.Tracer, tracing.GasChangeRefundAccountCreation)
}
if suberr == ErrExecutionReverted {
evm.returnData = res // set REVERT data to return data buffer
return res, nil
@ -701,7 +705,7 @@ func opCreate2(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
// reuse size int for stackvalue
stackvalue := size
child := scope.Contract.forwardGas(forward, evm.Config.Tracer, tracing.GasChangeCallContractCreation2)
res, addr, result, suberr := evm.Create2(scope.Contract.Address(), input, child, &endowment, &salt)
res, addr, result, creation, suberr := evm.Create2(scope.Contract.Address(), input, child, &endowment, &salt)
// Push item on the stack based on the returned error.
if suberr != nil {
stackvalue.Clear()
@ -713,6 +717,10 @@ func opCreate2(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
// Refund the leftover gas back to current frame
scope.Contract.refundGas(result, forward, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
// Refund the state gas of account-creation if creation doesn't happen
if evm.GetRules().IsAmsterdam && !creation {
scope.Contract.refundState(params.AccountCreationSize*evm.Context.CostPerStateByte, evm.Config.Tracer, tracing.GasChangeRefundAccountCreation)
}
if suberr == ErrExecutionReverted {
evm.returnData = res // set REVERT data to return data buffer
return res, nil
@ -758,6 +766,11 @@ func opCall(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
}
scope.Contract.refundGas(result, gas, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
// If the call frame reverts or halts exceptionally, the charged state-gas
// is refilled back to the state reservoir in Amsterdam.
if evm.chainRules.IsAmsterdam && err != nil && !value.IsZero() && evm.StateDB.Empty(toAddr) {
scope.Contract.refundState(params.AccountCreationSize*evm.Context.CostPerStateByte, evm.Config.Tracer, tracing.GasChangeRefundAccountCreation)
}
evm.returnData = ret
return ret, nil
}

View file

@ -28,6 +28,9 @@ type (
intrinsicGasFunc func(*EVM, *Contract, *Stack, *Memory, uint64) (uint64, error) // last parameter is the requested memory size as a uint64
// memorySizeFunc returns the required size, and whether the operation overflowed a uint64
memorySizeFunc func(*Stack) (size uint64, overflow bool)
regularGasFunc func(*EVM, *Contract, *Stack, *Memory, uint64) (uint64, error)
stateGasFunc func(*EVM, *Contract, *Stack) (uint64, error)
)
type operation struct {

View file

@ -262,6 +262,7 @@ var (
gasDelegateCallEIP7702 = makeCallVariantGasCallEIP7702(gasDelegateCallIntrinsic)
gasStaticCallEIP7702 = makeCallVariantGasCallEIP7702(gasStaticCallIntrinsic)
gasCallCodeEIP7702 = makeCallVariantGasCallEIP7702(gasCallCodeIntrinsic)
innerGasCallEIP8037 = makeCallVariantGasCallEIP8037(regularGasCall8037, stateGasCall8037)
)
func gasCallEIP7702(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) {
@ -276,6 +277,14 @@ func gasCallEIP7702(evm *EVM, contract *Contract, stack *Stack, mem *Memory, mem
return innerGasCallEIP7702(evm, contract, stack, mem, memorySize)
}
func gasCallEIP8037(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) {
transfersValue := !stack.back(2).IsZero()
if evm.readOnly && transfersValue {
return GasCosts{}, ErrWriteProtection
}
return innerGasCallEIP8037(evm, contract, stack, mem, memorySize)
}
func makeCallVariantGasCallEIP7702(intrinsicFunc intrinsicGasFunc) gasFunc {
return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) {
var (
@ -362,3 +371,89 @@ func makeCallVariantGasCallEIP7702(intrinsicFunc intrinsicGasFunc) gasFunc {
return GasCosts{RegularGas: totalCost}, nil
}
}
// makeCallVariantGasCallEIP8037 creates a call gas function for Amsterdam (EIP-8037).
// It extends the EIP-7702 pattern with state gas handling and GasUsed tracking.
// intrinsicFunc computes the regular gas (memory + transfer, no new account creation).
// stateGasFunc computes the state gas (new account creation as state gas).
func makeCallVariantGasCallEIP8037(regularFunc regularGasFunc, stateGasFunc stateGasFunc) gasFunc {
return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) {
var (
eip2929Cost uint64
eip7702Cost uint64
addr = common.Address(stack.back(1).Bytes20())
)
// EIP-2929 cold access check.
if !evm.StateDB.AddressInAccessList(addr) {
evm.StateDB.AddAddressToAccessList(addr)
eip2929Cost = params.ColdAccountAccessCostEIP2929 - params.WarmStorageReadCostEIP2929
if !contract.chargeRegular(eip2929Cost, evm.Config.Tracer, tracing.GasChangeCallStorageColdAccess) {
return GasCosts{}, ErrOutOfGas
}
}
// Compute regular cost (memory + transfer, no new account creation).
regularCost, err := regularFunc(evm, contract, stack, mem, memorySize)
if err != nil {
return GasCosts{}, err
}
// Charge intrinsic cost directly (regular gas). This must happen
// BEFORE state gas to prevent reservoir inflation, and also serves
// as the OOG guard before stateful operations.
if !contract.chargeRegular(regularCost, evm.Config.Tracer, tracing.GasChangeCallOpCode) {
return GasCosts{}, ErrOutOfGas
}
// EIP-7702 delegation check.
if target, ok := types.ParseDelegation(evm.StateDB.GetCode(addr)); ok {
if evm.StateDB.AddressInAccessList(target) {
eip7702Cost = params.WarmStorageReadCostEIP2929
} else {
evm.StateDB.AddAddressToAccessList(target)
eip7702Cost = params.ColdAccountAccessCostEIP2929
}
if !contract.chargeRegular(eip7702Cost, evm.Config.Tracer, tracing.GasChangeCallStorageColdAccess) {
return GasCosts{}, ErrOutOfGas
}
}
// Compute and charge state gas (new account creation) AFTER regular gas.
stateGas, err := stateGasFunc(evm, contract, stack)
if err != nil {
return GasCosts{}, err
}
if stateGas > 0 {
if _, ok := contract.Gas.ChargeState(stateGas); !ok {
return GasCosts{}, ErrOutOfGas
}
}
// Calculate the gas budget for the nested call (63/64 rule).
evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas.RegularGas, 0, stack.back(0))
if err != nil {
return GasCosts{}, err
}
// Temporarily undo direct regular charges for tracer reporting.
// The interpreter will charge the returned totalCost.
contract.Gas.RegularGas += eip2929Cost + eip7702Cost + regularCost
contract.Gas.UsedRegularGas -= eip2929Cost + eip7702Cost + regularCost
// Aggregate total cost.
var (
overflow bool
totalCost uint64
)
if totalCost, overflow = math.SafeAdd(eip2929Cost, eip7702Cost); overflow {
return GasCosts{}, ErrGasUintOverflow
}
if totalCost, overflow = math.SafeAdd(totalCost, regularCost); overflow {
return GasCosts{}, ErrGasUintOverflow
}
if totalCost, overflow = math.SafeAdd(totalCost, evm.callGasTemp); overflow {
return GasCosts{}, ErrGasUintOverflow
}
return GasCosts{RegularGas: totalCost}, nil
}
}

View file

@ -179,7 +179,7 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) {
// - reset transient storage(eip 1153)
cfg.State.Prepare(rules, cfg.Origin, cfg.Coinbase, nil, vm.ActivePrecompiles(rules), nil)
// Call the code with the given configuration.
code, address, result, err := vmenv.Create(
code, address, result, _, err := vmenv.Create(
cfg.Origin,
input,
vm.NewGasBudget(cfg.GasLimit, 0),