mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-05-20 23:09:27 +00:00
core: fixed issues from devnet
This commit is contained in:
parent
e483205878
commit
0140060d96
5 changed files with 91 additions and 31 deletions
|
|
@ -87,11 +87,21 @@ func (gp *GasPool) ReturnGasAmsterdam(txGasLimit, txRegular, txState, receiptGas
|
||||||
gp.cumulativeUsed += receiptGasUsed
|
gp.cumulativeUsed += receiptGasUsed
|
||||||
newUsed := max(gp.cumulativeRegular, gp.cumulativeState)
|
newUsed := max(gp.cumulativeRegular, gp.cumulativeState)
|
||||||
blockGasIncrement := newUsed - oldUsed
|
blockGasIncrement := newUsed - oldUsed
|
||||||
returned := txGasLimit - blockGasIncrement
|
if blockGasIncrement > txGasLimit {
|
||||||
if gp.remaining > math.MaxUint64-returned {
|
// State gas via reservoir model can push the dimensional cost above
|
||||||
return fmt.Errorf("%w: remaining: %d, returned: %d", ErrGasLimitOverflow, gp.remaining, returned)
|
// 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
|
||||||
}
|
}
|
||||||
gp.remaining += returned
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -536,7 +536,6 @@ func (evm *EVM) create(caller common.Address, code []byte, gas GasCosts, value *
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, common.Address{}, gas, err
|
return nil, common.Address{}, gas, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Charge the contract creation init gas in verkle mode
|
// Charge the contract creation init gas in verkle mode
|
||||||
if evm.chainRules.IsEIP4762 {
|
if evm.chainRules.IsEIP4762 {
|
||||||
statelessGas := evm.AccessEvents.ContractCreatePreCheckGas(address, gas.RegularGas)
|
statelessGas := evm.AccessEvents.ContractCreatePreCheckGas(address, gas.RegularGas)
|
||||||
|
|
@ -620,7 +619,8 @@ func (evm *EVM) create(caller common.Address, code []byte, gas GasCosts, value *
|
||||||
// State gas charges must persist for block 2D gas accounting even
|
// State gas charges must persist for block 2D gas accounting even
|
||||||
// though the state is reverted. Only zero regular gas as penalty.
|
// though the state is reverted. Only zero regular gas as penalty.
|
||||||
isCodeValidation := evm.chainRules.IsAmsterdam &&
|
isCodeValidation := evm.chainRules.IsAmsterdam &&
|
||||||
(errors.Is(err, ErrMaxCodeSizeExceeded) || errors.Is(err, ErrInvalidCode))
|
(errors.Is(err, ErrMaxCodeSizeExceeded) || errors.Is(err, ErrInvalidCode) ||
|
||||||
|
(err == ErrCodeStoreOutOfGas && contract.Gas.TotalStateGasCharged > savedTotalStateGas))
|
||||||
if !isRevert {
|
if !isRevert {
|
||||||
if isCodeValidation {
|
if isCodeValidation {
|
||||||
contract.Gas.RegularGas = 0
|
contract.Gas.RegularGas = 0
|
||||||
|
|
@ -646,8 +646,13 @@ func (evm *EVM) initNewContract(contract *Contract, address common.Address) ([]b
|
||||||
return ret, err
|
return ret, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Charge code storage gas BEFORE validation checks so that state gas is
|
// Check code validity once upfront.
|
||||||
// properly accounted for in block gas even if the code is invalid (EIP-7954).
|
codeErr := CheckMaxCodeSize(&evm.chainRules, uint64(len(ret)))
|
||||||
|
if codeErr == nil && len(ret) >= 1 && ret[0] == 0xEF && evm.chainRules.IsLondon {
|
||||||
|
codeErr = ErrInvalidCode
|
||||||
|
}
|
||||||
|
|
||||||
|
// Charge code storage gas.
|
||||||
if !evm.chainRules.IsEIP4762 {
|
if !evm.chainRules.IsEIP4762 {
|
||||||
createDataGas := GasCosts{RegularGas: uint64(len(ret)) * params.CreateDataGas}
|
createDataGas := GasCosts{RegularGas: uint64(len(ret)) * params.CreateDataGas}
|
||||||
if evm.chainRules.IsAmsterdam {
|
if evm.chainRules.IsAmsterdam {
|
||||||
|
|
@ -658,6 +663,13 @@ func (evm *EVM) initNewContract(contract *Contract, address common.Address) ([]b
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !contract.UseGas(createDataGas, evm.Config.Tracer, tracing.GasChangeCallCodeStorage) {
|
if !contract.UseGas(createDataGas, evm.Config.Tracer, tracing.GasChangeCallCodeStorage) {
|
||||||
|
if evm.chainRules.IsAmsterdam && codeErr == nil {
|
||||||
|
// Valid code that merely ran out of gas: track state gas for
|
||||||
|
// block accounting (EIP-8037).
|
||||||
|
contract.Gas.TotalStateGasCharged += createDataGas.StateGas
|
||||||
|
contract.Gas.RegularGas = 0
|
||||||
|
contract.Gas.StateGas = 0
|
||||||
|
}
|
||||||
return ret, ErrCodeStoreOutOfGas
|
return ret, ErrCodeStoreOutOfGas
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -668,14 +680,8 @@ func (evm *EVM) initNewContract(contract *Contract, address common.Address) ([]b
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check whether the max code size has been exceeded, assign err if the case.
|
if codeErr != nil {
|
||||||
if err := CheckMaxCodeSize(&evm.chainRules, uint64(len(ret))); err != nil {
|
return ret, codeErr
|
||||||
return ret, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reject code starting with 0xEF if EIP-3541 is enabled.
|
|
||||||
if len(ret) >= 1 && ret[0] == 0xEF && evm.chainRules.IsLondon {
|
|
||||||
return ret, ErrInvalidCode
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(ret) > 0 {
|
if len(ret) > 0 {
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@ package vm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/math"
|
"github.com/ethereum/go-ethereum/common/math"
|
||||||
|
|
@ -596,12 +595,13 @@ func gasCreateEip8037(evm *EVM, contract *Contract, stack *Stack, mem *Memory, m
|
||||||
if overflow {
|
if overflow {
|
||||||
return GasCosts{}, ErrGasUintOverflow
|
return GasCosts{}, ErrGasUintOverflow
|
||||||
}
|
}
|
||||||
if size > params.MaxInitCodeSize {
|
// Cap word gas at MaxInitCodeSizeAmsterdam to avoid overflow.
|
||||||
return GasCosts{}, fmt.Errorf("%w: size %d", ErrMaxInitCodeSizeExceeded, size)
|
// The actual init code size check happens in create() for graceful failure.
|
||||||
}
|
wordSize := min(size, params.MaxInitCodeSizeAmsterdam)
|
||||||
// Since size <= params.MaxInitCodeSize, these multiplication cannot overflow
|
words := (wordSize + 31) / 32
|
||||||
words := (size + 31) / 32
|
// Account creation is a fixed state gas cost, not proportional to init code size.
|
||||||
stateGas := params.AccountCreationSize * evm.Context.CostPerGasByte * words
|
// Code storage state gas is charged separately in initNewContract.
|
||||||
|
stateGas := params.AccountCreationSize * evm.Context.CostPerGasByte
|
||||||
// CREATE uses InitCodeWordGas (EIP-3860); Keccak256WordGas is only for CREATE2.
|
// CREATE uses InitCodeWordGas (EIP-3860); Keccak256WordGas is only for CREATE2.
|
||||||
wordGas := params.InitCodeWordGas * words
|
wordGas := params.InitCodeWordGas * words
|
||||||
return GasCosts{RegularGas: gas + wordGas, StateGas: stateGas}, nil
|
return GasCosts{RegularGas: gas + wordGas, StateGas: stateGas}, nil
|
||||||
|
|
@ -616,12 +616,13 @@ func gasCreate2Eip8037(evm *EVM, contract *Contract, stack *Stack, mem *Memory,
|
||||||
if overflow {
|
if overflow {
|
||||||
return GasCosts{}, ErrGasUintOverflow
|
return GasCosts{}, ErrGasUintOverflow
|
||||||
}
|
}
|
||||||
if size > params.MaxInitCodeSize {
|
// Cap word gas at MaxInitCodeSizeAmsterdam to avoid overflow.
|
||||||
return GasCosts{}, fmt.Errorf("%w: size %d", ErrMaxInitCodeSizeExceeded, size)
|
// The actual init code size check happens in create() for graceful failure.
|
||||||
}
|
wordSize := min(size, params.MaxInitCodeSizeAmsterdam)
|
||||||
// Since size <= params.MaxInitCodeSize, these multiplication cannot overflow
|
words := (wordSize + 31) / 32
|
||||||
words := (size + 31) / 32
|
// Account creation is a fixed state gas cost, not proportional to init code size.
|
||||||
stateGas := params.AccountCreationSize * evm.Context.CostPerGasByte * words
|
// Code storage state gas is charged separately in initNewContract.
|
||||||
|
stateGas := params.AccountCreationSize * evm.Context.CostPerGasByte
|
||||||
// CREATE2 charges both InitCodeWordGas (EIP-3860) and Keccak256WordGas (for address hashing).
|
// CREATE2 charges both InitCodeWordGas (EIP-3860) and Keccak256WordGas (for address hashing).
|
||||||
wordGas := (params.InitCodeWordGas + params.Keccak256WordGas) * words
|
wordGas := (params.InitCodeWordGas + params.Keccak256WordGas) * words
|
||||||
return GasCosts{RegularGas: gas + wordGas, StateGas: stateGas}, nil
|
return GasCosts{RegularGas: gas + wordGas, StateGas: stateGas}, nil
|
||||||
|
|
|
||||||
|
|
@ -28,13 +28,17 @@ func (g GasCosts) Sum() uint64 {
|
||||||
return g.RegularGas + g.StateGas
|
return g.RegularGas + g.StateGas
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sub returns true if the operation would underflow
|
// Underflow returns true if the operation would underflow.
|
||||||
|
// When state gas exceeds the reservoir, the excess spills to regular gas.
|
||||||
|
// The check accounts for regular gas already consumed by b.RegularGas.
|
||||||
func (g GasCosts) Underflow(b GasCosts) bool {
|
func (g GasCosts) Underflow(b GasCosts) bool {
|
||||||
if b.RegularGas > g.RegularGas {
|
if b.RegularGas > g.RegularGas {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if b.StateGas > g.StateGas {
|
if b.StateGas > g.StateGas {
|
||||||
if b.StateGas > g.RegularGas {
|
spillover := b.StateGas - g.StateGas
|
||||||
|
remainingRegular := g.RegularGas - b.RegularGas
|
||||||
|
if spillover > remainingRegular {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
package vm
|
package vm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
|
@ -661,6 +662,15 @@ func opCreate(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
gas.RegularGas -= gas.RegularGas / 64
|
gas.RegularGas -= gas.RegularGas / 64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EIP-7954: check init code size after gas is charged (by the gas function)
|
||||||
|
// but before execution. This aborts the caller's execution, ensuring all
|
||||||
|
// regular gas is consumed while the state gas spill is tracked.
|
||||||
|
if evm.chainRules.IsAmsterdam {
|
||||||
|
if err := CheckMaxInitCodeSize(&evm.chainRules, uint64(len(input))); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// reuse size int for stackvalue
|
// reuse size int for stackvalue
|
||||||
stackvalue := size
|
stackvalue := size
|
||||||
|
|
||||||
|
|
@ -684,6 +694,15 @@ func opCreate(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
}
|
}
|
||||||
scope.Stack.push(&stackvalue)
|
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
|
||||||
|
}
|
||||||
scope.Contract.RefundGas(returnGas, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
|
scope.Contract.RefundGas(returnGas, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
|
||||||
|
|
||||||
if suberr == ErrExecutionReverted {
|
if suberr == ErrExecutionReverted {
|
||||||
|
|
@ -708,6 +727,16 @@ func opCreate2(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
|
|
||||||
// Apply EIP150
|
// Apply EIP150
|
||||||
gas.RegularGas -= gas.RegularGas / 64
|
gas.RegularGas -= gas.RegularGas / 64
|
||||||
|
|
||||||
|
// EIP-7954: check init code size after gas is charged (by the gas function)
|
||||||
|
// but before execution. This aborts the caller's execution, ensuring all
|
||||||
|
// regular gas is consumed while the state gas spill is tracked.
|
||||||
|
if evm.chainRules.IsAmsterdam {
|
||||||
|
if err := CheckMaxInitCodeSize(&evm.chainRules, uint64(len(input))); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Pass caller's state gas (reservoir) to child and zero it out to avoid
|
// Pass caller's state gas (reservoir) to child and zero it out to avoid
|
||||||
// double-counting when the unused portion is refunded on return.
|
// double-counting when the unused portion is refunded on return.
|
||||||
stateGas := scope.Contract.Gas.StateGas
|
stateGas := scope.Contract.Gas.StateGas
|
||||||
|
|
@ -724,6 +753,16 @@ func opCreate2(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
stackvalue.SetBytes(addr.Bytes())
|
stackvalue.SetBytes(addr.Bytes())
|
||||||
}
|
}
|
||||||
scope.Stack.push(&stackvalue)
|
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
|
||||||
|
}
|
||||||
scope.Contract.RefundGas(returnGas, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
|
scope.Contract.RefundGas(returnGas, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
|
||||||
|
|
||||||
if suberr == ErrExecutionReverted {
|
if suberr == ErrExecutionReverted {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue