mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-05-17 13:36:37 +00:00
core/vm: fix two bugs
Fixes the collision bugs and create gas ordering
This commit is contained in:
parent
407cf11930
commit
cd2095fb4a
3 changed files with 37 additions and 45 deletions
|
|
@ -539,9 +539,7 @@ func (evm *EVM) create(caller common.Address, code []byte, gas GasBudget, value
|
||||||
evm.Config.Tracer.OnGasChange(gas.RegularGas, 0, tracing.GasChangeCallFailedExecution)
|
evm.Config.Tracer.OnGasChange(gas.RegularGas, 0, tracing.GasChangeCallFailedExecution)
|
||||||
}
|
}
|
||||||
// Burn all gas on collision
|
// Burn all gas on collision
|
||||||
collisionUsed := GasUsed{RegularGas: gas.RegularGas}
|
return nil, common.Address{}, GasBudget{}, GasUsed{}, ErrContractAddressCollision
|
||||||
gas.RegularGas = 0
|
|
||||||
return nil, common.Address{}, gas, collisionUsed, ErrContractAddressCollision
|
|
||||||
}
|
}
|
||||||
// Create a new account on the state only if the object was not present.
|
// 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
|
// It might be possible the contract code is deployed to a pre-existent
|
||||||
|
|
|
||||||
|
|
@ -291,10 +291,19 @@ var (
|
||||||
gasMLoad = pureMemoryGascost
|
gasMLoad = pureMemoryGascost
|
||||||
gasMStore8 = pureMemoryGascost
|
gasMStore8 = pureMemoryGascost
|
||||||
gasMStore = pureMemoryGascost
|
gasMStore = pureMemoryGascost
|
||||||
gasCreate = pureMemoryGascost
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func gasCreate(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) {
|
||||||
|
if evm.readOnly {
|
||||||
|
return GasCosts{}, ErrWriteProtection
|
||||||
|
}
|
||||||
|
return pureMemoryGascost(evm, contract, stack, mem, memorySize)
|
||||||
|
}
|
||||||
|
|
||||||
func gasCreate2(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) {
|
func gasCreate2(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) {
|
||||||
|
if evm.readOnly {
|
||||||
|
return GasCosts{}, ErrWriteProtection
|
||||||
|
}
|
||||||
gas, err := memoryGasCost(mem, memorySize)
|
gas, err := memoryGasCost(mem, memorySize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return GasCosts{}, err
|
return GasCosts{}, err
|
||||||
|
|
@ -313,6 +322,9 @@ func gasCreate2(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memoryS
|
||||||
}
|
}
|
||||||
|
|
||||||
func gasCreateEip3860(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) {
|
func gasCreateEip3860(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) {
|
||||||
|
if evm.readOnly {
|
||||||
|
return GasCosts{}, ErrWriteProtection
|
||||||
|
}
|
||||||
gas, err := memoryGasCost(mem, memorySize)
|
gas, err := memoryGasCost(mem, memorySize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return GasCosts{}, err
|
return GasCosts{}, err
|
||||||
|
|
@ -333,6 +345,9 @@ func gasCreateEip3860(evm *EVM, contract *Contract, stack *Stack, mem *Memory, m
|
||||||
}
|
}
|
||||||
|
|
||||||
func gasCreate2Eip3860(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) {
|
func gasCreate2Eip3860(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) {
|
||||||
|
if evm.readOnly {
|
||||||
|
return GasCosts{}, ErrWriteProtection
|
||||||
|
}
|
||||||
gas, err := memoryGasCost(mem, memorySize)
|
gas, err := memoryGasCost(mem, memorySize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return GasCosts{}, err
|
return GasCosts{}, err
|
||||||
|
|
@ -532,6 +547,9 @@ func gasSelfdestruct(evm *EVM, contract *Contract, stack *Stack, mem *Memory, me
|
||||||
}
|
}
|
||||||
|
|
||||||
func gasCreateEip8037(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) {
|
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)
|
gas, err := memoryGasCost(mem, memorySize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return GasCosts{}, err
|
return GasCosts{}, err
|
||||||
|
|
@ -540,19 +558,20 @@ func gasCreateEip8037(evm *EVM, contract *Contract, stack *Stack, mem *Memory, m
|
||||||
if overflow {
|
if overflow {
|
||||||
return GasCosts{}, ErrGasUintOverflow
|
return GasCosts{}, ErrGasUintOverflow
|
||||||
}
|
}
|
||||||
// Cap word gas at MaxInitCodeSizeAmsterdam to avoid overflow.
|
if err := CheckMaxInitCodeSize(&evm.chainRules, size); err != nil {
|
||||||
// The actual init code size check happens in create() for graceful failure.
|
return GasCosts{}, err
|
||||||
wordSize := min(size, params.MaxInitCodeSizeAmsterdam)
|
}
|
||||||
words := (wordSize + 31) / 32
|
// Since size <= MaxInitCodeSizeAmsterdam, these multiplications cannot overflow
|
||||||
// Account creation is a fixed state gas cost, not proportional to init code size.
|
words := (size + 31) / 32
|
||||||
// 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
|
wordGas := params.InitCodeWordGas * words
|
||||||
|
stateGas := params.AccountCreationSize * evm.Context.CostPerGasByte
|
||||||
return GasCosts{RegularGas: gas + wordGas, StateGas: stateGas}, nil
|
return GasCosts{RegularGas: gas + wordGas, StateGas: stateGas}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func gasCreate2Eip8037(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) {
|
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)
|
gas, err := memoryGasCost(mem, memorySize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return GasCosts{}, err
|
return GasCosts{}, err
|
||||||
|
|
@ -561,15 +580,14 @@ func gasCreate2Eip8037(evm *EVM, contract *Contract, stack *Stack, mem *Memory,
|
||||||
if overflow {
|
if overflow {
|
||||||
return GasCosts{}, ErrGasUintOverflow
|
return GasCosts{}, ErrGasUintOverflow
|
||||||
}
|
}
|
||||||
// Cap word gas at MaxInitCodeSizeAmsterdam to avoid overflow.
|
if err := CheckMaxInitCodeSize(&evm.chainRules, size); err != nil {
|
||||||
// The actual init code size check happens in create() for graceful failure.
|
return GasCosts{}, err
|
||||||
wordSize := min(size, params.MaxInitCodeSizeAmsterdam)
|
}
|
||||||
words := (wordSize + 31) / 32
|
// Since size <= MaxInitCodeSizeAmsterdam, these multiplications cannot overflow
|
||||||
// Account creation is a fixed state gas cost, not proportional to init code size.
|
words := (size + 31) / 32
|
||||||
// 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
|
||||||
|
stateGas := params.AccountCreationSize * evm.Context.CostPerGasByte
|
||||||
return GasCosts{RegularGas: gas + wordGas, StateGas: stateGas}, nil
|
return GasCosts{RegularGas: gas + wordGas, StateGas: stateGas}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -648,28 +648,16 @@ func opSwap16(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func opCreate(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
func opCreate(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
if evm.readOnly {
|
|
||||||
return nil, ErrWriteProtection
|
|
||||||
}
|
|
||||||
var (
|
var (
|
||||||
value = scope.Stack.pop()
|
value = scope.Stack.pop()
|
||||||
offset, size = scope.Stack.pop(), scope.Stack.pop()
|
offset, size = scope.Stack.pop(), scope.Stack.pop()
|
||||||
input = scope.Memory.GetCopy(offset.Uint64(), size.Uint64())
|
input = scope.Memory.GetCopy(offset.Uint64(), size.Uint64())
|
||||||
gas = scope.Contract.Gas
|
|
||||||
)
|
)
|
||||||
|
gas := scope.Contract.Gas
|
||||||
if evm.chainRules.IsEIP150 {
|
if evm.chainRules.IsEIP150 {
|
||||||
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
|
||||||
|
|
||||||
|
|
@ -701,29 +689,17 @@ func opCreate(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func opCreate2(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
func opCreate2(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
if evm.readOnly {
|
|
||||||
return nil, ErrWriteProtection
|
|
||||||
}
|
|
||||||
var (
|
var (
|
||||||
endowment = scope.Stack.pop()
|
endowment = scope.Stack.pop()
|
||||||
offset, size = scope.Stack.pop(), scope.Stack.pop()
|
offset, size = scope.Stack.pop(), scope.Stack.pop()
|
||||||
salt = scope.Stack.pop()
|
salt = scope.Stack.pop()
|
||||||
input = scope.Memory.GetCopy(offset.Uint64(), size.Uint64())
|
input = scope.Memory.GetCopy(offset.Uint64(), size.Uint64())
|
||||||
gas = scope.Contract.Gas
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Apply EIP150
|
// Apply EIP150
|
||||||
|
gas := scope.Contract.Gas
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
regularGasUsed := scope.Contract.GasUsed.RegularGas
|
regularGasUsed := scope.Contract.GasUsed.RegularGas
|
||||||
scope.Contract.UseGas(GasCosts{RegularGas: gas.RegularGas}, evm.Config.Tracer, tracing.GasChangeCallContractCreation2)
|
scope.Contract.UseGas(GasCosts{RegularGas: gas.RegularGas}, evm.Config.Tracer, tracing.GasChangeCallContractCreation2)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue