core/vm: fold EVMInterpreter into EVM #32352 (#1838)

This commit is contained in:
Daniel Liu 2025-12-04 13:01:40 +08:00 committed by GitHub
parent 10ac141b76
commit 4c098ddf1f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 324 additions and 351 deletions

View file

@ -70,8 +70,8 @@ func enable1884(jt *JumpTable) {
}
}
func opSelfBalance(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
balance, _ := uint256.FromBig(interpreter.evm.StateDB.GetBalance(scope.Contract.Address()))
func opSelfBalance(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
balance, _ := uint256.FromBig(evm.StateDB.GetBalance(scope.Contract.Address()))
scope.Stack.push(balance)
return nil, nil
}
@ -89,8 +89,8 @@ func enable1344(jt *JumpTable) {
}
// opChainID implements CHAINID opcode
func opChainID(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
chainId, _ := uint256.FromBig(interpreter.evm.chainConfig.ChainID)
func opChainID(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
chainId, _ := uint256.FromBig(evm.chainConfig.ChainID)
scope.Stack.push(chainId)
return nil, nil
}
@ -180,27 +180,27 @@ func enable1153(jt *JumpTable) {
}
// opTload implements TLOAD opcode
func opTload(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opTload(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
loc := scope.Stack.peek()
hash := common.Hash(loc.Bytes32())
val := interpreter.evm.StateDB.GetTransientState(scope.Contract.Address(), hash)
val := evm.StateDB.GetTransientState(scope.Contract.Address(), hash)
loc.SetBytes(val.Bytes())
return nil, nil
}
// opTstore implements TSTORE opcode
func opTstore(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
if interpreter.readOnly {
func opTstore(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
if evm.readOnly {
return nil, ErrWriteProtection
}
loc := scope.Stack.pop()
val := scope.Stack.pop()
interpreter.evm.StateDB.SetTransientState(scope.Contract.Address(), loc.Bytes32(), val.Bytes32())
evm.StateDB.SetTransientState(scope.Contract.Address(), loc.Bytes32(), val.Bytes32())
return nil, nil
}
// opBaseFee implements BASEFEE opcode
func opBaseFee(pc *uint64, interpreter *EVMInterpreter, callContext *ScopeContext) ([]byte, error) {
func opBaseFee(pc *uint64, evm *EVM, callContext *ScopeContext) ([]byte, error) {
baseFee, _ := uint256.FromBig(common.BaseFee)
callContext.Stack.push(baseFee)
return nil, nil
@ -218,7 +218,7 @@ func enable3855(jt *JumpTable) {
}
// opPush0 implements the PUSH0 opcode
func opPush0(pc *uint64, interpreter *EVMInterpreter, callContext *ScopeContext) ([]byte, error) {
func opPush0(pc *uint64, evm *EVM, callContext *ScopeContext) ([]byte, error) {
callContext.Stack.push(new(uint256.Int))
return nil, nil
}
@ -244,7 +244,7 @@ func enable5656(jt *JumpTable) {
}
// opMcopy implements the MCOPY opcode (https://eips.ethereum.org/EIPS/eip-5656)
func opMcopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opMcopy(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
var (
dst = scope.Stack.pop()
src = scope.Stack.pop()
@ -257,7 +257,7 @@ func opMcopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by
}
// opBlobHash implements the BLOBHASH opcode
func opBlobHash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opBlobHash(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
index := scope.Stack.peek()
// xdc chain have no blob hash, so len(interpreter.evm.TxContext.BlobHashes) is always 0
// and index.LtUint64(uint64(len(interpreter.evm.TxContext.BlobHashes))) is always false
@ -272,7 +272,7 @@ func opBlobHash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([
}
// opBlobBaseFee implements BLOBBASEFEE opcode
func opBlobBaseFee(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opBlobBaseFee(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
blobBaseFee := new(uint256.Int)
scope.Stack.push(blobBaseFee)
return nil, nil

View file

@ -26,6 +26,7 @@ import (
"github.com/XinFinOrg/XDPoSChain/core/tracing"
"github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/crypto"
"github.com/XinFinOrg/XDPoSChain/log"
"github.com/XinFinOrg/XDPoSChain/params"
"github.com/holiman/uint256"
)
@ -92,6 +93,9 @@ type EVM struct {
tradingStateDB *tradingstate.TradingStateDB
// table holds the opcode specific handlers
table *JumpTable
// Depth is the current call stack
depth int
@ -102,17 +106,23 @@ type EVM struct {
// virtual machine configuration options used to initialise the
// evm.
Config Config
// global (to this context) ethereum virtual machine
// used throughout the execution of the tx.
interpreter *EVMInterpreter
// abort is used to abort the EVM calling operations
abort atomic.Bool
// callGasTemp holds the gas available for the current call. This is needed because the
// available gas is calculated in gasCall* according to the 63/64 rule and later
// applied in opCall*.
callGasTemp uint64
// precompiles holds the precompiled contracts for the current epoch
precompiles map[common.Address]PrecompiledContract
hasher crypto.KeccakState // Keccak256 hasher instance shared across opcodes
hasherBuf common.Hash // Keccak256 hasher result array shared across opcodes
readOnly bool // Whether to throw on stateful modifications
returnData []byte // Last CALL's return data for subsequent reuse
}
// NewEVM returns a new EVM. The returned EVM is not thread safe and should
@ -126,9 +136,56 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, tradingStat
Config: config,
chainConfig: chainConfig,
chainRules: chainConfig.Rules(blockCtx.BlockNumber),
hasher: crypto.NewKeccakState(),
}
evm.precompiles = activePrecompiledContracts(evm.chainRules)
evm.interpreter = NewEVMInterpreter(evm)
switch {
// TODO(daniel): define pragueInstructionSet
// case evm.chainRules.IsPrague:
// evm.table = &pragueInstructionSet
case evm.chainRules.IsCancun:
evm.table = &cancunInstructionSet
case evm.chainRules.IsEIP1559:
evm.table = &eip1559InstructionSet
case evm.chainRules.IsShanghai:
evm.table = &shanghaiInstructionSet
case evm.chainRules.IsMerge:
evm.table = &mergeInstructionSet
case evm.chainRules.IsLondon:
evm.table = &londonInstructionSet
case evm.chainRules.IsBerlin:
evm.table = &berlinInstructionSet
case evm.chainRules.IsIstanbul:
evm.table = &istanbulInstructionSet
case evm.chainRules.IsConstantinople:
evm.table = &constantinopleInstructionSet
case evm.chainRules.IsByzantium:
evm.table = &byzantiumInstructionSet
case evm.chainRules.IsEIP158:
evm.table = &spuriousDragonInstructionSet
case evm.chainRules.IsEIP150:
evm.table = &tangerineWhistleInstructionSet
case evm.chainRules.IsHomestead:
evm.table = &homesteadInstructionSet
default:
evm.table = &frontierInstructionSet
}
if len(evm.Config.ExtraEips) > 0 {
// Deep-copy jumptable to prevent modification of opcodes in other tables
evm.table = copyJumpTable(evm.table)
}
extraEips := make([]int, 0, len(evm.Config.ExtraEips))
for _, eip := range evm.Config.ExtraEips {
if err := EnableEIP(eip, evm.table); err != nil {
// Disable it, so caller can check if it's activated or not
log.Error("EIP activation failed", "eip", eip, "error", err)
} else {
extraEips = append(extraEips, eip)
}
}
evm.Config.ExtraEips = extraEips[0:len(extraEips):len(extraEips)]
return evm
}
@ -157,11 +214,6 @@ func (evm *EVM) Cancelled() bool {
return evm.abort.Load()
}
// Interpreter returns the current interpreter
func (evm *EVM) Interpreter() *EVMInterpreter {
return evm.interpreter
}
// Call executes the contract associated with the addr with the given input as
// parameters. It also handles any necessary value transfer required and takes
// the necessary steps to create accounts and reverses the state in case of an
@ -208,7 +260,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
// The depth-check is already done, and precompiles handled above
contract := NewContract(caller, AccountRef(addrCopy), value, gas)
contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), code)
ret, err = evm.interpreter.Run(contract, input, false)
ret, err = evm.Run(contract, input, false)
gas = contract.Gas
}
}
@ -268,7 +320,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
// The contract is a scoped environment for this execution context only.
contract := NewContract(caller, AccountRef(caller.Address()), value, gas)
contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), evm.StateDB.GetCode(addrCopy))
ret, err = evm.interpreter.Run(contract, input, false)
ret, err = evm.Run(contract, input, false)
gas = contract.Gas
}
if err != nil {
@ -315,7 +367,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
// Initialise a new contract and make initialise the delegate values
contract := NewContract(caller, AccountRef(caller.Address()), nil, gas).AsDelegate()
contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), evm.StateDB.GetCode(addrCopy))
ret, err = evm.interpreter.Run(contract, input, false)
ret, err = evm.Run(contract, input, false)
gas = contract.Gas
}
if err != nil {
@ -376,7 +428,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
// above we revert to the snapshot and consume any gas remaining. Additionally
// when we're in Homestead this also counts for code storage gas errors.
readOnly := evm.ChainConfig().IsTIPXDCXCancellationFee(evm.Context.BlockNumber)
ret, err = evm.interpreter.Run(contract, input, readOnly)
ret, err = evm.Run(contract, input, readOnly)
gas = contract.Gas
}
if err != nil {
@ -458,7 +510,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
contract := NewContract(caller, AccountRef(address), value, gas)
contract.SetCodeOptionalHash(&address, codeAndHash)
ret, err = evm.interpreter.Run(contract, nil, false)
ret, err = evm.Run(contract, nil, false)
// Check whether the max code size has been exceeded, assign err if the case.
if err == nil && evm.chainRules.IsEIP158 && len(ret) > params.MaxCodeSize {

View file

@ -26,67 +26,67 @@ import (
"github.com/holiman/uint256"
)
func opAdd(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opAdd(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
x, y := scope.Stack.pop(), scope.Stack.peek()
y.Add(&x, y)
return nil, nil
}
func opSub(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opSub(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
x, y := scope.Stack.pop(), scope.Stack.peek()
y.Sub(&x, y)
return nil, nil
}
func opMul(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opMul(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
x, y := scope.Stack.pop(), scope.Stack.peek()
y.Mul(&x, y)
return nil, nil
}
func opDiv(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opDiv(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
x, y := scope.Stack.pop(), scope.Stack.peek()
y.Div(&x, y)
return nil, nil
}
func opSdiv(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opSdiv(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
x, y := scope.Stack.pop(), scope.Stack.peek()
y.SDiv(&x, y)
return nil, nil
}
func opMod(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opMod(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
x, y := scope.Stack.pop(), scope.Stack.peek()
y.Mod(&x, y)
return nil, nil
}
func opSmod(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opSmod(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
x, y := scope.Stack.pop(), scope.Stack.peek()
y.SMod(&x, y)
return nil, nil
}
func opExp(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opExp(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
base, exponent := scope.Stack.pop(), scope.Stack.peek()
exponent.Exp(&base, exponent)
return nil, nil
}
func opSignExtend(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opSignExtend(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
back, num := scope.Stack.pop(), scope.Stack.peek()
num.ExtendSign(num, &back)
return nil, nil
}
func opNot(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opNot(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
x := scope.Stack.peek()
x.Not(x)
return nil, nil
}
func opLt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opLt(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
x, y := scope.Stack.pop(), scope.Stack.peek()
if x.Lt(y) {
y.SetOne()
@ -96,7 +96,7 @@ func opLt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte,
return nil, nil
}
func opGt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opGt(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
x, y := scope.Stack.pop(), scope.Stack.peek()
if x.Gt(y) {
y.SetOne()
@ -106,7 +106,7 @@ func opGt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte,
return nil, nil
}
func opSlt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opSlt(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
x, y := scope.Stack.pop(), scope.Stack.peek()
if x.Slt(y) {
y.SetOne()
@ -116,7 +116,7 @@ func opSlt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte
return nil, nil
}
func opSgt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opSgt(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
x, y := scope.Stack.pop(), scope.Stack.peek()
if x.Sgt(y) {
y.SetOne()
@ -126,7 +126,7 @@ func opSgt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte
return nil, nil
}
func opEq(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opEq(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
x, y := scope.Stack.pop(), scope.Stack.peek()
if x.Eq(y) {
y.SetOne()
@ -136,7 +136,7 @@ func opEq(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte,
return nil, nil
}
func opIszero(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opIszero(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
x := scope.Stack.peek()
if x.IsZero() {
x.SetOne()
@ -146,31 +146,31 @@ func opIszero(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
return nil, nil
}
func opAnd(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opAnd(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
x, y := scope.Stack.pop(), scope.Stack.peek()
y.And(&x, y)
return nil, nil
}
func opOr(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opOr(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
x, y := scope.Stack.pop(), scope.Stack.peek()
y.Or(&x, y)
return nil, nil
}
func opXor(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opXor(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
x, y := scope.Stack.pop(), scope.Stack.peek()
y.Xor(&x, y)
return nil, nil
}
func opByte(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opByte(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
th, val := scope.Stack.pop(), scope.Stack.peek()
val.Byte(&th)
return nil, nil
}
func opAddmod(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opAddmod(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
x, y, z := scope.Stack.pop(), scope.Stack.pop(), scope.Stack.peek()
if z.IsZero() {
z.Clear()
@ -180,7 +180,7 @@ func opAddmod(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
return nil, nil
}
func opMulmod(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opMulmod(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
x, y, z := scope.Stack.pop(), scope.Stack.pop(), scope.Stack.peek()
z.MulMod(&x, &y, z)
return nil, nil
@ -189,7 +189,7 @@ func opMulmod(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
// opSHL implements Shift Left
// The SHL instruction (shift left) pops 2 values from the stack, first arg1 and then arg2,
// and pushes on the stack arg2 shifted to the left by arg1 number of bits.
func opSHL(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opSHL(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
// Note, second operand is left in the stack; accumulate result into it, and no need to push it afterwards
shift, value := scope.Stack.pop(), scope.Stack.peek()
if shift.LtUint64(256) {
@ -203,7 +203,7 @@ func opSHL(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte
// opSHR implements Logical Shift Right
// The SHR instruction (logical shift right) pops 2 values from the stack, first arg1 and then arg2,
// and pushes on the stack arg2 shifted to the right by arg1 number of bits with zero fill.
func opSHR(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opSHR(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
// Note, second operand is left in the stack; accumulate result into it, and no need to push it afterwards
shift, value := scope.Stack.pop(), scope.Stack.peek()
if shift.LtUint64(256) {
@ -217,7 +217,7 @@ func opSHR(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte
// opSAR implements Arithmetic Shift Right
// The SAR instruction (arithmetic shift right) pops 2 values from the stack, first arg1 and then arg2,
// and pushes on the stack arg2 shifted to the right by arg1 number of bits with sign extension.
func opSAR(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opSAR(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
shift, value := scope.Stack.pop(), scope.Stack.peek()
if shift.GtUint64(256) {
if value.Sign() >= 0 {
@ -233,51 +233,50 @@ func opSAR(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte
return nil, nil
}
func opKeccak256(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opKeccak256(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
offset, size := scope.Stack.pop(), scope.Stack.peek()
data := scope.Memory.GetPtr(int64(offset.Uint64()), int64(size.Uint64()))
interpreter.hasher.Reset()
interpreter.hasher.Write(data)
interpreter.hasher.Read(interpreter.hasherBuf[:])
evm.hasher.Reset()
evm.hasher.Write(data)
evm.hasher.Read(evm.hasherBuf[:])
evm := interpreter.evm
if evm.Config.EnablePreimageRecording {
evm.StateDB.AddPreimage(interpreter.hasherBuf, data)
evm.StateDB.AddPreimage(evm.hasherBuf, data)
}
size.SetBytes(interpreter.hasherBuf[:])
size.SetBytes(evm.hasherBuf[:])
return nil, nil
}
func opAddress(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opAddress(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
scope.Stack.push(new(uint256.Int).SetBytes(scope.Contract.Address().Bytes()))
return nil, nil
}
func opBalance(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opBalance(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
slot := scope.Stack.peek()
address := common.Address(slot.Bytes20())
slot.SetFromBig(interpreter.evm.StateDB.GetBalance(address))
slot.SetFromBig(evm.StateDB.GetBalance(address))
return nil, nil
}
func opOrigin(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
scope.Stack.push(new(uint256.Int).SetBytes(interpreter.evm.Origin.Bytes()))
func opOrigin(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
scope.Stack.push(new(uint256.Int).SetBytes(evm.Origin.Bytes()))
return nil, nil
}
func opCaller(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opCaller(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
scope.Stack.push(new(uint256.Int).SetBytes(scope.Contract.Caller().Bytes()))
return nil, nil
}
func opCallValue(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opCallValue(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
v, _ := uint256.FromBig(scope.Contract.value)
scope.Stack.push(v)
return nil, nil
}
func opCallDataLoad(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opCallDataLoad(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
x := scope.Stack.peek()
if offset, overflow := x.Uint64WithOverflow(); !overflow {
data := getData(scope.Contract.Input, offset, 32)
@ -288,12 +287,12 @@ func opCallDataLoad(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext
return nil, nil
}
func opCallDataSize(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opCallDataSize(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
scope.Stack.push(new(uint256.Int).SetUint64(uint64(len(scope.Contract.Input))))
return nil, nil
}
func opCallDataCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opCallDataCopy(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
var (
memOffset = scope.Stack.pop()
dataOffset = scope.Stack.pop()
@ -311,12 +310,12 @@ func opCallDataCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext
return nil, nil
}
func opReturnDataSize(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
scope.Stack.push(new(uint256.Int).SetUint64(uint64(len(interpreter.returnData))))
func opReturnDataSize(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
scope.Stack.push(new(uint256.Int).SetUint64(uint64(len(evm.returnData))))
return nil, nil
}
func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opReturnDataCopy(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
var (
memOffset = scope.Stack.pop()
dataOffset = scope.Stack.pop()
@ -331,27 +330,27 @@ func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeConte
var end = dataOffset
end.Add(&dataOffset, &length)
end64, overflow := end.Uint64WithOverflow()
if overflow || uint64(len(interpreter.returnData)) < end64 {
if overflow || uint64(len(evm.returnData)) < end64 {
return nil, ErrReturnDataOutOfBounds
}
scope.Memory.Set(memOffset.Uint64(), length.Uint64(), interpreter.returnData[offset64:end64])
scope.Memory.Set(memOffset.Uint64(), length.Uint64(), evm.returnData[offset64:end64])
return nil, nil
}
func opExtCodeSize(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opExtCodeSize(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
slot := scope.Stack.peek()
slot.SetUint64(uint64(interpreter.evm.StateDB.GetCodeSize(slot.Bytes20())))
slot.SetUint64(uint64(evm.StateDB.GetCodeSize(slot.Bytes20())))
return nil, nil
}
func opCodeSize(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opCodeSize(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
l := new(uint256.Int)
l.SetUint64(uint64(len(scope.Contract.Code)))
scope.Stack.push(l)
return nil, nil
}
func opCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opCodeCopy(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
var (
memOffset = scope.Stack.pop()
codeOffset = scope.Stack.pop()
@ -367,7 +366,7 @@ func opCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([
return nil, nil
}
func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opExtCodeCopy(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
var (
stack = scope.Stack
a = stack.pop()
@ -380,7 +379,7 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
uint64CodeOffset = math.MaxUint64
}
addr := common.Address(a.Bytes20())
codeCopy := getData(interpreter.evm.StateDB.GetCode(addr), uint64CodeOffset, length.Uint64())
codeCopy := getData(evm.StateDB.GetCode(addr), uint64CodeOffset, length.Uint64())
scope.Memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy)
return nil, nil
@ -419,24 +418,24 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
// (6) Caller tries to get the code hash for an account which is marked as deleted,
//
// this account should be regarded as a non-existent account and zero should be returned.
func opExtCodeHash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opExtCodeHash(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
slot := scope.Stack.peek()
address := common.Address(slot.Bytes20())
if interpreter.evm.StateDB.Empty(address) {
if evm.StateDB.Empty(address) {
slot.Clear()
} else {
slot.SetBytes(interpreter.evm.StateDB.GetCodeHash(address).Bytes())
slot.SetBytes(evm.StateDB.GetCodeHash(address).Bytes())
}
return nil, nil
}
func opGasprice(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
v, _ := uint256.FromBig(interpreter.evm.GasPrice)
func opGasprice(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
v, _ := uint256.FromBig(evm.GasPrice)
scope.Stack.push(v)
return nil, nil
}
func opBlockhash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opBlockhash(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
num := scope.Stack.peek()
num64, overflow := num.Uint64WithOverflow()
if overflow {
@ -444,47 +443,47 @@ func opBlockhash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) (
return nil, nil
}
var upper, lower uint64
upper = interpreter.evm.Context.BlockNumber.Uint64()
upper = evm.Context.BlockNumber.Uint64()
if upper < 257 {
lower = 0
} else {
lower = upper - 256
}
if num64 >= lower && num64 < upper {
num.SetBytes(interpreter.evm.Context.GetHash(num64).Bytes())
num.SetBytes(evm.Context.GetHash(num64).Bytes())
} else {
num.Clear()
}
return nil, nil
}
func opCoinbase(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
scope.Stack.push(new(uint256.Int).SetBytes(interpreter.evm.Context.Coinbase.Bytes()))
func opCoinbase(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
scope.Stack.push(new(uint256.Int).SetBytes(evm.Context.Coinbase.Bytes()))
return nil, nil
}
func opTimestamp(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
scope.Stack.push(new(uint256.Int).SetUint64(interpreter.evm.Context.Time))
func opTimestamp(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
scope.Stack.push(new(uint256.Int).SetUint64(evm.Context.Time))
return nil, nil
}
func opNumber(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
v, _ := uint256.FromBig(interpreter.evm.Context.BlockNumber)
func opNumber(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
v, _ := uint256.FromBig(evm.Context.BlockNumber)
scope.Stack.push(v)
return nil, nil
}
func opDifficulty(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
v, _ := uint256.FromBig(interpreter.evm.Context.Difficulty)
func opDifficulty(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
v, _ := uint256.FromBig(evm.Context.Difficulty)
scope.Stack.push(v)
return nil, nil
}
// NOTE: Random is predictable in current implemention, do not use it in real business
func opRandom(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opRandom(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
var v *uint256.Int
if interpreter.evm.Context.Random != nil {
v = new(uint256.Int).SetBytes((interpreter.evm.Context.Random.Bytes()))
if evm.Context.Random != nil {
v = new(uint256.Int).SetBytes((evm.Context.Random.Bytes()))
} else { // if context random is not set, use emptyCodeHash as default
v = new(uint256.Int).SetBytes(types.EmptyCodeHash.Bytes())
}
@ -492,56 +491,56 @@ func opRandom(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
return nil, nil
}
func opGasLimit(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
scope.Stack.push(new(uint256.Int).SetUint64(interpreter.evm.Context.GasLimit))
func opGasLimit(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
scope.Stack.push(new(uint256.Int).SetUint64(evm.Context.GasLimit))
return nil, nil
}
func opPop(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opPop(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
scope.Stack.pop()
return nil, nil
}
func opMload(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opMload(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
v := scope.Stack.peek()
offset := int64(v.Uint64())
v.SetBytes(scope.Memory.GetPtr(offset, 32))
return nil, nil
}
func opMstore(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opMstore(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
// pop value of the stack
mStart, val := scope.Stack.pop(), scope.Stack.pop()
scope.Memory.Set32(mStart.Uint64(), &val)
return nil, nil
}
func opMstore8(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opMstore8(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
off, val := scope.Stack.pop(), scope.Stack.pop()
scope.Memory.store[off.Uint64()] = byte(val.Uint64())
return nil, nil
}
func opSload(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opSload(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
loc := scope.Stack.peek()
hash := common.Hash(loc.Bytes32())
val := interpreter.evm.StateDB.GetState(scope.Contract.Address(), hash)
val := evm.StateDB.GetState(scope.Contract.Address(), hash)
loc.SetBytes(val.Bytes())
return nil, nil
}
func opSstore(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
if interpreter.readOnly {
func opSstore(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
if evm.readOnly {
return nil, ErrWriteProtection
}
loc := scope.Stack.pop()
val := scope.Stack.pop()
interpreter.evm.StateDB.SetState(scope.Contract.Address(), loc.Bytes32(), val.Bytes32())
evm.StateDB.SetState(scope.Contract.Address(), loc.Bytes32(), val.Bytes32())
return nil, nil
}
func opJump(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
if interpreter.evm.abort.Load() {
func opJump(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
if evm.abort.Load() {
return nil, errStopToken
}
pos := scope.Stack.pop()
@ -552,8 +551,8 @@ func opJump(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt
return nil, nil
}
func opJumpi(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
if interpreter.evm.abort.Load() {
func opJumpi(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
if evm.abort.Load() {
return nil, errStopToken
}
pos, cond := scope.Stack.pop(), scope.Stack.pop()
@ -566,27 +565,27 @@ func opJumpi(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by
return nil, nil
}
func opJumpdest(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opJumpdest(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
return nil, nil
}
func opPc(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opPc(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
scope.Stack.push(new(uint256.Int).SetUint64(*pc))
return nil, nil
}
func opMsize(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opMsize(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
scope.Stack.push(new(uint256.Int).SetUint64(uint64(scope.Memory.Len())))
return nil, nil
}
func opGas(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opGas(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
scope.Stack.push(new(uint256.Int).SetUint64(scope.Contract.Gas))
return nil, nil
}
func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
if interpreter.readOnly {
func opCreate(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
if evm.readOnly {
return nil, ErrWriteProtection
}
var (
@ -595,25 +594,25 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
input = scope.Memory.GetCopy(int64(offset.Uint64()), int64(size.Uint64()))
gas = scope.Contract.Gas
)
if interpreter.evm.chainRules.IsEIP150 {
if evm.chainRules.IsEIP150 {
gas -= gas / 64
}
// reuse size int for stackvalue
stackvalue := size
scope.Contract.UseGas(gas, interpreter.evm.Config.Tracer, tracing.GasChangeCallContractCreation)
scope.Contract.UseGas(gas, evm.Config.Tracer, tracing.GasChangeCallContractCreation)
// TODO(daniel): use uint256.Int instead of converting with toBig()
var bigVal = big0
if !value.IsZero() {
bigVal = value.ToBig()
}
res, addr, returnGas, suberr := interpreter.evm.Create(scope.Contract, input, gas, bigVal)
res, addr, returnGas, suberr := evm.Create(scope.Contract, input, gas, bigVal)
// Push item on the stack based on the returned error. If the ruleset is
// homestead we must check for CodeStoreOutOfGasError (homestead only
// rule) and treat as an error, if the ruleset is frontier we must
// ignore this error and pretend the operation was successful.
if interpreter.evm.chainRules.IsHomestead && suberr == ErrCodeStoreOutOfGas {
if evm.chainRules.IsHomestead && suberr == ErrCodeStoreOutOfGas {
stackvalue.Clear()
} else if suberr != nil && suberr != ErrCodeStoreOutOfGas {
stackvalue.Clear()
@ -622,18 +621,18 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
}
scope.Stack.push(&stackvalue)
scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
scope.Contract.RefundGas(returnGas, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
if suberr == ErrExecutionReverted {
interpreter.returnData = res // set REVERT data to return data buffer
evm.returnData = res // set REVERT data to return data buffer
return res, nil
}
interpreter.returnData = nil // clear dirty return data buffer
evm.returnData = nil // clear dirty return data buffer
return nil, nil
}
func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
if interpreter.readOnly {
func opCreate2(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
if evm.readOnly {
return nil, ErrWriteProtection
}
var (
@ -645,7 +644,7 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]
)
// Apply EIP150
gas -= gas / 64
scope.Contract.UseGas(gas, interpreter.evm.Config.Tracer, tracing.GasChangeCallContractCreation2)
scope.Contract.UseGas(gas, evm.Config.Tracer, tracing.GasChangeCallContractCreation2)
// reuse size int for stackvalue
stackvalue := size
// TODO(daniel): use uint256.Int instead of converting with toBig()
@ -653,7 +652,7 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]
if !endowment.IsZero() {
bigEndowment = endowment.ToBig()
}
res, addr, returnGas, suberr := interpreter.evm.Create2(scope.Contract, input, gas,
res, addr, returnGas, suberr := evm.Create2(scope.Contract, input, gas,
bigEndowment, &salt)
// Push item on the stack based on the returned error.
if suberr != nil {
@ -663,29 +662,29 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]
}
scope.Stack.push(&stackvalue)
scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
scope.Contract.RefundGas(returnGas, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
if suberr == ErrExecutionReverted {
interpreter.returnData = res // set REVERT data to return data buffer
evm.returnData = res // set REVERT data to return data buffer
return res, nil
}
interpreter.returnData = nil // clear dirty return data buffer
evm.returnData = nil // clear dirty return data buffer
return nil, nil
}
func opCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opCall(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
stack := scope.Stack
// Pop gas. The actual gas in interpreter.evm.callGasTemp.
// Pop gas. The actual gas in evm.callGasTemp.
// We can use this as a temporary value
temp := stack.pop()
gas := interpreter.evm.callGasTemp
gas := evm.callGasTemp
// Pop other call parameters.
addr, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
toAddr := common.Address(addr.Bytes20())
// Get the arguments from the memory.
args := scope.Memory.GetPtr(int64(inOffset.Uint64()), int64(inSize.Uint64()))
if interpreter.readOnly && !value.IsZero() {
if evm.readOnly && !value.IsZero() {
return nil, ErrWriteProtection
}
@ -698,7 +697,7 @@ func opCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt
bigVal = value.ToBig()
}
ret, returnGas, err := interpreter.evm.Call(scope.Contract, toAddr, args, gas, bigVal)
ret, returnGas, err := evm.Call(scope.Contract, toAddr, args, gas, bigVal)
if err != nil {
temp.Clear()
@ -710,18 +709,18 @@ func opCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
}
scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
scope.Contract.RefundGas(returnGas, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
interpreter.returnData = ret
evm.returnData = ret
return ret, nil
}
func opCallCode(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
// Pop gas. The actual gas is in interpreter.evm.callGasTemp.
func opCallCode(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
// Pop gas. The actual gas is in evm.callGasTemp.
stack := scope.Stack
// We use it as a temporary value
temp := stack.pop()
gas := interpreter.evm.callGasTemp
gas := evm.callGasTemp
// Pop other call parameters.
addr, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
toAddr := common.Address(addr.Bytes20())
@ -735,7 +734,7 @@ func opCallCode(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([
bigVal = value.ToBig()
}
ret, returnGas, err := interpreter.evm.CallCode(scope.Contract, toAddr, args, gas, bigVal)
ret, returnGas, err := evm.CallCode(scope.Contract, toAddr, args, gas, bigVal)
if err != nil {
temp.Clear()
} else {
@ -746,25 +745,25 @@ func opCallCode(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
}
scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
scope.Contract.RefundGas(returnGas, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
interpreter.returnData = ret
evm.returnData = ret
return ret, nil
}
func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opDelegateCall(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
stack := scope.Stack
// Pop gas. The actual gas is in interpreter.evm.callGasTemp.
// Pop gas. The actual gas is in evm.callGasTemp.
// We use it as a temporary value
temp := stack.pop()
gas := interpreter.evm.callGasTemp
gas := evm.callGasTemp
// Pop other call parameters.
addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
toAddr := common.Address(addr.Bytes20())
// Get arguments from the memory.
args := scope.Memory.GetPtr(int64(inOffset.Uint64()), int64(inSize.Uint64()))
ret, returnGas, err := interpreter.evm.DelegateCall(scope.Contract, toAddr, args, gas)
ret, returnGas, err := evm.DelegateCall(scope.Contract, toAddr, args, gas)
if err != nil {
temp.Clear()
} else {
@ -775,25 +774,25 @@ func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
}
scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
scope.Contract.RefundGas(returnGas, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
interpreter.returnData = ret
evm.returnData = ret
return ret, nil
}
func opStaticCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
// Pop gas. The actual gas is in interpreter.evm.callGasTemp.
func opStaticCall(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
// Pop gas. The actual gas is in evm.callGasTemp.
stack := scope.Stack
// We use it as a temporary value
temp := stack.pop()
gas := interpreter.evm.callGasTemp
gas := evm.callGasTemp
// Pop other call parameters.
addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
toAddr := common.Address(addr.Bytes20())
// Get arguments from the memory.
args := scope.Memory.GetPtr(int64(inOffset.Uint64()), int64(inSize.Uint64()))
ret, returnGas, err := interpreter.evm.StaticCall(scope.Contract, toAddr, args, gas)
ret, returnGas, err := evm.StaticCall(scope.Contract, toAddr, args, gas)
if err != nil {
temp.Clear()
} else {
@ -804,69 +803,69 @@ func opStaticCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
}
scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
scope.Contract.RefundGas(returnGas, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
interpreter.returnData = ret
evm.returnData = ret
return ret, nil
}
func opReturn(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opReturn(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
offset, size := scope.Stack.pop(), scope.Stack.pop()
ret := scope.Memory.GetPtr(int64(offset.Uint64()), int64(size.Uint64()))
return ret, errStopToken
}
func opRevert(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opRevert(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
offset, size := scope.Stack.pop(), scope.Stack.pop()
ret := scope.Memory.GetPtr(int64(offset.Uint64()), int64(size.Uint64()))
interpreter.returnData = ret
evm.returnData = ret
return ret, ErrExecutionReverted
}
func opUndefined(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opUndefined(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
return nil, &ErrInvalidOpCode{opcode: OpCode(scope.Contract.Code[*pc])}
}
func opStop(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opStop(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
return nil, errStopToken
}
func opSelfdestruct(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
if interpreter.readOnly {
func opSelfdestruct(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
if evm.readOnly {
return nil, ErrWriteProtection
}
beneficiary := scope.Stack.pop()
balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address())
interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, tracing.BalanceIncreaseSelfdestruct)
interpreter.evm.StateDB.SelfDestruct(scope.Contract.Address())
if tracer := interpreter.evm.Config.Tracer; tracer != nil {
balance := evm.StateDB.GetBalance(scope.Contract.Address())
evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, tracing.BalanceIncreaseSelfdestruct)
evm.StateDB.SelfDestruct(scope.Contract.Address())
if tracer := evm.Config.Tracer; tracer != nil {
if tracer.OnEnter != nil {
tracer.OnEnter(interpreter.evm.depth, byte(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance)
tracer.OnEnter(evm.depth, byte(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance)
}
if tracer.OnExit != nil {
tracer.OnExit(interpreter.evm.depth, []byte{}, 0, nil, false)
tracer.OnExit(evm.depth, []byte{}, 0, nil, false)
}
}
return nil, errStopToken
}
func opSelfdestruct6780(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
if interpreter.readOnly {
func opSelfdestruct6780(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
if evm.readOnly {
return nil, ErrWriteProtection
}
beneficiary := scope.Stack.pop()
balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address())
interpreter.evm.StateDB.SubBalance(scope.Contract.Address(), balance, tracing.BalanceDecreaseSelfdestruct)
interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, tracing.BalanceIncreaseSelfdestruct)
interpreter.evm.StateDB.Selfdestruct6780(scope.Contract.Address())
if tracer := interpreter.evm.Config.Tracer; tracer != nil {
balance := evm.StateDB.GetBalance(scope.Contract.Address())
evm.StateDB.SubBalance(scope.Contract.Address(), balance, tracing.BalanceDecreaseSelfdestruct)
evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, tracing.BalanceIncreaseSelfdestruct)
evm.StateDB.Selfdestruct6780(scope.Contract.Address())
if tracer := evm.Config.Tracer; tracer != nil {
if tracer.OnEnter != nil {
tracer.OnEnter(interpreter.evm.depth, byte(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance)
tracer.OnEnter(evm.depth, byte(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance)
}
if tracer.OnExit != nil {
tracer.OnExit(interpreter.evm.depth, []byte{}, 0, nil, false)
tracer.OnExit(evm.depth, []byte{}, 0, nil, false)
}
}
return nil, errStopToken
@ -876,8 +875,8 @@ func opSelfdestruct6780(pc *uint64, interpreter *EVMInterpreter, scope *ScopeCon
// make log instruction function
func makeLog(size int) executionFunc {
return func(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
if interpreter.readOnly {
return func(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
if evm.readOnly {
return nil, ErrWriteProtection
}
topics := make([]common.Hash, size)
@ -889,13 +888,13 @@ func makeLog(size int) executionFunc {
}
d := scope.Memory.GetCopy(int64(mStart.Uint64()), int64(mSize.Uint64()))
interpreter.evm.StateDB.AddLog(&types.Log{
evm.StateDB.AddLog(&types.Log{
Address: scope.Contract.Address(),
Topics: topics,
Data: d,
// This is a non-consensus field, but assigned here because
// core/state doesn't know the current block number.
BlockNumber: interpreter.evm.Context.BlockNumber.Uint64(),
BlockNumber: evm.Context.BlockNumber.Uint64(),
})
return nil, nil
@ -903,7 +902,7 @@ func makeLog(size int) executionFunc {
}
// opPush1 is a specialized version of pushN
func opPush1(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
func opPush1(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
var (
codeLen = uint64(len(scope.Contract.Code))
integer = new(uint256.Int)
@ -919,7 +918,7 @@ func opPush1(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by
// make push instruction function
func makePush(size uint64, pushByteSize int) executionFunc {
return func(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
return func(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
var (
codeLen = len(scope.Contract.Code)
start = min(codeLen, int(*pc+1))
@ -938,7 +937,7 @@ func makePush(size uint64, pushByteSize int) executionFunc {
// make dup instruction function
func makeDup(size int64) executionFunc {
return func(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
return func(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
scope.Stack.dup(int(size))
return nil, nil
}
@ -948,7 +947,7 @@ func makeDup(size int64) executionFunc {
func makeSwap(size int64) executionFunc {
// switch n + 1 otherwise n would be swapped with n
size++
return func(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
return func(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
scope.Stack.swap(int(size))
return nil, nil
}

View file

@ -106,10 +106,9 @@ func init() {
func testTwoOperandOp(t *testing.T, tests []TwoOperandTestcase, opFn executionFunc, name string) {
var (
env = NewEVM(BlockContext{}, TxContext{}, nil, nil, params.TestChainConfig, Config{})
stack = newstack()
pc = uint64(0)
evmInterpreter = env.interpreter
evm = NewEVM(BlockContext{}, TxContext{}, nil, nil, params.TestChainConfig, Config{})
stack = newstack()
pc = uint64(0)
)
for i, test := range tests {
@ -118,7 +117,7 @@ func testTwoOperandOp(t *testing.T, tests []TwoOperandTestcase, opFn executionFu
expected := new(uint256.Int).SetBytes(common.Hex2Bytes(test.Expected))
stack.push(x)
stack.push(y)
opFn(&pc, evmInterpreter, &ScopeContext{nil, stack, nil})
opFn(&pc, evm, &ScopeContext{nil, stack, nil})
if len(stack.data) != 1 {
t.Errorf("Expected one item on stack after %v, got %d: ", name, len(stack.data))
}
@ -205,10 +204,9 @@ func TestSAR(t *testing.T) {
func TestAddMod(t *testing.T) {
var (
env = NewEVM(BlockContext{}, TxContext{}, nil, nil, params.TestChainConfig, Config{})
stack = newstack()
evmInterpreter = NewEVMInterpreter(env)
pc = uint64(0)
evm = NewEVM(BlockContext{}, TxContext{}, nil, nil, params.TestChainConfig, Config{})
stack = newstack()
pc = uint64(0)
)
tests := []struct {
x string
@ -233,7 +231,7 @@ func TestAddMod(t *testing.T) {
stack.push(z)
stack.push(y)
stack.push(x)
opAddmod(&pc, evmInterpreter, &ScopeContext{nil, stack, nil})
opAddmod(&pc, evm, &ScopeContext{nil, stack, nil})
actual := stack.pop()
if actual.Cmp(expected) != 0 {
t.Errorf("Testcase %d, expected %x, got %x", i, expected, actual)
@ -249,10 +247,9 @@ func TestWriteExpectedValues(t *testing.T) {
// getResult is a convenience function to generate the expected values
getResult := func(args []*twoOperandParams, opFn executionFunc) []TwoOperandTestcase {
var (
env = NewEVM(BlockContext{}, TxContext{}, nil, nil, params.TestChainConfig, Config{})
stack = newstack()
pc = uint64(0)
interpreter = env.interpreter
evm = NewEVM(BlockContext{}, TxContext{}, nil, nil, params.TestChainConfig, Config{})
stack = newstack()
pc = uint64(0)
)
result := make([]TwoOperandTestcase, len(args))
for i, param := range args {
@ -260,7 +257,7 @@ func TestWriteExpectedValues(t *testing.T) {
y := new(uint256.Int).SetBytes(common.Hex2Bytes(param.y))
stack.push(x)
stack.push(y)
_, err := opFn(&pc, interpreter, &ScopeContext{nil, stack, nil})
_, err := opFn(&pc, evm, &ScopeContext{nil, stack, nil})
if err != nil {
log.Fatalln(err)
}
@ -300,13 +297,11 @@ func TestJsonTestcases(t *testing.T) {
func opBenchmark(bench *testing.B, op executionFunc, args ...string) {
var (
env = NewEVM(BlockContext{}, TxContext{}, nil, nil, params.TestChainConfig, Config{})
stack = newstack()
scope = &ScopeContext{nil, stack, nil}
evmInterpreter = NewEVMInterpreter(env)
evm = NewEVM(BlockContext{}, TxContext{}, nil, nil, params.TestChainConfig, Config{})
stack = newstack()
scope = &ScopeContext{nil, stack, nil}
)
env.interpreter = evmInterpreter
// convert args
intArgs := make([]*uint256.Int, len(args))
for i, arg := range args {
@ -317,7 +312,7 @@ func opBenchmark(bench *testing.B, op executionFunc, args ...string) {
for _, arg := range intArgs {
stack.push(arg)
}
op(&pc, evmInterpreter, scope)
op(&pc, evm, scope)
stack.pop()
}
@ -539,25 +534,23 @@ func BenchmarkOpIsZero(b *testing.B) {
func TestOpMstore(t *testing.T) {
var (
env = NewEVM(BlockContext{}, TxContext{}, nil, nil, params.TestChainConfig, Config{})
stack = newstack()
mem = NewMemory()
evmInterpreter = NewEVMInterpreter(env)
evm = NewEVM(BlockContext{}, TxContext{}, nil, nil, params.TestChainConfig, Config{})
stack = newstack()
mem = NewMemory()
)
env.interpreter = evmInterpreter
mem.Resize(64)
pc := uint64(0)
v := "abcdef00000000000000abba000000000deaf000000c0de00100000000133700"
stack.push(new(uint256.Int).SetBytes(common.Hex2Bytes(v)))
stack.push(new(uint256.Int))
opMstore(&pc, evmInterpreter, &ScopeContext{mem, stack, nil})
opMstore(&pc, evm, &ScopeContext{mem, stack, nil})
if got := common.Bytes2Hex(mem.GetCopy(0, 32)); got != v {
t.Fatalf("Mstore fail, got %v, expected %v", got, v)
}
stack.push(new(uint256.Int).SetUint64(0x1))
stack.push(new(uint256.Int))
opMstore(&pc, evmInterpreter, &ScopeContext{mem, stack, nil})
opMstore(&pc, evm, &ScopeContext{mem, stack, nil})
if common.Bytes2Hex(mem.GetCopy(0, 32)) != "0000000000000000000000000000000000000000000000000000000000000001" {
t.Fatalf("Mstore failed to overwrite previous value")
}
@ -565,13 +558,11 @@ func TestOpMstore(t *testing.T) {
func BenchmarkOpMstore(bench *testing.B) {
var (
env = NewEVM(BlockContext{}, TxContext{}, nil, nil, params.TestChainConfig, Config{})
stack = newstack()
mem = NewMemory()
evmInterpreter = NewEVMInterpreter(env)
evm = NewEVM(BlockContext{}, TxContext{}, nil, nil, params.TestChainConfig, Config{})
stack = newstack()
mem = NewMemory()
)
env.interpreter = evmInterpreter
mem.Resize(64)
pc := uint64(0)
memStart := new(uint256.Int)
@ -580,43 +571,41 @@ func BenchmarkOpMstore(bench *testing.B) {
for bench.Loop() {
stack.push(value)
stack.push(memStart)
opMstore(&pc, evmInterpreter, &ScopeContext{mem, stack, nil})
opMstore(&pc, evm, &ScopeContext{mem, stack, nil})
}
}
func TestOpTstore(t *testing.T) {
var (
statedb, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()))
env = NewEVM(BlockContext{}, TxContext{}, statedb, nil, params.TestChainConfig, Config{})
stack = newstack()
mem = NewMemory()
evmInterpreter = NewEVMInterpreter(env)
caller = common.Address{}
to = common.Address{1}
contractRef = contractRef{caller}
contract = NewContract(contractRef, AccountRef(to), new(big.Int), 0)
scopeContext = ScopeContext{mem, stack, contract}
value = common.Hex2Bytes("abcdef00000000000000abba000000000deaf000000c0de00100000000133700")
statedb, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()))
evm = NewEVM(BlockContext{}, TxContext{}, statedb, nil, params.TestChainConfig, Config{})
stack = newstack()
mem = NewMemory()
caller = common.Address{}
to = common.Address{1}
contractRef = contractRef{caller}
contract = NewContract(contractRef, AccountRef(to), new(big.Int), 0)
scopeContext = ScopeContext{mem, stack, contract}
value = common.Hex2Bytes("abcdef00000000000000abba000000000deaf000000c0de00100000000133700")
)
// Add a stateObject for the caller and the contract being called
statedb.CreateAccount(caller)
statedb.CreateAccount(to)
env.interpreter = evmInterpreter
pc := uint64(0)
// push the value to the stack
stack.push(new(uint256.Int).SetBytes(value))
// push the location to the stack
stack.push(new(uint256.Int))
opTstore(&pc, evmInterpreter, &scopeContext)
opTstore(&pc, evm, &scopeContext)
// there should be no elements on the stack after TSTORE
if stack.len() != 0 {
t.Fatal("stack wrong size")
}
// push the location to the stack
stack.push(new(uint256.Int))
opTload(&pc, evmInterpreter, &scopeContext)
opTload(&pc, evm, &scopeContext)
// there should be one element on the stack after TLOAD
if stack.len() != 1 {
t.Fatal("stack wrong size")
@ -629,12 +618,10 @@ func TestOpTstore(t *testing.T) {
func BenchmarkOpKeccak256(bench *testing.B) {
var (
env = NewEVM(BlockContext{}, TxContext{}, nil, nil, params.TestChainConfig, Config{})
stack = newstack()
mem = NewMemory()
evmInterpreter = NewEVMInterpreter(env)
evm = NewEVM(BlockContext{}, TxContext{}, nil, nil, params.TestChainConfig, Config{})
stack = newstack()
mem = NewMemory()
)
env.interpreter = evmInterpreter
mem.Resize(32)
pc := uint64(0)
start := new(uint256.Int)
@ -642,7 +629,7 @@ func BenchmarkOpKeccak256(bench *testing.B) {
for bench.Loop() {
stack.push(uint256.NewInt(32))
stack.push(start)
opKeccak256(&pc, evmInterpreter, &ScopeContext{mem, stack, nil})
opKeccak256(&pc, evm, &ScopeContext{mem, stack, nil})
}
}
@ -732,12 +719,11 @@ func TestRandom(t *testing.T) {
{name: "hash(0x010203)", random: crypto.Keccak256Hash([]byte{0x01, 0x02, 0x03})},
} {
var (
env = NewEVM(BlockContext{Random: &tt.random}, TxContext{}, nil, nil, params.TestChainConfig, Config{})
stack = newstack()
pc = uint64(0)
evmInterpreter = NewEVMInterpreter(env)
evm = NewEVM(BlockContext{Random: &tt.random}, TxContext{}, nil, nil, params.TestChainConfig, Config{})
stack = newstack()
pc = uint64(0)
)
opRandom(&pc, evmInterpreter, &ScopeContext{nil, stack, nil})
opRandom(&pc, evm, &ScopeContext{nil, stack, nil})
if len(stack.data) != 1 {
t.Errorf("Expected one item on stack after %v, got %d: ", tt.name, len(stack.data))
}
@ -779,7 +765,7 @@ func TestBlobHash(t *testing.T) {
)
// evm.SetTxContext(TxContext{BlobHashes: tt.hashes})
stack.push(uint256.NewInt(tt.idx))
opBlobHash(&pc, evm.interpreter, &ScopeContext{nil, stack, nil})
opBlobHash(&pc, evm, &ScopeContext{nil, stack, nil})
if len(stack.data) != 1 {
t.Errorf("Expected one item on stack after %v, got %d: ", tt.name, len(stack.data))
}
@ -876,10 +862,9 @@ func TestOpMCopy(t *testing.T) {
},
} {
var (
env = NewEVM(BlockContext{}, TxContext{}, nil, nil, params.TestChainConfig, Config{})
stack = newstack()
pc = uint64(0)
evmInterpreter = env.interpreter
evm = NewEVM(BlockContext{}, TxContext{}, nil, nil, params.TestChainConfig, Config{})
stack = newstack()
pc = uint64(0)
)
data := common.FromHex(strings.ReplaceAll(tc.pre, " ", ""))
// Set pre
@ -910,7 +895,7 @@ func TestOpMCopy(t *testing.T) {
}
// and the dynamic cost
var haveGas uint64
if dynamicCost, err := gasMcopy(env, nil, stack, mem, memorySize); err != nil {
if dynamicCost, err := gasMcopy(evm, nil, stack, mem, memorySize); err != nil {
t.Error(err)
} else {
haveGas = GasFastestStep + dynamicCost
@ -920,7 +905,7 @@ func TestOpMCopy(t *testing.T) {
mem.Resize(memorySize)
}
// Do the copy
opMcopy(&pc, evmInterpreter, &ScopeContext{mem, stack, nil})
opMcopy(&pc, evm, &ScopeContext{mem, stack, nil})
want := common.FromHex(strings.ReplaceAll(tc.want, " ", ""))
if have := mem.store; !bytes.Equal(want, have) {
t.Errorf("case %d: \nwant: %#x\nhave: %#x\n", i, want, have)

View file

@ -23,8 +23,6 @@ import (
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/common/math"
"github.com/XinFinOrg/XDPoSChain/core/tracing"
"github.com/XinFinOrg/XDPoSChain/crypto"
"github.com/XinFinOrg/XDPoSChain/log"
"github.com/holiman/uint256"
)
@ -83,88 +81,27 @@ func (ctx *ScopeContext) CallInput() []byte {
return ctx.Contract.Input
}
// EVMInterpreter represents an EVM interpreter
type EVMInterpreter struct {
evm *EVM
table *JumpTable
hasher crypto.KeccakState // Keccak256 hasher instance shared across opcodes
hasherBuf common.Hash // Keccak256 hasher result array shared across opcodes
readOnly bool // Whether to throw on stateful modifications
returnData []byte // Last CALL's return data for subsequent reuse
}
// NewEVMInterpreter returns a new instance of the Interpreter.
func NewEVMInterpreter(evm *EVM) *EVMInterpreter {
// If jump table was not initialised we set the default one.
var table *JumpTable
switch {
case evm.chainRules.IsCancun:
table = &cancunInstructionSet
case evm.chainRules.IsEIP1559:
table = &eip1559InstructionSet
case evm.chainRules.IsShanghai:
table = &shanghaiInstructionSet
case evm.chainRules.IsMerge:
table = &mergeInstructionSet
case evm.chainRules.IsLondon:
table = &londonInstructionSet
case evm.chainRules.IsBerlin:
table = &berlinInstructionSet
case evm.chainRules.IsIstanbul:
table = &istanbulInstructionSet
case evm.chainRules.IsConstantinople:
table = &constantinopleInstructionSet
case evm.chainRules.IsByzantium:
table = &byzantiumInstructionSet
case evm.chainRules.IsEIP158:
table = &spuriousDragonInstructionSet
case evm.chainRules.IsEIP150:
table = &tangerineWhistleInstructionSet
case evm.chainRules.IsHomestead:
table = &homesteadInstructionSet
default:
table = &frontierInstructionSet
}
if len(evm.Config.ExtraEips) > 0 {
// Deep-copy jumptable to prevent modification of opcodes in other tables
table = copyJumpTable(table)
}
extraEips := make([]int, 0, len(evm.Config.ExtraEips))
for _, eip := range evm.Config.ExtraEips {
if err := EnableEIP(eip, table); err != nil {
// Disable it, so caller can check if it's activated or not
log.Error("EIP activation failed", "eip", eip, "error", err)
} else {
extraEips = append(extraEips, eip)
}
}
evm.Config.ExtraEips = extraEips
return &EVMInterpreter{evm: evm, table: table, hasher: crypto.NewKeccakState()}
}
// Run loops and evaluates the contract's code with the given input data and returns
// the return byte-slice and an error if one occurred.
//
// It's important to note that any errors returned by the interpreter should be
// considered a revert-and-consume-all-gas operation except for
// ErrExecutionReverted which means revert-and-keep-gas-left.
func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (ret []byte, err error) {
func (evm *EVM) Run(contract *Contract, input []byte, readOnly bool) (ret []byte, err error) {
// Increment the call depth which is restricted to 1024
in.evm.depth++
defer func() { in.evm.depth-- }()
evm.depth++
defer func() { evm.depth-- }()
// Make sure the readOnly is only set if we aren't in readOnly yet.
// This also makes sure that the readOnly flag isn't removed for child calls.
if readOnly && !in.readOnly {
in.readOnly = true
defer func() { in.readOnly = false }()
if readOnly && !evm.readOnly {
evm.readOnly = true
defer func() { evm.readOnly = false }()
}
// Reset the previous call's return data. It's unimportant to preserve the old buffer
// as every returning call will return new data anyway.
in.returnData = nil
evm.returnData = nil
// Don't bother with the execution if there's no code.
if len(contract.Code) == 0 {
@ -190,7 +127,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
gasCopy uint64 // for EVMLogger to log gas remaining before execution
logged bool // deferred EVMLogger should ignore already logged steps
res []byte // result of the opcode execution function
debug = in.evm.Config.Tracer != nil
debug = evm.Config.Tracer != nil
)
// Don't move this deferred function, it's placed before the OnOpcode-deferred method,
// so that it gets executed _after_: the OnOpcode needs the stacks before
@ -205,11 +142,11 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
if err == nil {
return
}
if !logged && in.evm.Config.Tracer.OnOpcode != nil {
in.evm.Config.Tracer.OnOpcode(pcCopy, byte(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err))
if !logged && evm.Config.Tracer.OnOpcode != nil {
evm.Config.Tracer.OnOpcode(pcCopy, byte(op), gasCopy, cost, callContext, evm.returnData, evm.depth, VMErrorFromErr(err))
}
if logged && in.evm.Config.Tracer.OnFault != nil {
in.evm.Config.Tracer.OnFault(pcCopy, byte(op), gasCopy, cost, callContext, in.evm.depth, VMErrorFromErr(err))
if logged && evm.Config.Tracer.OnFault != nil {
evm.Config.Tracer.OnFault(pcCopy, byte(op), gasCopy, cost, callContext, evm.depth, VMErrorFromErr(err))
}
}()
}
@ -226,7 +163,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
// Get the operation from the jump table and validate the stack to ensure there are
// enough stack items available to perform the operation.
op = contract.GetOp(pc)
operation := in.table[op]
operation := evm.table[op]
cost = operation.constantGas // For tracing
// Validate stack
if sLen := stack.len(); sLen < operation.minStack {
@ -234,7 +171,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
} else if sLen > operation.maxStack {
return nil, &ErrStackOverflow{stackLen: sLen, limit: operation.maxStack}
}
if !contract.UseGas(cost, in.evm.Config.Tracer, tracing.GasChangeIgnored) {
if !contract.UseGas(cost, evm.Config.Tracer, tracing.GasChangeIgnored) {
return nil, ErrOutOfGas
}
@ -259,22 +196,22 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
// Consume the gas and return an error if not enough gas is available.
// cost is explicitly set so that the capture state defer method can get the proper cost
var dynamicCost uint64
dynamicCost, err = operation.dynamicGas(in.evm, contract, stack, mem, memorySize)
dynamicCost, err = operation.dynamicGas(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) {
if !contract.UseGas(dynamicCost, evm.Config.Tracer, tracing.GasChangeIgnored) {
return nil, ErrOutOfGas
}
// Do tracing before memory expansion
if debug {
if in.evm.Config.Tracer.OnGasChange != nil {
in.evm.Config.Tracer.OnGasChange(gasCopy, gasCopy-cost, tracing.GasChangeCallOpCode)
if evm.Config.Tracer.OnGasChange != nil {
evm.Config.Tracer.OnGasChange(gasCopy, gasCopy-cost, tracing.GasChangeCallOpCode)
}
if in.evm.Config.Tracer.OnOpcode != nil {
in.evm.Config.Tracer.OnOpcode(pc, byte(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err))
if evm.Config.Tracer.OnOpcode != nil {
evm.Config.Tracer.OnOpcode(pc, byte(op), gasCopy, cost, callContext, evm.returnData, evm.depth, VMErrorFromErr(err))
logged = true
}
}
@ -282,17 +219,17 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
mem.Resize(memorySize)
}
} else if debug {
if in.evm.Config.Tracer.OnGasChange != nil {
in.evm.Config.Tracer.OnGasChange(gasCopy, gasCopy-cost, tracing.GasChangeCallOpCode)
if evm.Config.Tracer.OnGasChange != nil {
evm.Config.Tracer.OnGasChange(gasCopy, gasCopy-cost, tracing.GasChangeCallOpCode)
}
if in.evm.Config.Tracer.OnOpcode != nil {
in.evm.Config.Tracer.OnOpcode(pc, byte(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err))
if evm.Config.Tracer.OnOpcode != nil {
evm.Config.Tracer.OnOpcode(pc, byte(op), gasCopy, cost, callContext, evm.returnData, evm.depth, VMErrorFromErr(err))
logged = true
}
}
// execute the operation
res, err = operation.execute(&pc, in, callContext)
res, err = operation.execute(&pc, evm, callContext)
if err != nil {
break
}

View file

@ -23,7 +23,7 @@ import (
)
type (
executionFunc func(pc *uint64, interpreter *EVMInterpreter, callContext *ScopeContext) ([]byte, error)
executionFunc func(pc *uint64, evm *EVM, callContext *ScopeContext) ([]byte, error)
gasFunc func(*EVM, *Contract, *Stack, *Memory, uint64) (uint64, error) // last parameter is the requested memory size as a uint64
// memorySizeFunc returns the required size, and whether the operation overflowed a uint64
memorySizeFunc func(*Stack) (size uint64, overflow bool)

View file

@ -63,7 +63,7 @@ func testCtx() *vmContext {
func runTrace(tracer *tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainConfig, contractCode []byte) (json.RawMessage, error) {
var (
env = vm.NewEVM(vmctx.ctx, vmctx.txContext, &dummyStatedb{}, nil, chaincfg, vm.Config{Tracer: tracer.Hooks})
evm = vm.NewEVM(vmctx.ctx, vmctx.txContext, &dummyStatedb{}, nil, chaincfg, vm.Config{Tracer: tracer.Hooks})
gasLimit uint64 = 31000
startGas uint64 = 10000
value = big.NewInt(0)
@ -74,9 +74,9 @@ func runTrace(tracer *tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainCo
contract.Code = contractCode
}
tracer.OnTxStart(env.GetVMContext(), types.NewTx(&types.LegacyTx{Gas: gasLimit}), contract.Caller())
tracer.OnTxStart(evm.GetVMContext(), types.NewTx(&types.LegacyTx{Gas: gasLimit}), contract.Caller())
tracer.OnEnter(0, byte(vm.CALL), contract.Caller(), contract.Address(), []byte{}, startGas, value)
ret, err := env.Interpreter().Run(contract, []byte{}, false)
ret, err := evm.Run(contract, []byte{}, false)
tracer.OnExit(0, ret, startGas-contract.Gas, err, true)
// Rest gas assumes no refund
tracer.OnTxEnd(&types.Receipt{GasUsed: gasLimit - contract.Gas}, nil)

View file

@ -55,13 +55,13 @@ func (*dummyStatedb) SetState(_ common.Address, _ common.Hash, _ common.Hash) {}
func TestStoreCapture(t *testing.T) {
var (
logger = NewStructLogger(nil)
env = vm.NewEVM(vm.BlockContext{}, vm.TxContext{}, &dummyStatedb{}, nil, params.TestChainConfig, vm.Config{Tracer: logger.Hooks()})
evm = vm.NewEVM(vm.BlockContext{}, vm.TxContext{}, &dummyStatedb{}, nil, params.TestChainConfig, vm.Config{Tracer: logger.Hooks()})
contract = vm.NewContract(&dummyContractRef{}, &dummyContractRef{}, new(big.Int), 100000)
)
contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x0, byte(vm.SSTORE)}
var index common.Hash
logger.OnTxStart(env.GetVMContext(), nil, common.Address{})
_, err := env.Interpreter().Run(contract, []byte{}, false)
logger.OnTxStart(evm.GetVMContext(), nil, common.Address{})
_, err := evm.Run(contract, []byte{}, false)
if err != nil {
t.Fatal(err)
}