mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-03-07 03:45:02 +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
|
||||
newUsed := max(gp.cumulativeRegular, gp.cumulativeState)
|
||||
blockGasIncrement := newUsed - oldUsed
|
||||
returned := txGasLimit - blockGasIncrement
|
||||
if gp.remaining > math.MaxUint64-returned {
|
||||
return fmt.Errorf("%w: remaining: %d, returned: %d", ErrGasLimitOverflow, gp.remaining, returned)
|
||||
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
|
||||
}
|
||||
gp.remaining += returned
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -536,7 +536,6 @@ func (evm *EVM) create(caller common.Address, code []byte, gas GasCosts, value *
|
|||
if err != nil {
|
||||
return nil, common.Address{}, gas, err
|
||||
}
|
||||
|
||||
// Charge the contract creation init gas in verkle mode
|
||||
if evm.chainRules.IsEIP4762 {
|
||||
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
|
||||
// though the state is reverted. Only zero regular gas as penalty.
|
||||
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 isCodeValidation {
|
||||
contract.Gas.RegularGas = 0
|
||||
|
|
@ -646,8 +646,13 @@ func (evm *EVM) initNewContract(contract *Contract, address common.Address) ([]b
|
|||
return ret, err
|
||||
}
|
||||
|
||||
// Charge code storage gas BEFORE validation checks so that state gas is
|
||||
// properly accounted for in block gas even if the code is invalid (EIP-7954).
|
||||
// Check code validity once upfront.
|
||||
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 {
|
||||
createDataGas := GasCosts{RegularGas: uint64(len(ret)) * params.CreateDataGas}
|
||||
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 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
|
||||
}
|
||||
} 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 err := CheckMaxCodeSize(&evm.chainRules, uint64(len(ret))); err != nil {
|
||||
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 codeErr != nil {
|
||||
return ret, codeErr
|
||||
}
|
||||
|
||||
if len(ret) > 0 {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ package vm
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/math"
|
||||
|
|
@ -596,12 +595,13 @@ func gasCreateEip8037(evm *EVM, contract *Contract, stack *Stack, mem *Memory, m
|
|||
if overflow {
|
||||
return GasCosts{}, ErrGasUintOverflow
|
||||
}
|
||||
if size > params.MaxInitCodeSize {
|
||||
return GasCosts{}, fmt.Errorf("%w: size %d", ErrMaxInitCodeSizeExceeded, size)
|
||||
}
|
||||
// Since size <= params.MaxInitCodeSize, these multiplication cannot overflow
|
||||
words := (size + 31) / 32
|
||||
stateGas := params.AccountCreationSize * evm.Context.CostPerGasByte * words
|
||||
// Cap word gas at MaxInitCodeSizeAmsterdam to avoid overflow.
|
||||
// The actual init code size check happens in create() for graceful failure.
|
||||
wordSize := min(size, params.MaxInitCodeSizeAmsterdam)
|
||||
words := (wordSize + 31) / 32
|
||||
// Account creation is a fixed state gas cost, not proportional to init code size.
|
||||
// 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.
|
||||
wordGas := params.InitCodeWordGas * words
|
||||
return GasCosts{RegularGas: gas + wordGas, StateGas: stateGas}, nil
|
||||
|
|
@ -616,12 +616,13 @@ func gasCreate2Eip8037(evm *EVM, contract *Contract, stack *Stack, mem *Memory,
|
|||
if overflow {
|
||||
return GasCosts{}, ErrGasUintOverflow
|
||||
}
|
||||
if size > params.MaxInitCodeSize {
|
||||
return GasCosts{}, fmt.Errorf("%w: size %d", ErrMaxInitCodeSizeExceeded, size)
|
||||
}
|
||||
// Since size <= params.MaxInitCodeSize, these multiplication cannot overflow
|
||||
words := (size + 31) / 32
|
||||
stateGas := params.AccountCreationSize * evm.Context.CostPerGasByte * words
|
||||
// Cap word gas at MaxInitCodeSizeAmsterdam to avoid overflow.
|
||||
// The actual init code size check happens in create() for graceful failure.
|
||||
wordSize := min(size, params.MaxInitCodeSizeAmsterdam)
|
||||
words := (wordSize + 31) / 32
|
||||
// Account creation is a fixed state gas cost, not proportional to init code size.
|
||||
// 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).
|
||||
wordGas := (params.InitCodeWordGas + params.Keccak256WordGas) * words
|
||||
return GasCosts{RegularGas: gas + wordGas, StateGas: stateGas}, nil
|
||||
|
|
|
|||
|
|
@ -28,13 +28,17 @@ func (g GasCosts) Sum() uint64 {
|
|||
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 {
|
||||
if b.RegularGas > g.RegularGas {
|
||||
return true
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
package vm
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math"
|
||||
|
||||
"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
|
||||
}
|
||||
|
||||
// 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
|
||||
stackvalue := size
|
||||
|
||||
|
|
@ -684,6 +694,15 @@ 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
|
||||
}
|
||||
scope.Contract.RefundGas(returnGas, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
|
||||
|
||||
if suberr == ErrExecutionReverted {
|
||||
|
|
@ -708,6 +727,16 @@ func opCreate2(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
|||
|
||||
// Apply EIP150
|
||||
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
|
||||
// double-counting when the unused portion is refunded on return.
|
||||
stateGas := scope.Contract.Gas.StateGas
|
||||
|
|
@ -724,6 +753,16 @@ func opCreate2(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
|||
stackvalue.SetBytes(addr.Bytes())
|
||||
}
|
||||
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)
|
||||
|
||||
if suberr == ErrExecutionReverted {
|
||||
|
|
|
|||
Loading…
Reference in a new issue