diff --git a/core/vm/eips.go b/core/vm/eips.go index ed89282236..335186174a 100644 --- a/core/vm/eips.go +++ b/core/vm/eips.go @@ -725,10 +725,10 @@ func enableEOF(jt *JumpTable) { jt[EXTCALL] = &operation{ execute: opExtCall, constantGas: params.CallGasEIP150, - dynamicGas: gasCall, + dynamicGas: gasCallExt, minStack: minStack(4, 1), maxStack: maxStack(4, 1), - memorySize: memoryCall, + memorySize: memoryExtCall, } jt[EXTDELEGATECALL] = &operation{ execute: opExtDelegateCall, @@ -1073,17 +1073,18 @@ func opReturnDataLoad(pc *uint64, interpreter *EVMInterpreter, scope *ScopeConte var ( offset = scope.Stack.pop() ) - if offset.Uint64()+32 > uint64(len(interpreter.returnData)) { - return nil, errors.New("return buffer overflow") + offset64, overflow := offset.Uint64WithOverflow() + if overflow { + offset64 = math.MaxUint64 } - scope.Stack.push(offset.SetBytes(interpreter.returnData[offset.Uint64() : offset.Uint64()+32])) + scope.Stack.push(offset.SetBytes(getData(interpreter.returnData, offset64, 32))) return nil, nil } func opExtCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { stack := scope.Stack // Use all available gas - gas := (scope.Contract.Gas / 64) * 63 + gas := interpreter.evm.callGasTemp // Pop other call parameters. addr, value, inOffset, inSize := stack.pop(), stack.pop(), stack.pop(), stack.pop() toAddr := common.Address(addr.Bytes20()) @@ -1106,7 +1107,7 @@ func opExtCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([] temp.SetOne() } stack.push(&temp) - + fmt.Println(returnGas) scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) interpreter.returnData = ret diff --git a/core/vm/evm.go b/core/vm/evm.go index 17b900bf09..286e160e0d 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -689,7 +689,7 @@ func (evm *EVM) GetVMContext() *tracing.VMContext { // parseContainer tries to parse an EOF container if the Shanghai fork is active. It expects the code to already be validated. func (evm *EVM) parseContainer(b []byte) *Container { - if evm.chainRules.IsShanghai { + if evm.chainRules.IsPrague { var c Container if err := c.UnmarshalBinary(b); err != nil && strings.HasPrefix(err.Error(), "invalid magic") { return nil diff --git a/core/vm/gas.go b/core/vm/gas.go index def6280427..5aaa7eb473 100644 --- a/core/vm/gas.go +++ b/core/vm/gas.go @@ -43,7 +43,7 @@ func callGas(isEip150 bool, availableGas, base uint64, callCost *uint256.Int) (u // If the bit length exceeds 64 bit we know that the newly calculated "gas" for EIP150 // is smaller than the requested amount. Therefore we return the new gas instead // of returning an error. - if !callCost.IsUint64() || gas < callCost.Uint64() { + if !callCost.IsUint64() || gas <= callCost.Uint64() { return gas, nil } } diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go index 5dc36e15d2..bf6401f9fc 100644 --- a/core/vm/gas_table.go +++ b/core/vm/gas_table.go @@ -23,6 +23,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/params" + "github.com/holiman/uint256" ) // memoryGasCost calculates the quadratic gas for memory expansion. It does so @@ -413,6 +414,51 @@ func gasCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize return gas, nil } +func gasCallExt(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + var ( + gas uint64 + transfersValue = !stack.Back(2).IsZero() + address = common.Address(stack.Back(1).Bytes20()) + ) + if evm.chainRules.IsEIP158 { + if transfersValue && evm.StateDB.Empty(address) { + gas += params.CallNewAccountGas + } + } else if !evm.StateDB.Exist(address) { + gas += params.CallNewAccountGas + } + if transfersValue && !evm.chainRules.IsEIP4762 { + gas += params.CallValueTransferGas + } + memoryGas, err := memoryGasCost(mem, memorySize) + if err != nil { + return 0, err + } + var overflow bool + if gas, overflow = math.SafeAdd(gas, memoryGas); overflow { + return 0, ErrGasUintOverflow + } + if evm.chainRules.IsEIP4762 { + if transfersValue { + gas, overflow = math.SafeAdd(gas, evm.AccessEvents.ValueTransferGas(contract.Address(), address)) + if overflow { + return 0, ErrGasUintOverflow + } + } + } + + evm.callGasTemp, err = callGas(true, contract.Gas, gas, new(uint256.Int).SetUint64(contract.Gas)) + if err != nil { + return 0, err + } + + if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow { + return 0, ErrGasUintOverflow + } + + return gas, nil +} + func gasCallCode(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { memoryGas, err := memoryGasCost(mem, memorySize) if err != nil { diff --git a/core/vm/instructions.go b/core/vm/instructions.go index d14bc84991..eb1c13a8be 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -323,6 +323,18 @@ func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeConte length = scope.Stack.pop() ) + if scope.Contract.IsEOF() { + dataOffset64, overflow := dataOffset.Uint64WithOverflow() + if overflow { + dataOffset64 = math.MaxUint64 + } + // These values are checked for overflow during gas cost calculation + memOffset64 := memOffset.Uint64() + length64 := length.Uint64() + scope.Memory.Set(memOffset64, length64, getData(interpreter.returnData, dataOffset64, length64)) + return nil, nil + } + offset64, overflow := dataOffset.Uint64WithOverflow() if overflow { return nil, ErrReturnDataOutOfBounds diff --git a/core/vm/memory_table.go b/core/vm/memory_table.go index f34e7da589..d23c0033ab 100644 --- a/core/vm/memory_table.go +++ b/core/vm/memory_table.go @@ -86,6 +86,7 @@ func memoryCall(stack *Stack) (uint64, bool) { } return y, false } + func memoryDelegateCall(stack *Stack) (uint64, bool) { x, overflow := calcMemSize64(stack.Back(4), stack.Back(5)) if overflow { @@ -116,6 +117,14 @@ func memoryStaticCall(stack *Stack) (uint64, bool) { return y, false } +func memoryExtCall(stack *Stack) (uint64, bool) { + x, overflow := calcMemSize64(stack.Back(2), stack.Back(3)) + if overflow { + return 0, true + } + return x, false +} + func memoryReturn(stack *Stack) (uint64, bool) { return calcMemSize64(stack.Back(0), stack.Back(1)) }