diff --git a/core/gaspool.go b/core/gaspool.go index 7c85e36fde..1e8b57fd11 100644 --- a/core/gaspool.go +++ b/core/gaspool.go @@ -36,6 +36,7 @@ type GasPool struct { // NewGasPool initializes the gasPool with the given amount. func NewGasPool(amount uint64) *GasPool { + fmt.Printf("DEBUG_POOL NewGasPool: amount=%d\n", amount) return &GasPool{ remaining: amount, initial: amount, @@ -45,6 +46,7 @@ func NewGasPool(amount uint64) *GasPool { // SubGas deducts the given amount from the pool if enough gas is // available and returns an error otherwise. func (gp *GasPool) SubGas(amount uint64) error { + fmt.Printf("DEBUG_POOL SubGas: before_remaining=%d amount=%d initial=%d\n", gp.remaining, amount, gp.initial) if gp.remaining < amount { return ErrGasLimitReached } @@ -55,6 +57,8 @@ func (gp *GasPool) SubGas(amount uint64) error { // ReturnGas adds the refunded gas back to the pool and updates // the cumulative gas usage accordingly. func (gp *GasPool) ReturnGas(returned uint64, gasUsed uint64) error { + fmt.Printf("DEBUG_POOL ReturnGas: before_remaining=%d returned=%d gasUsed=%d initial=%d cumR=%d cumS=%d\n", + gp.remaining, returned, gasUsed, gp.initial, gp.cumulativeRegular, gp.cumulativeState) if gp.remaining > math.MaxUint64-returned { return fmt.Errorf("%w: remaining: %d, returned: %d", ErrGasLimitOverflow, gp.remaining, returned) } @@ -73,38 +77,6 @@ func (gp *GasPool) ReturnGas(returned uint64, gasUsed uint64) error { return nil } -// ReturnGasAmsterdam returns unused gas to the pool using two-dimensional -// gas accounting (EIP-8037). receiptGasUsed is the per-tx gas the user pays -// (tx.gas - gas_left - state_gas_reservoir), used for receipt cumulative tracking. -// -// The block gas increment for this tx is the change in max(sumR, sumS) after -// adding the tx's per-dimension values, NOT max(txR, txS) per-tx. This avoids -// overcounting when the dominant dimension switches between transactions. -func (gp *GasPool) ReturnGasAmsterdam(txGasLimit, txRegular, txState, receiptGasUsed uint64) error { - oldUsed := max(gp.cumulativeRegular, gp.cumulativeState) - gp.cumulativeRegular += txRegular - gp.cumulativeState += txState - gp.cumulativeUsed += receiptGasUsed - newUsed := max(gp.cumulativeRegular, gp.cumulativeState) - blockGasIncrement := newUsed - oldUsed - if blockGasIncrement > txGasLimit { - // State gas via reservoir model can push the dimensional cost above - // the tx gas limit. Consume the excess from the pool. - excess := blockGasIncrement - txGasLimit - if gp.remaining < excess { - return fmt.Errorf("%w: remaining: %d, excess: %d", ErrGasLimitReached, gp.remaining, excess) - } - gp.remaining -= excess - } else { - returned := txGasLimit - blockGasIncrement - if gp.remaining > math.MaxUint64-returned { - return fmt.Errorf("%w: remaining: %d, returned: %d", ErrGasLimitOverflow, gp.remaining, returned) - } - gp.remaining += returned - } - return nil -} - // Gas returns the amount of gas remaining in the pool. func (gp *GasPool) Gas() uint64 { return gp.remaining @@ -120,6 +92,8 @@ func (gp *GasPool) CumulativeUsed() uint64 { // Used returns the amount of consumed gas. For Amsterdam blocks with // 2D gas accounting (EIP-8037), returns max(sum_regular, sum_state). func (gp *GasPool) Used() uint64 { + fmt.Printf("DEBUG_POOL Used: initial=%d remaining=%d cumR=%d cumS=%d cumUsed=%d\n", + gp.initial, gp.remaining, gp.cumulativeRegular, gp.cumulativeState, gp.cumulativeUsed) if gp.cumulativeRegular > 0 || gp.cumulativeState > 0 { return max(gp.cumulativeRegular, gp.cumulativeState) } diff --git a/core/state_transition.go b/core/state_transition.go index d3c3f0f886..dd1ebffdc8 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -472,7 +472,6 @@ func (st *stateTransition) execute() (*ExecutionResult, error) { if err != nil { return nil, err } - var execGasStart vm.GasCosts if rules.IsAmsterdam { // EIP-8037: total intrinsic must fit within the transaction gas limit. if msg.GasLimit < gas.Sum() { @@ -482,7 +481,6 @@ func (st *stateTransition) execute() (*ExecutionResult, error) { executionGas := msg.GasLimit - gas.Sum() regularGas := min(params.MaxTxGas-gas.RegularGas, executionGas) st.gasRemaining = vm.GasCosts{RegularGas: regularGas, StateGas: executionGas - regularGas} - execGasStart = st.gasRemaining } else { if st.gasRemaining.Underflow(gas) { return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.gasRemaining.RegularGas, gas.RegularGas) @@ -572,11 +570,6 @@ func (st *stateTransition) execute() (*ExecutionResult, error) { // gas allowance required to complete execution. peakGasUsed := st.gasUsed() - var txRegular, txState uint64 - if rules.IsAmsterdam { - txRegular, txState = st.blockGasUsed(gas, execGasStart) - } - // Compute refund counter, capped to a refund quotient. st.gasRemaining.RegularGas += st.calcRefund() if rules.IsPrague { @@ -591,50 +584,13 @@ func (st *stateTransition) execute() (*ExecutionResult, error) { if peakGasUsed < floorDataGas { peakGasUsed = floorDataGas } - if rules.IsAmsterdam && txRegular < floorDataGas { - txRegular = floorDataGas - } - } - // Compute the receipt gas used (what the user pays) for Amsterdam before - // returning gas. Per EIP-8037: - // tx_gas_used_after_refund = tx.gas - gas_left - state_gas_reservoir - state_gas_refund - // At this point, gas_left already includes the regular refund (added above). - // The state gas refund (e.g., auth to existing accounts) is also returned to the user. - var receiptGasUsed uint64 - if rules.IsAmsterdam { - receiptGasUsed = msg.GasLimit - st.gasRemaining.RegularGas - st.gasRemaining.StateGas - st.stateGasRefund - // On successful execution, refund regular gas that was consumed for - // state operations in child calls that subsequently reverted. This gas - // paid for state growth that didn't persist, so the user shouldn't pay. - // On failed execution (exceptional halt), all gas is consumed — no refund. - if vmerr == nil { - receiptGasUsed -= st.gasRemaining.RevertedStateGasSpill - } } - // Return gas to the user - if rules.IsAmsterdam { - // In Amsterdam, return regular gas + unspent state gas reservoir + state gas refund. - gasReturn := st.gasRemaining.RegularGas + st.gasRemaining.StateGas + st.stateGasRefund - if vmerr == nil { - gasReturn += st.gasRemaining.RevertedStateGasSpill - } - remaining := uint256.NewInt(gasReturn) - remaining.Mul(remaining, uint256.MustFromBig(st.msg.GasPrice)) - st.state.AddBalance(st.msg.From, remaining, tracing.BalanceIncreaseGasReturn) - if st.evm.Config.Tracer != nil && st.evm.Config.Tracer.OnGasChange != nil && gasReturn > 0 { - st.evm.Config.Tracer.OnGasChange(gasReturn, 0, tracing.GasChangeTxLeftOverReturned) - } - } else { - st.returnGas() - } + returned := st.returnGas() + fmt.Printf("DEBUG_GAS buyGas_deducted=%d returned=%d gasUsed=%d remR=%d remS=%d initR=%d initS=%d refund=%d stateGasRef=%d SGC=%d\n", + msg.GasLimit, returned, st.gasUsed(), st.gasRemaining.RegularGas, st.gasRemaining.StateGas, st.initialGas.RegularGas, st.initialGas.StateGas, st.state.GetRefund(), st.stateGasRefund, st.gasRemaining.StateGasCharged) - if rules.IsAmsterdam { - err = st.gp.ReturnGasAmsterdam(msg.GasLimit, txRegular, txState, receiptGasUsed) - } else { - err = st.gp.ReturnGas(st.gasRemaining.RegularGas, st.gasUsed()) - } - if err != nil { + if err := st.gp.ReturnGas(returned, st.gasUsed()); err != nil { return nil, err } effectiveTip := msg.GasPrice @@ -650,9 +606,6 @@ func (st *stateTransition) execute() (*ExecutionResult, error) { } else { // For Amsterdam, the fee is based on what the user pays (receipt gas used). feeGas := st.gasUsed() - if rules.IsAmsterdam { - feeGas = receiptGasUsed - } fee := new(uint256.Int).SetUint64(feeGas) fee.Mul(fee, effectiveTipU256) @@ -667,10 +620,6 @@ func (st *stateTransition) execute() (*ExecutionResult, error) { } } usedGas := st.gasUsed() - if rules.IsAmsterdam { - // Per EIP-8037, receipt gas_used = tx_gas_used_after_refund (what the user pays). - usedGas = receiptGasUsed - } return &ExecutionResult{ UsedGas: usedGas, MaxUsedGas: peakGasUsed, @@ -768,14 +717,16 @@ func (st *stateTransition) calcRefund() uint64 { // returnGas returns ETH for remaining gas, // exchanged at the original rate. -func (st *stateTransition) returnGas() { - remaining := uint256.NewInt(st.gasRemaining.RegularGas) +func (st *stateTransition) returnGas() uint64 { + gas := st.gasRemaining.RegularGas + st.gasRemaining.StateGas + remaining := uint256.NewInt(gas) remaining.Mul(remaining, uint256.MustFromBig(st.msg.GasPrice)) st.state.AddBalance(st.msg.From, remaining, tracing.BalanceIncreaseGasReturn) - if st.evm.Config.Tracer != nil && st.evm.Config.Tracer.OnGasChange != nil && st.gasRemaining.RegularGas > 0 { - st.evm.Config.Tracer.OnGasChange(st.gasRemaining.RegularGas, 0, tracing.GasChangeTxLeftOverReturned) + if st.evm.Config.Tracer != nil && st.evm.Config.Tracer.OnGasChange != nil && gas > 0 { + st.evm.Config.Tracer.OnGasChange(gas, 0, tracing.GasChangeTxLeftOverReturned) } + return gas } // gasUsed returns the amount of gas used up by the state transition. @@ -785,24 +736,6 @@ func (st *stateTransition) gasUsed() uint64 { (st.gasRemaining.RegularGas + st.gasRemaining.StateGas) } -// blockGasUsed returns the per-transaction (regular, state) gas used for -// block-level 2D accounting (EIP-8037). -func (st *stateTransition) blockGasUsed(intrinsicGas, execGasStart vm.GasCosts) (uint64, uint64) { - totalExecUsed := (execGasStart.RegularGas + execGasStart.StateGas) - - (st.gasRemaining.RegularGas + st.gasRemaining.StateGas) - execStateUsed := st.gasRemaining.TotalStateGasCharged - // Exclude state gas that was charged from regular gas but then reverted. - // This gas was consumed from the regular pool but was for state operations - // that didn't persist, so it shouldn't count in either dimension for block - // accounting (invisible to the block). This matches nethermind's approach. - execRegularUsed := totalExecUsed - execStateUsed - st.gasRemaining.RevertedStateGasSpill - st.gasRemaining.CollisionConsumedGas - - txRegular := intrinsicGas.RegularGas + execRegularUsed - txState := intrinsicGas.StateGas + execStateUsed - st.stateGasRefund - - return txRegular, txState -} - // blobGasUsed returns the amount of blob gas used by the message. func (st *stateTransition) blobGasUsed() uint64 { return uint64(len(st.msg.BlobHashes) * params.BlobTxBlobGasPerBlob) diff --git a/core/vm/contract.go b/core/vm/contract.go index b5aed03886..ab5102ed53 100644 --- a/core/vm/contract.go +++ b/core/vm/contract.go @@ -145,7 +145,16 @@ func (c *Contract) RefundGas(gas GasCosts, logger *tracing.Hooks, reason tracing if logger != nil && logger.OnGasChange != nil && reason != tracing.GasChangeIgnored { logger.OnGasChange(c.Gas.RegularGas, c.Gas.RegularGas+gas.RegularGas, reason) } - c.Gas.Add(gas) + c.Gas.RegularGas += gas.RegularGas + c.Gas.StateGas = gas.StateGas + /* + if c.Gas.StateGas < gas.StateGasCharged { + // We overcharged StateGas, during reverts we need to add back to regular gas + missing := c.Gas.StateGasCharged - c.Gas.StateGas + c.Gas.RegularGas += missing + } + */ + c.Gas.StateGasCharged += gas.StateGasCharged } // Address returns the contracts address diff --git a/core/vm/evm.go b/core/vm/evm.go index 0d4e8f3402..7df259ec09 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -257,8 +257,7 @@ func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, g return nil, gas, ErrInsufficientBalance } snapshot := evm.StateDB.Snapshot() - savedTotalStateGas := gas.TotalStateGasCharged - savedStateGas := gas.StateGas + stateGas := gas.StateGas p, isPrecompile := evm.precompile(addr) if !evm.StateDB.Exist(addr) { @@ -323,13 +322,8 @@ func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, g } gas.RegularGas = 0 } - // State changes are rolled back on any error, so state gas charges - // from the reverted execution should not count toward block accounting. - // Also restore the state gas reservoir since state creation was undone. - gas.RevertStateGas(savedTotalStateGas, savedStateGas, isRevert) - // TODO: consider clearing up unused snapshots: - //} else { - // evm.StateDB.DiscardSnapshot(snapshot) + gas.StateGasCharged = 0 + gas.StateGas = stateGas } return ret, gas, err } @@ -361,8 +355,7 @@ func (evm *EVM) CallCode(caller common.Address, addr common.Address, input []byt return nil, gas, ErrInsufficientBalance } var snapshot = evm.StateDB.Snapshot() - savedTotalStateGas := gas.TotalStateGasCharged - savedStateGas := gas.StateGas + stateGas := gas.StateGas // It is allowed to call precompiles, even via delegatecall if p, isPrecompile := evm.precompile(addr); isPrecompile { @@ -388,7 +381,8 @@ func (evm *EVM) CallCode(caller common.Address, addr common.Address, input []byt } gas.RegularGas = 0 } - gas.RevertStateGas(savedTotalStateGas, savedStateGas, isRevert) + gas.StateGasCharged = 0 + gas.StateGas = stateGas } return ret, gas, err } @@ -412,8 +406,7 @@ func (evm *EVM) DelegateCall(originCaller common.Address, caller common.Address, return nil, gas, ErrDepth } var snapshot = evm.StateDB.Snapshot() - savedTotalStateGas := gas.TotalStateGasCharged - savedStateGas := gas.StateGas + stateGas := gas.StateGas // It is allowed to call precompiles, even via delegatecall if p, isPrecompile := evm.precompile(addr); isPrecompile { @@ -440,7 +433,8 @@ func (evm *EVM) DelegateCall(originCaller common.Address, caller common.Address, } gas.RegularGas = 0 } - gas.RevertStateGas(savedTotalStateGas, savedStateGas, isRevert) + gas.StateGasCharged = 0 + gas.StateGas = stateGas } return ret, gas, err } @@ -467,8 +461,7 @@ func (evm *EVM) StaticCall(caller common.Address, addr common.Address, input []b // then certain tests start failing; stRevertTest/RevertPrecompiledTouchExactOOG.json. // We could change this, but for now it's left for legacy reasons var snapshot = evm.StateDB.Snapshot() - savedTotalStateGas := gas.TotalStateGasCharged - savedStateGas := gas.StateGas + stateGas := gas.StateGas // We do an AddBalance of zero here, just in order to trigger a touch. // This doesn't matter on Mainnet, where all empties are gone at the time of Byzantium, @@ -503,7 +496,8 @@ func (evm *EVM) StaticCall(caller common.Address, addr common.Address, input []b } gas.RegularGas = 0 } - gas.RevertStateGas(savedTotalStateGas, savedStateGas, isRevert) + gas.StateGasCharged = 0 + gas.StateGas = stateGas } return ret, gas, err } @@ -573,8 +567,7 @@ func (evm *EVM) create(caller common.Address, code []byte, gas GasCosts, value * // It might be possible the contract code is deployed to a pre-existent // account with non-zero balance. snapshot := evm.StateDB.Snapshot() - savedTotalStateGas := gas.TotalStateGasCharged - savedStateGas := gas.StateGas + stateGas := gas.StateGas if !evm.StateDB.Exist(address) { evm.StateDB.CreateAccount(address) @@ -613,26 +606,13 @@ func (evm *EVM) create(caller common.Address, code []byte, gas GasCosts, value * ret, err = evm.initNewContract(contract, address) if err != nil && (evm.chainRules.IsHomestead || err != ErrCodeStoreOutOfGas) { evm.StateDB.RevertToSnapshot(snapshot) - isRevert := err == ErrExecutionReverted - // Post-Amsterdam code validation errors (ErrMaxCodeSizeExceeded, - // ErrInvalidCode): the init code ran and code storage gas was charged. - // State gas charges must persist for block 2D gas accounting even - // though the state is reverted. Only zero regular gas as penalty. - isCodeValidation := evm.chainRules.IsAmsterdam && - (errors.Is(err, ErrMaxCodeSizeExceeded) || errors.Is(err, ErrInvalidCode)) - if !isRevert { - if isCodeValidation { - contract.Gas.RegularGas = 0 - } else { - contract.UseGas(contract.Gas, evm.Config.Tracer, tracing.GasChangeCallFailedExecution) - } - } - if !isCodeValidation { - // State changes are rolled back, so state gas charges from the - // reverted execution should not count toward block accounting. - // Also restore the state gas reservoir since state creation was undone. - contract.Gas.RevertStateGas(savedTotalStateGas, savedStateGas, isRevert) - } + + contract.UseGas(contract.Gas, evm.Config.Tracer, tracing.GasChangeCallFailedExecution) + // State changes are rolled back, so state gas charges from the + // reverted execution should not count toward block accounting. + // Also restore the state gas reservoir since state creation was undone. + contract.Gas.StateGasCharged = 0 + contract.Gas.StateGas = stateGas } return ret, address, contract.Gas, err } diff --git a/core/vm/gascosts.go b/core/vm/gascosts.go index d0e044af72..32f4455b36 100644 --- a/core/vm/gascosts.go +++ b/core/vm/gascosts.go @@ -6,25 +6,8 @@ type GasCosts struct { RegularGas uint64 StateGas uint64 - // TotalStateGasCharged tracks the cumulative state gas charged during - // execution, including gas that spilled from the reservoir to regular gas. - // This is needed for EIP-8037 block gas accounting where the state gas - // dimension counts ALL state creation charges, not just reservoir consumption. - TotalStateGasCharged uint64 - - // RevertedStateGasSpill tracks state gas that was charged from regular gas - // (spilled) during execution of a call that subsequently reverted. When a - // call fails, its state changes are undone, but the regular gas was already - // consumed. Block gas accounting must exclude this amount from the regular - // gas dimension since it was for state operations that didn't persist. - // This gas is refunded to the user (invisible to both block and receipt). - RevertedStateGasSpill uint64 - - // CollisionConsumedGas tracks regular gas consumed on CREATE/CREATE2 address - // collision. On collision, the child's regular gas is consumed (user pays) - // but must be excluded from block regular gas accounting to preserve 2D - // block gas semantics. Unlike RevertedStateGasSpill, this is NOT refunded. - CollisionConsumedGas uint64 + // StateGasCharged tracks the cumulative state gas charged during execution. + StateGasCharged uint64 } func (g GasCosts) Max() uint64 { @@ -55,7 +38,7 @@ func (g GasCosts) Underflow(b GasCosts) bool { // Sub doesn't check for underflows func (g *GasCosts) Sub(b GasCosts) { g.RegularGas -= b.RegularGas - g.TotalStateGasCharged += b.StateGas + g.StateGasCharged += b.StateGas if b.StateGas > g.StateGas { diff := b.StateGas - g.StateGas g.StateGas = 0 @@ -69,30 +52,7 @@ func (g *GasCosts) Sub(b GasCosts) { func (g *GasCosts) Add(b GasCosts) { g.RegularGas += b.RegularGas g.StateGas += b.StateGas - g.TotalStateGasCharged += b.TotalStateGasCharged - g.RevertedStateGasSpill += b.RevertedStateGasSpill - g.CollisionConsumedGas += b.CollisionConsumedGas -} - -// RevertStateGas handles state gas accounting when a call reverts (EIP-8037). -// It computes how much state gas was charged from regular gas (spill) during the -// call, and either returns it for REVERT errors or tracks it for non-REVERT errors. -func (g *GasCosts) RevertStateGas(savedTotalStateGas, savedStateGas uint64, isRevert bool) { - chargedDuringCall := g.TotalStateGasCharged - savedTotalStateGas - fromReservoir := savedStateGas - g.StateGas - spilledFromRegular := chargedDuringCall - fromReservoir - - if isRevert { - // REVERT: return the spilled state gas to regular gas since the caller - // keeps unused gas and state operations were undone. - g.RegularGas += spilledFromRegular - } else { - // Non-REVERT: regular gas is zeroed, but block accounting must exclude - // the spill from the regular gas dimension. - g.RevertedStateGasSpill += spilledFromRegular - } - g.TotalStateGasCharged = savedTotalStateGas - g.StateGas = savedStateGas + g.StateGasCharged += b.StateGasCharged } func (g GasCosts) String() string { diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 95f851c646..2b3c8e982a 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -17,7 +17,6 @@ package vm import ( - "errors" "math" "github.com/ethereum/go-ethereum/common" @@ -674,13 +673,9 @@ func opCreate(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { // reuse size int for stackvalue stackvalue := size - // Pass caller's state gas (reservoir) to child and zero it out to avoid - // double-counting when the unused portion is refunded on return. - stateGas := scope.Contract.Gas.StateGas - scope.Contract.Gas.StateGas = 0 scope.Contract.UseGas(GasCosts{RegularGas: gas.RegularGas}, evm.Config.Tracer, tracing.GasChangeCallContractCreation) - res, addr, returnGas, suberr := evm.Create(scope.Contract.Address(), input, GasCosts{RegularGas: gas.RegularGas, StateGas: stateGas}, &value) + res, addr, returnGas, suberr := evm.Create(scope.Contract.Address(), input, GasCosts{RegularGas: gas.RegularGas, StateGas: scope.Contract.Gas.StateGas}, &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 @@ -694,22 +689,6 @@ func opCreate(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { } scope.Stack.push(&stackvalue) - // For inner CREATEs that fail code validation (EIP-7954 + EIP-8037): - // the state was reverted so no state growth occurred. Don't propagate - // the code storage state gas to the parent's block gas accounting. - // Restore the parent's state gas reservoir since it was not consumed. - if evm.chainRules.IsAmsterdam && (errors.Is(suberr, ErrMaxCodeSizeExceeded) || errors.Is(suberr, ErrInvalidCode)) { - returnGas.TotalStateGasCharged = 0 - returnGas.RevertedStateGasSpill = 0 - returnGas.StateGas = stateGas - } - // On address collision, child's regular gas is consumed (not returned). - // Track as CollisionConsumedGas so block 2D accounting is unaffected - // while the user still pays for the consumed gas (not refunded). - if evm.chainRules.IsAmsterdam && errors.Is(suberr, ErrContractAddressCollision) { - returnGas.CollisionConsumedGas += returnGas.RegularGas - returnGas.RegularGas = 0 - } scope.Contract.RefundGas(returnGas, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) if suberr == ErrExecutionReverted { @@ -744,14 +723,10 @@ func opCreate2(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { } } - // Pass caller's state gas (reservoir) to child and zero it out to avoid - // double-counting when the unused portion is refunded on return. - stateGas := scope.Contract.Gas.StateGas - scope.Contract.Gas.StateGas = 0 scope.Contract.UseGas(GasCosts{RegularGas: gas.RegularGas}, evm.Config.Tracer, tracing.GasChangeCallContractCreation2) // reuse size int for stackvalue stackvalue := size - res, addr, returnGas, suberr := evm.Create2(scope.Contract.Address(), input, GasCosts{RegularGas: gas.RegularGas, StateGas: stateGas}, + res, addr, returnGas, suberr := evm.Create2(scope.Contract.Address(), input, GasCosts{RegularGas: gas.RegularGas, StateGas: scope.Contract.Gas.StateGas}, &endowment, &salt) // Push item on the stack based on the returned error. if suberr != nil { @@ -761,22 +736,6 @@ func opCreate2(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { } scope.Stack.push(&stackvalue) - // For inner CREATEs that fail code validation (EIP-7954 + EIP-8037): - // the state was reverted so no state growth occurred. Don't propagate - // the code storage state gas to the parent's block gas accounting. - // Restore the parent's state gas reservoir since it was not consumed. - if evm.chainRules.IsAmsterdam && (errors.Is(suberr, ErrMaxCodeSizeExceeded) || errors.Is(suberr, ErrInvalidCode)) { - returnGas.TotalStateGasCharged = 0 - returnGas.RevertedStateGasSpill = 0 - returnGas.StateGas = stateGas - } - // On address collision, child's regular gas is consumed (not returned). - // Track as CollisionConsumedGas so block 2D accounting is unaffected - // while the user still pays for the consumed gas (not refunded). - if evm.chainRules.IsAmsterdam && errors.Is(suberr, ErrContractAddressCollision) { - returnGas.CollisionConsumedGas += returnGas.RegularGas - returnGas.RegularGas = 0 - } scope.Contract.RefundGas(returnGas, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) if suberr == ErrExecutionReverted { @@ -805,11 +764,7 @@ func opCall(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { if !value.IsZero() { gas += params.CallStipend } - // Pass caller's state gas (reservoir) to callee and zero it out to avoid - // double-counting when the unused portion is refunded on return. - stateGas := scope.Contract.Gas.StateGas - scope.Contract.Gas.StateGas = 0 - ret, returnGas, err := evm.Call(scope.Contract.Address(), toAddr, args, GasCosts{RegularGas: gas, StateGas: stateGas}, &value) + ret, returnGas, err := evm.Call(scope.Contract.Address(), toAddr, args, GasCosts{RegularGas: gas, StateGas: scope.Contract.Gas.StateGas}, &value) if err != nil { temp.Clear() @@ -843,9 +798,7 @@ func opCallCode(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { gas += params.CallStipend } - stateGas := scope.Contract.Gas.StateGas - scope.Contract.Gas.StateGas = 0 - ret, returnGas, err := evm.CallCode(scope.Contract.Address(), toAddr, args, GasCosts{RegularGas: gas, StateGas: stateGas}, &value) + ret, returnGas, err := evm.CallCode(scope.Contract.Address(), toAddr, args, GasCosts{RegularGas: gas, StateGas: scope.Contract.Gas.StateGas}, &value) if err != nil { temp.Clear() } else { @@ -875,7 +828,6 @@ func opDelegateCall(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { args := scope.Memory.GetPtr(inOffset.Uint64(), inSize.Uint64()) stateGas := scope.Contract.Gas.StateGas - scope.Contract.Gas.StateGas = 0 ret, returnGas, err := evm.DelegateCall(scope.Contract.Caller(), scope.Contract.Address(), toAddr, args, GasCosts{RegularGas: gas, StateGas: stateGas}, scope.Contract.value) if err != nil { temp.Clear() @@ -906,7 +858,6 @@ func opStaticCall(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { args := scope.Memory.GetPtr(inOffset.Uint64(), inSize.Uint64()) stateGas := scope.Contract.Gas.StateGas - scope.Contract.Gas.StateGas = 0 ret, returnGas, err := evm.StaticCall(scope.Contract.Address(), toAddr, args, GasCosts{RegularGas: gas, StateGas: stateGas}) if err != nil { temp.Clear()