core/vm: added EXTCALL,EXTDELEGATECALL,EXTSTATICCALL opcode
This commit is contained in:
parent
c7db447b1f
commit
d206fba16d
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue