From 68b0c3ef83b0ac03d004f0d333ee4774b77e1232 Mon Sep 17 00:00:00 2001 From: Delweng Date: Wed, 25 Sep 2024 19:44:14 +0800 Subject: [PATCH] feat(core/vm): better oog error with backport ethereum/go-ethereum#29354 (#12066) align with go-ethereum of detailed oog reason, ref: https://github.com/ethereum/go-ethereum/blob/b018da9d02513ab13de50d63688c465798bd0e14/core/vm/interpreter.go#L273-L275 ```go dynamicCost, err = operation.dynamicGas(in.evm, contract, stack, mem, memorySize) cost += dynamicCost // for tracing if err != nil { return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err) } if !contract.UseGas(dynamicCost, in.evm.Config.Tracer, tracing.GasChangeIgnored) { return nil, ErrOutOfGas } ``` --------- Signed-off-by: jsvisa --- core/vm/errors.go | 1 + core/vm/gas_table.go | 23 +++++++++++++++-------- core/vm/interpreter.go | 6 +++++- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/core/vm/errors.go b/core/vm/errors.go index 1706e611447..ce8ff51f1eb 100644 --- a/core/vm/errors.go +++ b/core/vm/errors.go @@ -36,6 +36,7 @@ var ( ErrContractAddressCollision = errors.New("contract address collision") ErrExecutionReverted = errors.New("execution reverted") ErrMaxCodeSizeExceeded = errors.New("max code size exceeded") + ErrMaxInitCodeSizeExceeded = errors.New("max initcode size exceeded") ErrInvalidJump = errors.New("invalid jump destination") ErrWriteProtection = errors.New("write protection") ErrReturnDataOutOfBounds = errors.New("return data out of bounds") diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go index c8e4d2d0cfe..ef38856ccfc 100644 --- a/core/vm/gas_table.go +++ b/core/vm/gas_table.go @@ -21,6 +21,7 @@ package vm import ( "errors" + "fmt" "github.com/holiman/uint256" @@ -297,11 +298,11 @@ func gasCreate2(_ *EVM, contract *Contract, stack *stack.Stack, mem *Memory, mem if err != nil { return 0, err } - len, overflow := stack.Back(2).Uint64WithOverflow() + size, overflow := stack.Back(2).Uint64WithOverflow() if overflow { return 0, ErrGasUintOverflow } - numWords := ToWordSize(len) + numWords := ToWordSize(size) wordGas, overflow := math.SafeMul(numWords, params.Keccak256WordGas) if overflow { return 0, ErrGasUintOverflow @@ -318,11 +319,14 @@ func gasCreateEip3860(_ *EVM, contract *Contract, stack *stack.Stack, mem *Memor if err != nil { return 0, err } - len, overflow := stack.Back(2).Uint64WithOverflow() - if overflow || len > params.MaxInitCodeSize { + size, overflow := stack.Back(2).Uint64WithOverflow() + if overflow { return 0, ErrGasUintOverflow } - numWords := ToWordSize(len) + if size > params.MaxInitCodeSize { + return 0, fmt.Errorf("%w: size %d", ErrMaxInitCodeSizeExceeded, size) + } + numWords := ToWordSize(size) // Since size <= params.MaxInitCodeSize, this multiplication cannot overflow wordGas := params.InitCodeWordGas * numWords gas, overflow = math.SafeAdd(gas, wordGas) @@ -337,11 +341,14 @@ func gasCreate2Eip3860(_ *EVM, contract *Contract, stack *stack.Stack, mem *Memo if err != nil { return 0, err } - len, overflow := stack.Back(2).Uint64WithOverflow() - if overflow || len > params.MaxInitCodeSize { + size, overflow := stack.Back(2).Uint64WithOverflow() + if overflow { return 0, ErrGasUintOverflow } - numWords := ToWordSize(len) + if size > params.MaxInitCodeSize { + return 0, fmt.Errorf("%w: size %d", ErrMaxInitCodeSizeExceeded, size) + } + numWords := ToWordSize(size) // Since size <= params.MaxInitCodeSize, this multiplication cannot overflow wordGas := (params.InitCodeWordGas + params.Keccak256WordGas) * numWords gas, overflow = math.SafeAdd(gas, wordGas) diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index a6983ef9d2d..7465566bb13 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -20,6 +20,7 @@ package vm import ( + "fmt" "hash" "sync" @@ -298,7 +299,10 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( var dynamicCost uint64 dynamicCost, err = operation.dynamicGas(in.evm, contract, locStack, mem, memorySize) cost += dynamicCost // for tracing - if err != nil || !contract.UseGas(dynamicCost, tracing.GasChangeIgnored) { + if err != nil { + return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err) + } + if !contract.UseGas(dynamicCost, tracing.GasChangeIgnored) { return nil, ErrOutOfGas } // Do tracing before memory expansion