core/vm: added EXTCALL,EXTDELEGATECALL,EXTSTATICCALL opcode

This commit is contained in:
Marius van der Wijden 2024-09-26 14:16:14 +02:00
parent c7db447b1f
commit d206fba16d
1 changed files with 128 additions and 3 deletions

View File

@ -21,6 +21,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
@ -319,15 +320,139 @@ func opReturnDataLoad(pc *uint64, interpreter *EVMInterpreter, scope *ScopeConte
// opExtCall implements the EOFCREATE opcode // opExtCall implements the EOFCREATE opcode
func opExtCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { func opExtCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
panic("not implemented") stack := scope.Stack
// Use all available gas
gas := interpreter.evm.callGasTemp
// Pop other call parameters.
addr, inOffset, inSize, value := stack.pop(), stack.pop(), stack.pop(), stack.pop()
toAddr := common.Address(addr.Bytes20())
if addr.ByteLen() > 20 {
return nil, errors.New("address space extension")
}
// safe a memory alloc
temp := addr
// Get the arguments from the memory.
args := scope.Memory.GetPtr(inOffset.Uint64(), inSize.Uint64())
if interpreter.readOnly && !value.IsZero() {
return nil, ErrWriteProtection
}
var (
ret []byte
returnGas uint64
err error
)
if interpreter.evm.callGasTemp == 0 {
// zero temp call gas indicates a min retained gas error
ret, returnGas, err = nil, 0, ErrExecutionReverted
} else {
ret, returnGas, err = interpreter.evm.Call(scope.Contract, toAddr, args, gas, &value)
}
if errors.Is(err, ErrExecutionReverted) || errors.Is(err, ErrInsufficientBalance) || errors.Is(err, ErrDepth) {
temp.SetOne()
} else if err != nil {
temp.SetUint64(2)
} else {
temp.Clear()
}
stack.push(&temp)
scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
interpreter.returnData = ret
return ret, nil
} }
// opExtDelegateCall implements the EXTDELEGATECALL opcode // opExtDelegateCall implements the EXTDELEGATECALL opcode
func opExtDelegateCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { func opExtDelegateCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
panic("not implemented") stack := scope.Stack
// Use all available gas
gas := interpreter.evm.callGasTemp
// Pop other call parameters.
addr, inOffset, inSize := stack.pop(), stack.pop(), stack.pop()
toAddr := common.Address(addr.Bytes20())
if addr.ByteLen() > 20 {
return nil, errors.New("address space extension")
}
// safe a memory alloc
temp := addr
// Get arguments from the memory.
args := scope.Memory.GetPtr(inOffset.Uint64(), inSize.Uint64())
// Check that we're only calling non-legacy contracts
var (
err error
ret []byte
returnGas uint64
)
code := interpreter.evm.StateDB.GetCode(toAddr)
if !hasEOFMagic(code) {
// Delegate-calling a non-eof contract should return 1
err = ErrExecutionReverted
ret = nil
returnGas = gas
} else if interpreter.evm.callGasTemp == 0 {
// zero temp call gas indicates a min retained gas error
ret, returnGas, err = nil, 0, ErrExecutionReverted
} else {
ret, returnGas, err = interpreter.evm.DelegateCall(scope.Contract, toAddr, args, gas, true)
}
if err == ErrExecutionReverted || err == ErrDepth {
temp.SetOne()
} else if err != nil {
temp.SetUint64(2)
} else {
temp.Clear()
}
stack.push(&temp)
scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
interpreter.returnData = ret
return ret, nil
} }
// opExtStaticCall implements the EXTSTATICCALL opcode // opExtStaticCall implements the EXTSTATICCALL opcode
func opExtStaticCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { func opExtStaticCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
panic("not implemented") stack := scope.Stack
// Use all available gas
gas := interpreter.evm.callGasTemp
// Pop other call parameters.
addr, inOffset, inSize := stack.pop(), stack.pop(), stack.pop()
toAddr := common.Address(addr.Bytes20())
if addr.ByteLen() > 20 {
return nil, errors.New("address space extension")
}
// safe a memory alloc
temp := addr
// Get arguments from the memory.
args := scope.Memory.GetPtr(inOffset.Uint64(), inSize.Uint64())
var (
ret []byte
returnGas uint64
err error
)
if interpreter.evm.callGasTemp == 0 {
// zero temp call gas indicates a min retained gas error
ret, returnGas, err = nil, 0, ErrExecutionReverted
} else {
ret, returnGas, err = interpreter.evm.StaticCall(scope.Contract, toAddr, args, gas)
}
if err == ErrExecutionReverted || err == ErrDepth {
temp.SetOne()
} else if err != nil {
temp.SetUint64(2)
} else {
temp.Clear()
}
stack.push(&temp)
scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
interpreter.returnData = ret
return ret, nil
} }