mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-05-24 08:49:29 +00:00
core/vm: fold EVMInterpreter into EVM (#32352)
The separation serves no purpose atm, and the circular dependency that EVM and EVMInterpreter had was begging for them to be merged.
This commit is contained in:
parent
888b71b3cf
commit
c3ef6c77c2
8 changed files with 316 additions and 335 deletions
|
|
@ -89,8 +89,8 @@ func enable1884(jt *JumpTable) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSelfBalance(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opSelfBalance(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address())
|
balance := evm.StateDB.GetBalance(scope.Contract.Address())
|
||||||
scope.Stack.push(balance)
|
scope.Stack.push(balance)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
@ -108,8 +108,8 @@ func enable1344(jt *JumpTable) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// opChainID implements CHAINID opcode
|
// opChainID implements CHAINID opcode
|
||||||
func opChainID(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opChainID(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
chainId, _ := uint256.FromBig(interpreter.evm.chainConfig.ChainID)
|
chainId, _ := uint256.FromBig(evm.chainConfig.ChainID)
|
||||||
scope.Stack.push(chainId)
|
scope.Stack.push(chainId)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
@ -199,28 +199,28 @@ func enable1153(jt *JumpTable) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// opTload implements TLOAD opcode
|
// 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()
|
loc := scope.Stack.peek()
|
||||||
hash := common.Hash(loc.Bytes32())
|
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())
|
loc.SetBytes(val.Bytes())
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// opTstore implements TSTORE opcode
|
// opTstore implements TSTORE opcode
|
||||||
func opTstore(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opTstore(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
if interpreter.readOnly {
|
if evm.readOnly {
|
||||||
return nil, ErrWriteProtection
|
return nil, ErrWriteProtection
|
||||||
}
|
}
|
||||||
loc := scope.Stack.pop()
|
loc := scope.Stack.pop()
|
||||||
val := 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
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// opBaseFee implements BASEFEE opcode
|
// opBaseFee implements BASEFEE opcode
|
||||||
func opBaseFee(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opBaseFee(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
baseFee, _ := uint256.FromBig(interpreter.evm.Context.BaseFee)
|
baseFee, _ := uint256.FromBig(evm.Context.BaseFee)
|
||||||
scope.Stack.push(baseFee)
|
scope.Stack.push(baseFee)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
@ -237,7 +237,7 @@ func enable3855(jt *JumpTable) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// opPush0 implements the PUSH0 opcode
|
// opPush0 implements the PUSH0 opcode
|
||||||
func opPush0(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opPush0(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
scope.Stack.push(new(uint256.Int))
|
scope.Stack.push(new(uint256.Int))
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
@ -263,7 +263,7 @@ func enable5656(jt *JumpTable) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// opMcopy implements the MCOPY opcode (https://eips.ethereum.org/EIPS/eip-5656)
|
// 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 (
|
var (
|
||||||
dst = scope.Stack.pop()
|
dst = scope.Stack.pop()
|
||||||
src = scope.Stack.pop()
|
src = scope.Stack.pop()
|
||||||
|
|
@ -276,10 +276,10 @@ func opMcopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by
|
||||||
}
|
}
|
||||||
|
|
||||||
// opBlobHash implements the BLOBHASH opcode
|
// 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()
|
index := scope.Stack.peek()
|
||||||
if index.LtUint64(uint64(len(interpreter.evm.TxContext.BlobHashes))) {
|
if index.LtUint64(uint64(len(evm.TxContext.BlobHashes))) {
|
||||||
blobHash := interpreter.evm.TxContext.BlobHashes[index.Uint64()]
|
blobHash := evm.TxContext.BlobHashes[index.Uint64()]
|
||||||
index.SetBytes32(blobHash[:])
|
index.SetBytes32(blobHash[:])
|
||||||
} else {
|
} else {
|
||||||
index.Clear()
|
index.Clear()
|
||||||
|
|
@ -288,14 +288,14 @@ func opBlobHash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([
|
||||||
}
|
}
|
||||||
|
|
||||||
// opBlobBaseFee implements BLOBBASEFEE opcode
|
// 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, _ := uint256.FromBig(interpreter.evm.Context.BlobBaseFee)
|
blobBaseFee, _ := uint256.FromBig(evm.Context.BlobBaseFee)
|
||||||
scope.Stack.push(blobBaseFee)
|
scope.Stack.push(blobBaseFee)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// opCLZ implements the CLZ opcode (count leading zero bytes)
|
// opCLZ implements the CLZ opcode (count leading zero bytes)
|
||||||
func opCLZ(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opCLZ(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
x := scope.Stack.peek()
|
x := scope.Stack.peek()
|
||||||
x.SetUint64(256 - uint64(x.BitLen()))
|
x.SetUint64(256 - uint64(x.BitLen()))
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
|
@ -342,7 +342,7 @@ func enable6780(jt *JumpTable) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func opExtCodeCopyEIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opExtCodeCopyEIP4762(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
var (
|
var (
|
||||||
stack = scope.Stack
|
stack = scope.Stack
|
||||||
a = stack.pop()
|
a = stack.pop()
|
||||||
|
|
@ -355,10 +355,10 @@ func opExtCodeCopyEIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeC
|
||||||
uint64CodeOffset = math.MaxUint64
|
uint64CodeOffset = math.MaxUint64
|
||||||
}
|
}
|
||||||
addr := common.Address(a.Bytes20())
|
addr := common.Address(a.Bytes20())
|
||||||
code := interpreter.evm.StateDB.GetCode(addr)
|
code := evm.StateDB.GetCode(addr)
|
||||||
paddedCodeCopy, copyOffset, nonPaddedCopyLength := getDataAndAdjustedBounds(code, uint64CodeOffset, length.Uint64())
|
paddedCodeCopy, copyOffset, nonPaddedCopyLength := getDataAndAdjustedBounds(code, uint64CodeOffset, length.Uint64())
|
||||||
consumed, wanted := interpreter.evm.AccessEvents.CodeChunksRangeGas(addr, copyOffset, nonPaddedCopyLength, uint64(len(code)), false, scope.Contract.Gas)
|
consumed, wanted := evm.AccessEvents.CodeChunksRangeGas(addr, copyOffset, nonPaddedCopyLength, uint64(len(code)), false, scope.Contract.Gas)
|
||||||
scope.Contract.UseGas(consumed, interpreter.evm.Config.Tracer, tracing.GasChangeUnspecified)
|
scope.Contract.UseGas(consumed, evm.Config.Tracer, tracing.GasChangeUnspecified)
|
||||||
if consumed < wanted {
|
if consumed < wanted {
|
||||||
return nil, ErrOutOfGas
|
return nil, ErrOutOfGas
|
||||||
}
|
}
|
||||||
|
|
@ -370,7 +370,7 @@ func opExtCodeCopyEIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeC
|
||||||
// opPush1EIP4762 handles the special case of PUSH1 opcode for EIP-4762, which
|
// opPush1EIP4762 handles the special case of PUSH1 opcode for EIP-4762, which
|
||||||
// need not worry about the adjusted bound logic when adding the PUSHDATA to
|
// need not worry about the adjusted bound logic when adding the PUSHDATA to
|
||||||
// the list of access events.
|
// the list of access events.
|
||||||
func opPush1EIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opPush1EIP4762(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
var (
|
var (
|
||||||
codeLen = uint64(len(scope.Contract.Code))
|
codeLen = uint64(len(scope.Contract.Code))
|
||||||
integer = new(uint256.Int)
|
integer = new(uint256.Int)
|
||||||
|
|
@ -383,8 +383,8 @@ func opPush1EIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext
|
||||||
// touch next chunk if PUSH1 is at the boundary. if so, *pc has
|
// touch next chunk if PUSH1 is at the boundary. if so, *pc has
|
||||||
// advanced past this boundary.
|
// advanced past this boundary.
|
||||||
contractAddr := scope.Contract.Address()
|
contractAddr := scope.Contract.Address()
|
||||||
consumed, wanted := interpreter.evm.AccessEvents.CodeChunksRangeGas(contractAddr, *pc+1, uint64(1), uint64(len(scope.Contract.Code)), false, scope.Contract.Gas)
|
consumed, wanted := evm.AccessEvents.CodeChunksRangeGas(contractAddr, *pc+1, uint64(1), uint64(len(scope.Contract.Code)), false, scope.Contract.Gas)
|
||||||
scope.Contract.UseGas(wanted, interpreter.evm.Config.Tracer, tracing.GasChangeUnspecified)
|
scope.Contract.UseGas(wanted, evm.Config.Tracer, tracing.GasChangeUnspecified)
|
||||||
if consumed < wanted {
|
if consumed < wanted {
|
||||||
return nil, ErrOutOfGas
|
return nil, ErrOutOfGas
|
||||||
}
|
}
|
||||||
|
|
@ -396,7 +396,7 @@ func opPush1EIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext
|
||||||
}
|
}
|
||||||
|
|
||||||
func makePushEIP4762(size uint64, pushByteSize int) executionFunc {
|
func makePushEIP4762(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 (
|
var (
|
||||||
codeLen = len(scope.Contract.Code)
|
codeLen = len(scope.Contract.Code)
|
||||||
start = min(codeLen, int(*pc+1))
|
start = min(codeLen, int(*pc+1))
|
||||||
|
|
@ -411,8 +411,8 @@ func makePushEIP4762(size uint64, pushByteSize int) executionFunc {
|
||||||
|
|
||||||
if !scope.Contract.IsDeployment && !scope.Contract.IsSystemCall {
|
if !scope.Contract.IsDeployment && !scope.Contract.IsSystemCall {
|
||||||
contractAddr := scope.Contract.Address()
|
contractAddr := scope.Contract.Address()
|
||||||
consumed, wanted := interpreter.evm.AccessEvents.CodeChunksRangeGas(contractAddr, uint64(start), uint64(pushByteSize), uint64(len(scope.Contract.Code)), false, scope.Contract.Gas)
|
consumed, wanted := evm.AccessEvents.CodeChunksRangeGas(contractAddr, uint64(start), uint64(pushByteSize), uint64(len(scope.Contract.Code)), false, scope.Contract.Gas)
|
||||||
scope.Contract.UseGas(consumed, interpreter.evm.Config.Tracer, tracing.GasChangeUnspecified)
|
scope.Contract.UseGas(consumed, evm.Config.Tracer, tracing.GasChangeUnspecified)
|
||||||
if consumed < wanted {
|
if consumed < wanted {
|
||||||
return nil, ErrOutOfGas
|
return nil, ErrOutOfGas
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/tracing"
|
"github.com/ethereum/go-ethereum/core/tracing"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
@ -95,6 +96,9 @@ type EVM struct {
|
||||||
// StateDB gives access to the underlying state
|
// StateDB gives access to the underlying state
|
||||||
StateDB StateDB
|
StateDB StateDB
|
||||||
|
|
||||||
|
// table holds the opcode specific handlers
|
||||||
|
table *JumpTable
|
||||||
|
|
||||||
// depth is the current call stack
|
// depth is the current call stack
|
||||||
depth int
|
depth int
|
||||||
|
|
||||||
|
|
@ -107,10 +111,6 @@ type EVM struct {
|
||||||
// virtual machine configuration options used to initialise the evm
|
// virtual machine configuration options used to initialise the evm
|
||||||
Config Config
|
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 is used to abort the EVM calling operations
|
||||||
abort atomic.Bool
|
abort atomic.Bool
|
||||||
|
|
||||||
|
|
@ -124,6 +124,12 @@ type EVM struct {
|
||||||
|
|
||||||
// jumpDests stores results of JUMPDEST analysis.
|
// jumpDests stores results of JUMPDEST analysis.
|
||||||
jumpDests JumpDestCache
|
jumpDests JumpDestCache
|
||||||
|
|
||||||
|
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 constructs an EVM instance with the supplied block context, state
|
// NewEVM constructs an EVM instance with the supplied block context, state
|
||||||
|
|
@ -138,9 +144,57 @@ func NewEVM(blockCtx BlockContext, statedb StateDB, chainConfig *params.ChainCon
|
||||||
chainConfig: chainConfig,
|
chainConfig: chainConfig,
|
||||||
chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time),
|
chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time),
|
||||||
jumpDests: newMapJumpDests(),
|
jumpDests: newMapJumpDests(),
|
||||||
|
hasher: crypto.NewKeccakState(),
|
||||||
}
|
}
|
||||||
evm.precompiles = activePrecompiledContracts(evm.chainRules)
|
evm.precompiles = activePrecompiledContracts(evm.chainRules)
|
||||||
evm.interpreter = NewEVMInterpreter(evm)
|
|
||||||
|
switch {
|
||||||
|
case evm.chainRules.IsOsaka:
|
||||||
|
evm.table = &osakaInstructionSet
|
||||||
|
case evm.chainRules.IsVerkle:
|
||||||
|
// TODO replace with proper instruction set when fork is specified
|
||||||
|
evm.table = &verkleInstructionSet
|
||||||
|
case evm.chainRules.IsPrague:
|
||||||
|
evm.table = &pragueInstructionSet
|
||||||
|
case evm.chainRules.IsCancun:
|
||||||
|
evm.table = &cancunInstructionSet
|
||||||
|
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
|
||||||
|
}
|
||||||
|
var extraEips []int
|
||||||
|
if len(evm.Config.ExtraEips) > 0 {
|
||||||
|
// Deep-copy jumptable to prevent modification of opcodes in other tables
|
||||||
|
evm.table = copyJumpTable(evm.table)
|
||||||
|
}
|
||||||
|
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
|
||||||
return evm
|
return evm
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -176,11 +230,6 @@ func (evm *EVM) Cancelled() bool {
|
||||||
return evm.abort.Load()
|
return evm.abort.Load()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interpreter returns the current interpreter
|
|
||||||
func (evm *EVM) Interpreter() *EVMInterpreter {
|
|
||||||
return evm.interpreter
|
|
||||||
}
|
|
||||||
|
|
||||||
func isSystemCall(caller common.Address) bool {
|
func isSystemCall(caller common.Address) bool {
|
||||||
return caller == params.SystemAddress
|
return caller == params.SystemAddress
|
||||||
}
|
}
|
||||||
|
|
@ -245,7 +294,7 @@ func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, g
|
||||||
contract := NewContract(caller, addr, value, gas, evm.jumpDests)
|
contract := NewContract(caller, addr, value, gas, evm.jumpDests)
|
||||||
contract.IsSystemCall = isSystemCall(caller)
|
contract.IsSystemCall = isSystemCall(caller)
|
||||||
contract.SetCallCode(evm.resolveCodeHash(addr), code)
|
contract.SetCallCode(evm.resolveCodeHash(addr), code)
|
||||||
ret, err = evm.interpreter.Run(contract, input, false)
|
ret, err = evm.Run(contract, input, false)
|
||||||
gas = contract.Gas
|
gas = contract.Gas
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -304,7 +353,7 @@ func (evm *EVM) CallCode(caller common.Address, addr common.Address, input []byt
|
||||||
// The contract is a scoped environment for this execution context only.
|
// The contract is a scoped environment for this execution context only.
|
||||||
contract := NewContract(caller, caller, value, gas, evm.jumpDests)
|
contract := NewContract(caller, caller, value, gas, evm.jumpDests)
|
||||||
contract.SetCallCode(evm.resolveCodeHash(addr), evm.resolveCode(addr))
|
contract.SetCallCode(evm.resolveCodeHash(addr), evm.resolveCode(addr))
|
||||||
ret, err = evm.interpreter.Run(contract, input, false)
|
ret, err = evm.Run(contract, input, false)
|
||||||
gas = contract.Gas
|
gas = contract.Gas
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -348,7 +397,7 @@ func (evm *EVM) DelegateCall(originCaller common.Address, caller common.Address,
|
||||||
// Note: The value refers to the original value from the parent call.
|
// Note: The value refers to the original value from the parent call.
|
||||||
contract := NewContract(originCaller, caller, value, gas, evm.jumpDests)
|
contract := NewContract(originCaller, caller, value, gas, evm.jumpDests)
|
||||||
contract.SetCallCode(evm.resolveCodeHash(addr), evm.resolveCode(addr))
|
contract.SetCallCode(evm.resolveCodeHash(addr), evm.resolveCode(addr))
|
||||||
ret, err = evm.interpreter.Run(contract, input, false)
|
ret, err = evm.Run(contract, input, false)
|
||||||
gas = contract.Gas
|
gas = contract.Gas
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -403,7 +452,7 @@ func (evm *EVM) StaticCall(caller common.Address, addr common.Address, input []b
|
||||||
// When an error was returned by the EVM or when setting the creation code
|
// When an error was returned by the EVM or when setting the creation code
|
||||||
// above we revert to the snapshot and consume any gas remaining. Additionally
|
// 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.
|
// when we're in Homestead this also counts for code storage gas errors.
|
||||||
ret, err = evm.interpreter.Run(contract, input, true)
|
ret, err = evm.Run(contract, input, true)
|
||||||
gas = contract.Gas
|
gas = contract.Gas
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -524,7 +573,7 @@ func (evm *EVM) create(caller common.Address, code []byte, gas uint64, value *ui
|
||||||
// initNewContract runs a new contract's creation code, performs checks on the
|
// initNewContract runs a new contract's creation code, performs checks on the
|
||||||
// resulting code that is to be deployed, and consumes necessary gas.
|
// resulting code that is to be deployed, and consumes necessary gas.
|
||||||
func (evm *EVM) initNewContract(contract *Contract, address common.Address) ([]byte, error) {
|
func (evm *EVM) initNewContract(contract *Contract, address common.Address) ([]byte, error) {
|
||||||
ret, err := evm.interpreter.Run(contract, nil, false)
|
ret, err := evm.Run(contract, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ret, err
|
return ret, err
|
||||||
}
|
}
|
||||||
|
|
@ -567,7 +616,7 @@ func (evm *EVM) Create(caller common.Address, code []byte, gas uint64, value *ui
|
||||||
// The different between Create2 with Create is Create2 uses keccak256(0xff ++ msg.sender ++ salt ++ keccak256(init_code))[12:]
|
// The different between Create2 with Create is Create2 uses keccak256(0xff ++ msg.sender ++ salt ++ keccak256(init_code))[12:]
|
||||||
// instead of the usual sender-and-nonce-hash as the address where the contract is initialized at.
|
// instead of the usual sender-and-nonce-hash as the address where the contract is initialized at.
|
||||||
func (evm *EVM) Create2(caller common.Address, code []byte, gas uint64, endowment *uint256.Int, salt *uint256.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {
|
func (evm *EVM) Create2(caller common.Address, code []byte, gas uint64, endowment *uint256.Int, salt *uint256.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {
|
||||||
inithash := crypto.HashData(evm.interpreter.hasher, code)
|
inithash := crypto.HashData(evm.hasher, code)
|
||||||
contractAddr = crypto.CreateAddress2(caller, salt.Bytes32(), inithash[:])
|
contractAddr = crypto.CreateAddress2(caller, salt.Bytes32(), inithash[:])
|
||||||
return evm.create(caller, code, gas, endowment, contractAddr, CREATE2)
|
return evm.create(caller, code, gas, endowment, contractAddr, CREATE2)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,67 +26,67 @@ import (
|
||||||
"github.com/holiman/uint256"
|
"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()
|
x, y := scope.Stack.pop(), scope.Stack.peek()
|
||||||
y.Add(&x, y)
|
y.Add(&x, y)
|
||||||
return nil, nil
|
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()
|
x, y := scope.Stack.pop(), scope.Stack.peek()
|
||||||
y.Sub(&x, y)
|
y.Sub(&x, y)
|
||||||
return nil, nil
|
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()
|
x, y := scope.Stack.pop(), scope.Stack.peek()
|
||||||
y.Mul(&x, y)
|
y.Mul(&x, y)
|
||||||
return nil, nil
|
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()
|
x, y := scope.Stack.pop(), scope.Stack.peek()
|
||||||
y.Div(&x, y)
|
y.Div(&x, y)
|
||||||
return nil, nil
|
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()
|
x, y := scope.Stack.pop(), scope.Stack.peek()
|
||||||
y.SDiv(&x, y)
|
y.SDiv(&x, y)
|
||||||
return nil, nil
|
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()
|
x, y := scope.Stack.pop(), scope.Stack.peek()
|
||||||
y.Mod(&x, y)
|
y.Mod(&x, y)
|
||||||
return nil, nil
|
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()
|
x, y := scope.Stack.pop(), scope.Stack.peek()
|
||||||
y.SMod(&x, y)
|
y.SMod(&x, y)
|
||||||
return nil, nil
|
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()
|
base, exponent := scope.Stack.pop(), scope.Stack.peek()
|
||||||
exponent.Exp(&base, exponent)
|
exponent.Exp(&base, exponent)
|
||||||
return nil, nil
|
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()
|
back, num := scope.Stack.pop(), scope.Stack.peek()
|
||||||
num.ExtendSign(num, &back)
|
num.ExtendSign(num, &back)
|
||||||
return nil, nil
|
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 := scope.Stack.peek()
|
||||||
x.Not(x)
|
x.Not(x)
|
||||||
return nil, nil
|
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()
|
x, y := scope.Stack.pop(), scope.Stack.peek()
|
||||||
if x.Lt(y) {
|
if x.Lt(y) {
|
||||||
y.SetOne()
|
y.SetOne()
|
||||||
|
|
@ -96,7 +96,7 @@ func opLt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte,
|
||||||
return nil, nil
|
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()
|
x, y := scope.Stack.pop(), scope.Stack.peek()
|
||||||
if x.Gt(y) {
|
if x.Gt(y) {
|
||||||
y.SetOne()
|
y.SetOne()
|
||||||
|
|
@ -106,7 +106,7 @@ func opGt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte,
|
||||||
return nil, nil
|
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()
|
x, y := scope.Stack.pop(), scope.Stack.peek()
|
||||||
if x.Slt(y) {
|
if x.Slt(y) {
|
||||||
y.SetOne()
|
y.SetOne()
|
||||||
|
|
@ -116,7 +116,7 @@ func opSlt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte
|
||||||
return nil, nil
|
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()
|
x, y := scope.Stack.pop(), scope.Stack.peek()
|
||||||
if x.Sgt(y) {
|
if x.Sgt(y) {
|
||||||
y.SetOne()
|
y.SetOne()
|
||||||
|
|
@ -126,7 +126,7 @@ func opSgt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte
|
||||||
return nil, nil
|
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()
|
x, y := scope.Stack.pop(), scope.Stack.peek()
|
||||||
if x.Eq(y) {
|
if x.Eq(y) {
|
||||||
y.SetOne()
|
y.SetOne()
|
||||||
|
|
@ -136,7 +136,7 @@ func opEq(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte,
|
||||||
return nil, nil
|
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()
|
x := scope.Stack.peek()
|
||||||
if x.IsZero() {
|
if x.IsZero() {
|
||||||
x.SetOne()
|
x.SetOne()
|
||||||
|
|
@ -146,37 +146,37 @@ func opIszero(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
|
||||||
return nil, nil
|
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()
|
x, y := scope.Stack.pop(), scope.Stack.peek()
|
||||||
y.And(&x, y)
|
y.And(&x, y)
|
||||||
return nil, nil
|
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()
|
x, y := scope.Stack.pop(), scope.Stack.peek()
|
||||||
y.Or(&x, y)
|
y.Or(&x, y)
|
||||||
return nil, nil
|
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()
|
x, y := scope.Stack.pop(), scope.Stack.peek()
|
||||||
y.Xor(&x, y)
|
y.Xor(&x, y)
|
||||||
return nil, nil
|
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()
|
th, val := scope.Stack.pop(), scope.Stack.peek()
|
||||||
val.Byte(&th)
|
val.Byte(&th)
|
||||||
return nil, nil
|
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()
|
x, y, z := scope.Stack.pop(), scope.Stack.pop(), scope.Stack.peek()
|
||||||
z.AddMod(&x, &y, z)
|
z.AddMod(&x, &y, z)
|
||||||
return nil, nil
|
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()
|
x, y, z := scope.Stack.pop(), scope.Stack.pop(), scope.Stack.peek()
|
||||||
z.MulMod(&x, &y, z)
|
z.MulMod(&x, &y, z)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
|
@ -185,7 +185,7 @@ func opMulmod(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
|
||||||
// opSHL implements Shift Left
|
// opSHL implements Shift Left
|
||||||
// The SHL instruction (shift left) pops 2 values from the stack, first arg1 and then arg2,
|
// 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.
|
// 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
|
// 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()
|
shift, value := scope.Stack.pop(), scope.Stack.peek()
|
||||||
if shift.LtUint64(256) {
|
if shift.LtUint64(256) {
|
||||||
|
|
@ -199,7 +199,7 @@ func opSHL(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte
|
||||||
// opSHR implements Logical Shift Right
|
// opSHR implements Logical Shift Right
|
||||||
// The SHR instruction (logical shift right) pops 2 values from the stack, first arg1 and then arg2,
|
// 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.
|
// 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
|
// 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()
|
shift, value := scope.Stack.pop(), scope.Stack.peek()
|
||||||
if shift.LtUint64(256) {
|
if shift.LtUint64(256) {
|
||||||
|
|
@ -213,7 +213,7 @@ func opSHR(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte
|
||||||
// opSAR implements Arithmetic Shift Right
|
// opSAR implements Arithmetic Shift Right
|
||||||
// The SAR instruction (arithmetic shift right) pops 2 values from the stack, first arg1 and then arg2,
|
// 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.
|
// 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()
|
shift, value := scope.Stack.pop(), scope.Stack.peek()
|
||||||
if shift.GtUint64(256) {
|
if shift.GtUint64(256) {
|
||||||
if value.Sign() >= 0 {
|
if value.Sign() >= 0 {
|
||||||
|
|
@ -229,50 +229,49 @@ func opSAR(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte
|
||||||
return nil, nil
|
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()
|
offset, size := scope.Stack.pop(), scope.Stack.peek()
|
||||||
data := scope.Memory.GetPtr(offset.Uint64(), size.Uint64())
|
data := scope.Memory.GetPtr(offset.Uint64(), size.Uint64())
|
||||||
|
|
||||||
interpreter.hasher.Reset()
|
evm.hasher.Reset()
|
||||||
interpreter.hasher.Write(data)
|
evm.hasher.Write(data)
|
||||||
interpreter.hasher.Read(interpreter.hasherBuf[:])
|
evm.hasher.Read(evm.hasherBuf[:])
|
||||||
|
|
||||||
evm := interpreter.evm
|
|
||||||
if evm.Config.EnablePreimageRecording {
|
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
|
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()))
|
scope.Stack.push(new(uint256.Int).SetBytes(scope.Contract.Address().Bytes()))
|
||||||
return nil, nil
|
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()
|
slot := scope.Stack.peek()
|
||||||
address := common.Address(slot.Bytes20())
|
address := common.Address(slot.Bytes20())
|
||||||
slot.Set(interpreter.evm.StateDB.GetBalance(address))
|
slot.Set(evm.StateDB.GetBalance(address))
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opOrigin(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opOrigin(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
scope.Stack.push(new(uint256.Int).SetBytes(interpreter.evm.Origin.Bytes()))
|
scope.Stack.push(new(uint256.Int).SetBytes(evm.Origin.Bytes()))
|
||||||
return nil, nil
|
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()))
|
scope.Stack.push(new(uint256.Int).SetBytes(scope.Contract.Caller().Bytes()))
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opCallValue(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opCallValue(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
scope.Stack.push(scope.Contract.value)
|
scope.Stack.push(scope.Contract.value)
|
||||||
return nil, nil
|
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()
|
x := scope.Stack.peek()
|
||||||
if offset, overflow := x.Uint64WithOverflow(); !overflow {
|
if offset, overflow := x.Uint64WithOverflow(); !overflow {
|
||||||
data := getData(scope.Contract.Input, offset, 32)
|
data := getData(scope.Contract.Input, offset, 32)
|
||||||
|
|
@ -283,12 +282,12 @@ func opCallDataLoad(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext
|
||||||
return nil, nil
|
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))))
|
scope.Stack.push(new(uint256.Int).SetUint64(uint64(len(scope.Contract.Input))))
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opCallDataCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opCallDataCopy(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
var (
|
var (
|
||||||
memOffset = scope.Stack.pop()
|
memOffset = scope.Stack.pop()
|
||||||
dataOffset = scope.Stack.pop()
|
dataOffset = scope.Stack.pop()
|
||||||
|
|
@ -306,12 +305,12 @@ func opCallDataCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opReturnDataSize(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opReturnDataSize(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
scope.Stack.push(new(uint256.Int).SetUint64(uint64(len(interpreter.returnData))))
|
scope.Stack.push(new(uint256.Int).SetUint64(uint64(len(evm.returnData))))
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opReturnDataCopy(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
var (
|
var (
|
||||||
memOffset = scope.Stack.pop()
|
memOffset = scope.Stack.pop()
|
||||||
dataOffset = scope.Stack.pop()
|
dataOffset = scope.Stack.pop()
|
||||||
|
|
@ -326,25 +325,25 @@ func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeConte
|
||||||
var end = dataOffset
|
var end = dataOffset
|
||||||
end.Add(&dataOffset, &length)
|
end.Add(&dataOffset, &length)
|
||||||
end64, overflow := end.Uint64WithOverflow()
|
end64, overflow := end.Uint64WithOverflow()
|
||||||
if overflow || uint64(len(interpreter.returnData)) < end64 {
|
if overflow || uint64(len(evm.returnData)) < end64 {
|
||||||
return nil, ErrReturnDataOutOfBounds
|
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
|
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 := scope.Stack.peek()
|
||||||
slot.SetUint64(uint64(interpreter.evm.StateDB.GetCodeSize(slot.Bytes20())))
|
slot.SetUint64(uint64(evm.StateDB.GetCodeSize(slot.Bytes20())))
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opCodeSize(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opCodeSize(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
scope.Stack.push(new(uint256.Int).SetUint64(uint64(len(scope.Contract.Code))))
|
scope.Stack.push(new(uint256.Int).SetUint64(uint64(len(scope.Contract.Code))))
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opCodeCopy(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
var (
|
var (
|
||||||
memOffset = scope.Stack.pop()
|
memOffset = scope.Stack.pop()
|
||||||
codeOffset = scope.Stack.pop()
|
codeOffset = scope.Stack.pop()
|
||||||
|
|
@ -360,7 +359,7 @@ func opCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opExtCodeCopy(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
var (
|
var (
|
||||||
stack = scope.Stack
|
stack = scope.Stack
|
||||||
a = stack.pop()
|
a = stack.pop()
|
||||||
|
|
@ -373,7 +372,7 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
|
||||||
uint64CodeOffset = math.MaxUint64
|
uint64CodeOffset = math.MaxUint64
|
||||||
}
|
}
|
||||||
addr := common.Address(a.Bytes20())
|
addr := common.Address(a.Bytes20())
|
||||||
code := interpreter.evm.StateDB.GetCode(addr)
|
code := evm.StateDB.GetCode(addr)
|
||||||
codeCopy := getData(code, uint64CodeOffset, length.Uint64())
|
codeCopy := getData(code, uint64CodeOffset, length.Uint64())
|
||||||
scope.Memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy)
|
scope.Memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy)
|
||||||
|
|
||||||
|
|
@ -406,24 +405,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
|
// 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.
|
// 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()
|
slot := scope.Stack.peek()
|
||||||
address := common.Address(slot.Bytes20())
|
address := common.Address(slot.Bytes20())
|
||||||
if interpreter.evm.StateDB.Empty(address) {
|
if evm.StateDB.Empty(address) {
|
||||||
slot.Clear()
|
slot.Clear()
|
||||||
} else {
|
} else {
|
||||||
slot.SetBytes(interpreter.evm.StateDB.GetCodeHash(address).Bytes())
|
slot.SetBytes(evm.StateDB.GetCodeHash(address).Bytes())
|
||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opGasprice(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opGasprice(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
v, _ := uint256.FromBig(interpreter.evm.GasPrice)
|
v, _ := uint256.FromBig(evm.GasPrice)
|
||||||
scope.Stack.push(v)
|
scope.Stack.push(v)
|
||||||
return nil, nil
|
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()
|
num := scope.Stack.peek()
|
||||||
num64, overflow := num.Uint64WithOverflow()
|
num64, overflow := num.Uint64WithOverflow()
|
||||||
if overflow {
|
if overflow {
|
||||||
|
|
@ -432,18 +431,18 @@ func opBlockhash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) (
|
||||||
}
|
}
|
||||||
|
|
||||||
var upper, lower uint64
|
var upper, lower uint64
|
||||||
upper = interpreter.evm.Context.BlockNumber.Uint64()
|
upper = evm.Context.BlockNumber.Uint64()
|
||||||
if upper < 257 {
|
if upper < 257 {
|
||||||
lower = 0
|
lower = 0
|
||||||
} else {
|
} else {
|
||||||
lower = upper - 256
|
lower = upper - 256
|
||||||
}
|
}
|
||||||
if num64 >= lower && num64 < upper {
|
if num64 >= lower && num64 < upper {
|
||||||
res := interpreter.evm.Context.GetHash(num64)
|
res := evm.Context.GetHash(num64)
|
||||||
if witness := interpreter.evm.StateDB.Witness(); witness != nil {
|
if witness := evm.StateDB.Witness(); witness != nil {
|
||||||
witness.AddBlockHash(num64)
|
witness.AddBlockHash(num64)
|
||||||
}
|
}
|
||||||
if tracer := interpreter.evm.Config.Tracer; tracer != nil && tracer.OnBlockHashRead != nil {
|
if tracer := evm.Config.Tracer; tracer != nil && tracer.OnBlockHashRead != nil {
|
||||||
tracer.OnBlockHashRead(num64, res)
|
tracer.OnBlockHashRead(num64, res)
|
||||||
}
|
}
|
||||||
num.SetBytes(res[:])
|
num.SetBytes(res[:])
|
||||||
|
|
@ -453,83 +452,83 @@ func opBlockhash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) (
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opCoinbase(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opCoinbase(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
scope.Stack.push(new(uint256.Int).SetBytes(interpreter.evm.Context.Coinbase.Bytes()))
|
scope.Stack.push(new(uint256.Int).SetBytes(evm.Context.Coinbase.Bytes()))
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opTimestamp(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opTimestamp(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
scope.Stack.push(new(uint256.Int).SetUint64(interpreter.evm.Context.Time))
|
scope.Stack.push(new(uint256.Int).SetUint64(evm.Context.Time))
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opNumber(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opNumber(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
v, _ := uint256.FromBig(interpreter.evm.Context.BlockNumber)
|
v, _ := uint256.FromBig(evm.Context.BlockNumber)
|
||||||
scope.Stack.push(v)
|
scope.Stack.push(v)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opDifficulty(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opDifficulty(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
v, _ := uint256.FromBig(interpreter.evm.Context.Difficulty)
|
v, _ := uint256.FromBig(evm.Context.Difficulty)
|
||||||
scope.Stack.push(v)
|
scope.Stack.push(v)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opRandom(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opRandom(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
v := new(uint256.Int).SetBytes(interpreter.evm.Context.Random.Bytes())
|
v := new(uint256.Int).SetBytes(evm.Context.Random.Bytes())
|
||||||
scope.Stack.push(v)
|
scope.Stack.push(v)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opGasLimit(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opGasLimit(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
scope.Stack.push(new(uint256.Int).SetUint64(interpreter.evm.Context.GasLimit))
|
scope.Stack.push(new(uint256.Int).SetUint64(evm.Context.GasLimit))
|
||||||
return nil, nil
|
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()
|
scope.Stack.pop()
|
||||||
return nil, nil
|
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()
|
v := scope.Stack.peek()
|
||||||
offset := v.Uint64()
|
offset := v.Uint64()
|
||||||
v.SetBytes(scope.Memory.GetPtr(offset, 32))
|
v.SetBytes(scope.Memory.GetPtr(offset, 32))
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opMstore(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opMstore(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
mStart, val := scope.Stack.pop(), scope.Stack.pop()
|
mStart, val := scope.Stack.pop(), scope.Stack.pop()
|
||||||
scope.Memory.Set32(mStart.Uint64(), &val)
|
scope.Memory.Set32(mStart.Uint64(), &val)
|
||||||
return nil, nil
|
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()
|
off, val := scope.Stack.pop(), scope.Stack.pop()
|
||||||
scope.Memory.store[off.Uint64()] = byte(val.Uint64())
|
scope.Memory.store[off.Uint64()] = byte(val.Uint64())
|
||||||
return nil, nil
|
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()
|
loc := scope.Stack.peek()
|
||||||
hash := common.Hash(loc.Bytes32())
|
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())
|
loc.SetBytes(val.Bytes())
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSstore(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opSstore(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
if interpreter.readOnly {
|
if evm.readOnly {
|
||||||
return nil, ErrWriteProtection
|
return nil, ErrWriteProtection
|
||||||
}
|
}
|
||||||
loc := scope.Stack.pop()
|
loc := scope.Stack.pop()
|
||||||
val := 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
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opJump(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opJump(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
if interpreter.evm.abort.Load() {
|
if evm.abort.Load() {
|
||||||
return nil, errStopToken
|
return nil, errStopToken
|
||||||
}
|
}
|
||||||
pos := scope.Stack.pop()
|
pos := scope.Stack.pop()
|
||||||
|
|
@ -540,8 +539,8 @@ func opJump(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opJumpi(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opJumpi(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
if interpreter.evm.abort.Load() {
|
if evm.abort.Load() {
|
||||||
return nil, errStopToken
|
return nil, errStopToken
|
||||||
}
|
}
|
||||||
pos, cond := scope.Stack.pop(), scope.Stack.pop()
|
pos, cond := scope.Stack.pop(), scope.Stack.pop()
|
||||||
|
|
@ -554,107 +553,107 @@ func opJumpi(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by
|
||||||
return nil, nil
|
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
|
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))
|
scope.Stack.push(new(uint256.Int).SetUint64(*pc))
|
||||||
return nil, nil
|
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())))
|
scope.Stack.push(new(uint256.Int).SetUint64(uint64(scope.Memory.Len())))
|
||||||
return nil, nil
|
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))
|
scope.Stack.push(new(uint256.Int).SetUint64(scope.Contract.Gas))
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSwap1(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opSwap1(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
scope.Stack.swap1()
|
scope.Stack.swap1()
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSwap2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opSwap2(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
scope.Stack.swap2()
|
scope.Stack.swap2()
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSwap3(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opSwap3(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
scope.Stack.swap3()
|
scope.Stack.swap3()
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSwap4(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opSwap4(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
scope.Stack.swap4()
|
scope.Stack.swap4()
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSwap5(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opSwap5(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
scope.Stack.swap5()
|
scope.Stack.swap5()
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSwap6(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opSwap6(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
scope.Stack.swap6()
|
scope.Stack.swap6()
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSwap7(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opSwap7(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
scope.Stack.swap7()
|
scope.Stack.swap7()
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSwap8(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opSwap8(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
scope.Stack.swap8()
|
scope.Stack.swap8()
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSwap9(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opSwap9(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
scope.Stack.swap9()
|
scope.Stack.swap9()
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSwap10(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opSwap10(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
scope.Stack.swap10()
|
scope.Stack.swap10()
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSwap11(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opSwap11(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
scope.Stack.swap11()
|
scope.Stack.swap11()
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSwap12(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opSwap12(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
scope.Stack.swap12()
|
scope.Stack.swap12()
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSwap13(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opSwap13(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
scope.Stack.swap13()
|
scope.Stack.swap13()
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSwap14(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opSwap14(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
scope.Stack.swap14()
|
scope.Stack.swap14()
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSwap15(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opSwap15(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
scope.Stack.swap15()
|
scope.Stack.swap15()
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSwap16(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opSwap16(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
scope.Stack.swap16()
|
scope.Stack.swap16()
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opCreate(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
if interpreter.readOnly {
|
if evm.readOnly {
|
||||||
return nil, ErrWriteProtection
|
return nil, ErrWriteProtection
|
||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
|
|
@ -663,21 +662,21 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
|
||||||
input = scope.Memory.GetCopy(offset.Uint64(), size.Uint64())
|
input = scope.Memory.GetCopy(offset.Uint64(), size.Uint64())
|
||||||
gas = scope.Contract.Gas
|
gas = scope.Contract.Gas
|
||||||
)
|
)
|
||||||
if interpreter.evm.chainRules.IsEIP150 {
|
if evm.chainRules.IsEIP150 {
|
||||||
gas -= gas / 64
|
gas -= gas / 64
|
||||||
}
|
}
|
||||||
|
|
||||||
// reuse size int for stackvalue
|
// reuse size int for stackvalue
|
||||||
stackvalue := size
|
stackvalue := size
|
||||||
|
|
||||||
scope.Contract.UseGas(gas, interpreter.evm.Config.Tracer, tracing.GasChangeCallContractCreation)
|
scope.Contract.UseGas(gas, evm.Config.Tracer, tracing.GasChangeCallContractCreation)
|
||||||
|
|
||||||
res, addr, returnGas, suberr := interpreter.evm.Create(scope.Contract.Address(), input, gas, &value)
|
res, addr, returnGas, suberr := evm.Create(scope.Contract.Address(), input, gas, &value)
|
||||||
// Push item on the stack based on the returned error. If the ruleset is
|
// Push item on the stack based on the returned error. If the ruleset is
|
||||||
// homestead we must check for CodeStoreOutOfGasError (homestead only
|
// homestead we must check for CodeStoreOutOfGasError (homestead only
|
||||||
// rule) and treat as an error, if the ruleset is frontier we must
|
// rule) and treat as an error, if the ruleset is frontier we must
|
||||||
// ignore this error and pretend the operation was successful.
|
// ignore this error and pretend the operation was successful.
|
||||||
if interpreter.evm.chainRules.IsHomestead && suberr == ErrCodeStoreOutOfGas {
|
if evm.chainRules.IsHomestead && suberr == ErrCodeStoreOutOfGas {
|
||||||
stackvalue.Clear()
|
stackvalue.Clear()
|
||||||
} else if suberr != nil && suberr != ErrCodeStoreOutOfGas {
|
} else if suberr != nil && suberr != ErrCodeStoreOutOfGas {
|
||||||
stackvalue.Clear()
|
stackvalue.Clear()
|
||||||
|
|
@ -686,18 +685,18 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
|
||||||
}
|
}
|
||||||
scope.Stack.push(&stackvalue)
|
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 {
|
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
|
return res, nil
|
||||||
}
|
}
|
||||||
interpreter.returnData = nil // clear dirty return data buffer
|
evm.returnData = nil // clear dirty return data buffer
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opCreate2(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
if interpreter.readOnly {
|
if evm.readOnly {
|
||||||
return nil, ErrWriteProtection
|
return nil, ErrWriteProtection
|
||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
|
|
@ -710,10 +709,10 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]
|
||||||
|
|
||||||
// Apply EIP150
|
// Apply EIP150
|
||||||
gas -= gas / 64
|
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
|
// reuse size int for stackvalue
|
||||||
stackvalue := size
|
stackvalue := size
|
||||||
res, addr, returnGas, suberr := interpreter.evm.Create2(scope.Contract.Address(), input, gas,
|
res, addr, returnGas, suberr := evm.Create2(scope.Contract.Address(), input, gas,
|
||||||
&endowment, &salt)
|
&endowment, &salt)
|
||||||
// Push item on the stack based on the returned error.
|
// Push item on the stack based on the returned error.
|
||||||
if suberr != nil {
|
if suberr != nil {
|
||||||
|
|
@ -722,35 +721,35 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]
|
||||||
stackvalue.SetBytes(addr.Bytes())
|
stackvalue.SetBytes(addr.Bytes())
|
||||||
}
|
}
|
||||||
scope.Stack.push(&stackvalue)
|
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 {
|
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
|
return res, nil
|
||||||
}
|
}
|
||||||
interpreter.returnData = nil // clear dirty return data buffer
|
evm.returnData = nil // clear dirty return data buffer
|
||||||
return nil, nil
|
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
|
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
|
// We can use this as a temporary value
|
||||||
temp := stack.pop()
|
temp := stack.pop()
|
||||||
gas := interpreter.evm.callGasTemp
|
gas := evm.callGasTemp
|
||||||
// Pop other call parameters.
|
// Pop other call parameters.
|
||||||
addr, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
|
addr, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
|
||||||
toAddr := common.Address(addr.Bytes20())
|
toAddr := common.Address(addr.Bytes20())
|
||||||
// Get the arguments from the memory.
|
// Get the arguments from the memory.
|
||||||
args := scope.Memory.GetPtr(inOffset.Uint64(), inSize.Uint64())
|
args := scope.Memory.GetPtr(inOffset.Uint64(), inSize.Uint64())
|
||||||
|
|
||||||
if interpreter.readOnly && !value.IsZero() {
|
if evm.readOnly && !value.IsZero() {
|
||||||
return nil, ErrWriteProtection
|
return nil, ErrWriteProtection
|
||||||
}
|
}
|
||||||
if !value.IsZero() {
|
if !value.IsZero() {
|
||||||
gas += params.CallStipend
|
gas += params.CallStipend
|
||||||
}
|
}
|
||||||
ret, returnGas, err := interpreter.evm.Call(scope.Contract.Address(), toAddr, args, gas, &value)
|
ret, returnGas, err := evm.Call(scope.Contract.Address(), toAddr, args, gas, &value)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
temp.Clear()
|
temp.Clear()
|
||||||
|
|
@ -762,18 +761,18 @@ func opCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt
|
||||||
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
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
|
return ret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opCallCode(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opCallCode(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
// Pop gas. The actual gas is in interpreter.evm.callGasTemp.
|
// Pop gas. The actual gas is in evm.callGasTemp.
|
||||||
stack := scope.Stack
|
stack := scope.Stack
|
||||||
// We use it as a temporary value
|
// We use it as a temporary value
|
||||||
temp := stack.pop()
|
temp := stack.pop()
|
||||||
gas := interpreter.evm.callGasTemp
|
gas := evm.callGasTemp
|
||||||
// Pop other call parameters.
|
// Pop other call parameters.
|
||||||
addr, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
|
addr, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
|
||||||
toAddr := common.Address(addr.Bytes20())
|
toAddr := common.Address(addr.Bytes20())
|
||||||
|
|
@ -784,7 +783,7 @@ func opCallCode(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([
|
||||||
gas += params.CallStipend
|
gas += params.CallStipend
|
||||||
}
|
}
|
||||||
|
|
||||||
ret, returnGas, err := interpreter.evm.CallCode(scope.Contract.Address(), toAddr, args, gas, &value)
|
ret, returnGas, err := evm.CallCode(scope.Contract.Address(), toAddr, args, gas, &value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
temp.Clear()
|
temp.Clear()
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -795,25 +794,25 @@ func opCallCode(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([
|
||||||
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
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
|
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
|
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
|
// We use it as a temporary value
|
||||||
temp := stack.pop()
|
temp := stack.pop()
|
||||||
gas := interpreter.evm.callGasTemp
|
gas := evm.callGasTemp
|
||||||
// Pop other call parameters.
|
// Pop other call parameters.
|
||||||
addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
|
addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
|
||||||
toAddr := common.Address(addr.Bytes20())
|
toAddr := common.Address(addr.Bytes20())
|
||||||
// Get arguments from the memory.
|
// Get arguments from the memory.
|
||||||
args := scope.Memory.GetPtr(inOffset.Uint64(), inSize.Uint64())
|
args := scope.Memory.GetPtr(inOffset.Uint64(), inSize.Uint64())
|
||||||
|
|
||||||
ret, returnGas, err := interpreter.evm.DelegateCall(scope.Contract.Caller(), scope.Contract.Address(), toAddr, args, gas, scope.Contract.value)
|
ret, returnGas, err := evm.DelegateCall(scope.Contract.Caller(), scope.Contract.Address(), toAddr, args, gas, scope.Contract.value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
temp.Clear()
|
temp.Clear()
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -824,25 +823,25 @@ func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext
|
||||||
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
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
|
return ret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opStaticCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opStaticCall(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
// Pop gas. The actual gas is in interpreter.evm.callGasTemp.
|
// Pop gas. The actual gas is in evm.callGasTemp.
|
||||||
stack := scope.Stack
|
stack := scope.Stack
|
||||||
// We use it as a temporary value
|
// We use it as a temporary value
|
||||||
temp := stack.pop()
|
temp := stack.pop()
|
||||||
gas := interpreter.evm.callGasTemp
|
gas := evm.callGasTemp
|
||||||
// Pop other call parameters.
|
// Pop other call parameters.
|
||||||
addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
|
addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
|
||||||
toAddr := common.Address(addr.Bytes20())
|
toAddr := common.Address(addr.Bytes20())
|
||||||
// Get arguments from the memory.
|
// Get arguments from the memory.
|
||||||
args := scope.Memory.GetPtr(inOffset.Uint64(), inSize.Uint64())
|
args := scope.Memory.GetPtr(inOffset.Uint64(), inSize.Uint64())
|
||||||
|
|
||||||
ret, returnGas, err := interpreter.evm.StaticCall(scope.Contract.Address(), toAddr, args, gas)
|
ret, returnGas, err := evm.StaticCall(scope.Contract.Address(), toAddr, args, gas)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
temp.Clear()
|
temp.Clear()
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -853,69 +852,69 @@ func opStaticCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
|
||||||
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
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
|
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()
|
offset, size := scope.Stack.pop(), scope.Stack.pop()
|
||||||
ret := scope.Memory.GetCopy(offset.Uint64(), size.Uint64())
|
ret := scope.Memory.GetCopy(offset.Uint64(), size.Uint64())
|
||||||
|
|
||||||
return ret, errStopToken
|
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()
|
offset, size := scope.Stack.pop(), scope.Stack.pop()
|
||||||
ret := scope.Memory.GetCopy(offset.Uint64(), size.Uint64())
|
ret := scope.Memory.GetCopy(offset.Uint64(), size.Uint64())
|
||||||
|
|
||||||
interpreter.returnData = ret
|
evm.returnData = ret
|
||||||
return ret, ErrExecutionReverted
|
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])}
|
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
|
return nil, errStopToken
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSelfdestruct(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opSelfdestruct(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
if interpreter.readOnly {
|
if evm.readOnly {
|
||||||
return nil, ErrWriteProtection
|
return nil, ErrWriteProtection
|
||||||
}
|
}
|
||||||
beneficiary := scope.Stack.pop()
|
beneficiary := scope.Stack.pop()
|
||||||
balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address())
|
balance := evm.StateDB.GetBalance(scope.Contract.Address())
|
||||||
interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, tracing.BalanceIncreaseSelfdestruct)
|
evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, tracing.BalanceIncreaseSelfdestruct)
|
||||||
interpreter.evm.StateDB.SelfDestruct(scope.Contract.Address())
|
evm.StateDB.SelfDestruct(scope.Contract.Address())
|
||||||
if tracer := interpreter.evm.Config.Tracer; tracer != nil {
|
if tracer := evm.Config.Tracer; tracer != nil {
|
||||||
if tracer.OnEnter != nil {
|
if tracer.OnEnter != nil {
|
||||||
tracer.OnEnter(interpreter.evm.depth, byte(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance.ToBig())
|
tracer.OnEnter(evm.depth, byte(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance.ToBig())
|
||||||
}
|
}
|
||||||
if tracer.OnExit != nil {
|
if tracer.OnExit != nil {
|
||||||
tracer.OnExit(interpreter.evm.depth, []byte{}, 0, nil, false)
|
tracer.OnExit(evm.depth, []byte{}, 0, nil, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil, errStopToken
|
return nil, errStopToken
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSelfdestruct6780(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opSelfdestruct6780(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
if interpreter.readOnly {
|
if evm.readOnly {
|
||||||
return nil, ErrWriteProtection
|
return nil, ErrWriteProtection
|
||||||
}
|
}
|
||||||
beneficiary := scope.Stack.pop()
|
beneficiary := scope.Stack.pop()
|
||||||
balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address())
|
balance := evm.StateDB.GetBalance(scope.Contract.Address())
|
||||||
interpreter.evm.StateDB.SubBalance(scope.Contract.Address(), balance, tracing.BalanceDecreaseSelfdestruct)
|
evm.StateDB.SubBalance(scope.Contract.Address(), balance, tracing.BalanceDecreaseSelfdestruct)
|
||||||
interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, tracing.BalanceIncreaseSelfdestruct)
|
evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, tracing.BalanceIncreaseSelfdestruct)
|
||||||
interpreter.evm.StateDB.SelfDestruct6780(scope.Contract.Address())
|
evm.StateDB.SelfDestruct6780(scope.Contract.Address())
|
||||||
if tracer := interpreter.evm.Config.Tracer; tracer != nil {
|
if tracer := evm.Config.Tracer; tracer != nil {
|
||||||
if tracer.OnEnter != nil {
|
if tracer.OnEnter != nil {
|
||||||
tracer.OnEnter(interpreter.evm.depth, byte(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance.ToBig())
|
tracer.OnEnter(evm.depth, byte(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance.ToBig())
|
||||||
}
|
}
|
||||||
if tracer.OnExit != nil {
|
if tracer.OnExit != nil {
|
||||||
tracer.OnExit(interpreter.evm.depth, []byte{}, 0, nil, false)
|
tracer.OnExit(evm.depth, []byte{}, 0, nil, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil, errStopToken
|
return nil, errStopToken
|
||||||
|
|
@ -925,8 +924,8 @@ func opSelfdestruct6780(pc *uint64, interpreter *EVMInterpreter, scope *ScopeCon
|
||||||
|
|
||||||
// make log instruction function
|
// make log instruction function
|
||||||
func makeLog(size int) executionFunc {
|
func makeLog(size int) executionFunc {
|
||||||
return func(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
return func(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
if interpreter.readOnly {
|
if evm.readOnly {
|
||||||
return nil, ErrWriteProtection
|
return nil, ErrWriteProtection
|
||||||
}
|
}
|
||||||
topics := make([]common.Hash, size)
|
topics := make([]common.Hash, size)
|
||||||
|
|
@ -938,13 +937,13 @@ func makeLog(size int) executionFunc {
|
||||||
}
|
}
|
||||||
|
|
||||||
d := scope.Memory.GetCopy(mStart.Uint64(), mSize.Uint64())
|
d := scope.Memory.GetCopy(mStart.Uint64(), mSize.Uint64())
|
||||||
interpreter.evm.StateDB.AddLog(&types.Log{
|
evm.StateDB.AddLog(&types.Log{
|
||||||
Address: scope.Contract.Address(),
|
Address: scope.Contract.Address(),
|
||||||
Topics: topics,
|
Topics: topics,
|
||||||
Data: d,
|
Data: d,
|
||||||
// This is a non-consensus field, but assigned here because
|
// This is a non-consensus field, but assigned here because
|
||||||
// core/state doesn't know the current block number.
|
// core/state doesn't know the current block number.
|
||||||
BlockNumber: interpreter.evm.Context.BlockNumber.Uint64(),
|
BlockNumber: evm.Context.BlockNumber.Uint64(),
|
||||||
})
|
})
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
|
@ -952,7 +951,7 @@ func makeLog(size int) executionFunc {
|
||||||
}
|
}
|
||||||
|
|
||||||
// opPush1 is a specialized version of pushN
|
// 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 (
|
var (
|
||||||
codeLen = uint64(len(scope.Contract.Code))
|
codeLen = uint64(len(scope.Contract.Code))
|
||||||
integer = new(uint256.Int)
|
integer = new(uint256.Int)
|
||||||
|
|
@ -967,7 +966,7 @@ func opPush1(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by
|
||||||
}
|
}
|
||||||
|
|
||||||
// opPush2 is a specialized version of pushN
|
// opPush2 is a specialized version of pushN
|
||||||
func opPush2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opPush2(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
var (
|
var (
|
||||||
codeLen = uint64(len(scope.Contract.Code))
|
codeLen = uint64(len(scope.Contract.Code))
|
||||||
integer = new(uint256.Int)
|
integer = new(uint256.Int)
|
||||||
|
|
@ -985,7 +984,7 @@ func opPush2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by
|
||||||
|
|
||||||
// make push instruction function
|
// make push instruction function
|
||||||
func makePush(size uint64, pushByteSize int) executionFunc {
|
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 (
|
var (
|
||||||
codeLen = len(scope.Contract.Code)
|
codeLen = len(scope.Contract.Code)
|
||||||
start = min(codeLen, int(*pc+1))
|
start = min(codeLen, int(*pc+1))
|
||||||
|
|
@ -1005,7 +1004,7 @@ func makePush(size uint64, pushByteSize int) executionFunc {
|
||||||
|
|
||||||
// make dup instruction function
|
// make dup instruction function
|
||||||
func makeDup(size int64) executionFunc {
|
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))
|
scope.Stack.dup(int(size))
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,7 @@ func testTwoOperandOp(t *testing.T, tests []TwoOperandTestcase, opFn executionFu
|
||||||
expected := new(uint256.Int).SetBytes(common.Hex2Bytes(test.Expected))
|
expected := new(uint256.Int).SetBytes(common.Hex2Bytes(test.Expected))
|
||||||
stack.push(x)
|
stack.push(x)
|
||||||
stack.push(y)
|
stack.push(y)
|
||||||
opFn(&pc, evm.interpreter, &ScopeContext{nil, stack, nil})
|
opFn(&pc, evm, &ScopeContext{nil, stack, nil})
|
||||||
if len(stack.data) != 1 {
|
if len(stack.data) != 1 {
|
||||||
t.Errorf("Expected one item on stack after %v, got %d: ", name, len(stack.data))
|
t.Errorf("Expected one item on stack after %v, got %d: ", name, len(stack.data))
|
||||||
}
|
}
|
||||||
|
|
@ -221,7 +221,7 @@ func TestAddMod(t *testing.T) {
|
||||||
stack.push(z)
|
stack.push(z)
|
||||||
stack.push(y)
|
stack.push(y)
|
||||||
stack.push(x)
|
stack.push(x)
|
||||||
opAddmod(&pc, evm.interpreter, &ScopeContext{nil, stack, nil})
|
opAddmod(&pc, evm, &ScopeContext{nil, stack, nil})
|
||||||
actual := stack.pop()
|
actual := stack.pop()
|
||||||
if actual.Cmp(expected) != 0 {
|
if actual.Cmp(expected) != 0 {
|
||||||
t.Errorf("Testcase %d, expected %x, got %x", i, expected, actual)
|
t.Errorf("Testcase %d, expected %x, got %x", i, expected, actual)
|
||||||
|
|
@ -247,7 +247,7 @@ func TestWriteExpectedValues(t *testing.T) {
|
||||||
y := new(uint256.Int).SetBytes(common.Hex2Bytes(param.y))
|
y := new(uint256.Int).SetBytes(common.Hex2Bytes(param.y))
|
||||||
stack.push(x)
|
stack.push(x)
|
||||||
stack.push(y)
|
stack.push(y)
|
||||||
opFn(&pc, evm.interpreter, &ScopeContext{nil, stack, nil})
|
opFn(&pc, evm, &ScopeContext{nil, stack, nil})
|
||||||
actual := stack.pop()
|
actual := stack.pop()
|
||||||
result[i] = TwoOperandTestcase{param.x, param.y, fmt.Sprintf("%064x", actual)}
|
result[i] = TwoOperandTestcase{param.x, param.y, fmt.Sprintf("%064x", actual)}
|
||||||
}
|
}
|
||||||
|
|
@ -296,7 +296,7 @@ func opBenchmark(bench *testing.B, op executionFunc, args ...string) {
|
||||||
for _, arg := range intArgs {
|
for _, arg := range intArgs {
|
||||||
stack.push(arg)
|
stack.push(arg)
|
||||||
}
|
}
|
||||||
op(&pc, evm.interpreter, scope)
|
op(&pc, evm, scope)
|
||||||
stack.pop()
|
stack.pop()
|
||||||
}
|
}
|
||||||
bench.StopTimer()
|
bench.StopTimer()
|
||||||
|
|
@ -528,13 +528,13 @@ func TestOpMstore(t *testing.T) {
|
||||||
v := "abcdef00000000000000abba000000000deaf000000c0de00100000000133700"
|
v := "abcdef00000000000000abba000000000deaf000000c0de00100000000133700"
|
||||||
stack.push(new(uint256.Int).SetBytes(common.Hex2Bytes(v)))
|
stack.push(new(uint256.Int).SetBytes(common.Hex2Bytes(v)))
|
||||||
stack.push(new(uint256.Int))
|
stack.push(new(uint256.Int))
|
||||||
opMstore(&pc, evm.interpreter, &ScopeContext{mem, stack, nil})
|
opMstore(&pc, evm, &ScopeContext{mem, stack, nil})
|
||||||
if got := common.Bytes2Hex(mem.GetCopy(0, 32)); got != v {
|
if got := common.Bytes2Hex(mem.GetCopy(0, 32)); got != v {
|
||||||
t.Fatalf("Mstore fail, got %v, expected %v", got, v)
|
t.Fatalf("Mstore fail, got %v, expected %v", got, v)
|
||||||
}
|
}
|
||||||
stack.push(new(uint256.Int).SetUint64(0x1))
|
stack.push(new(uint256.Int).SetUint64(0x1))
|
||||||
stack.push(new(uint256.Int))
|
stack.push(new(uint256.Int))
|
||||||
opMstore(&pc, evm.interpreter, &ScopeContext{mem, stack, nil})
|
opMstore(&pc, evm, &ScopeContext{mem, stack, nil})
|
||||||
if common.Bytes2Hex(mem.GetCopy(0, 32)) != "0000000000000000000000000000000000000000000000000000000000000001" {
|
if common.Bytes2Hex(mem.GetCopy(0, 32)) != "0000000000000000000000000000000000000000000000000000000000000001" {
|
||||||
t.Fatalf("Mstore failed to overwrite previous value")
|
t.Fatalf("Mstore failed to overwrite previous value")
|
||||||
}
|
}
|
||||||
|
|
@ -555,7 +555,7 @@ func BenchmarkOpMstore(bench *testing.B) {
|
||||||
for i := 0; i < bench.N; i++ {
|
for i := 0; i < bench.N; i++ {
|
||||||
stack.push(value)
|
stack.push(value)
|
||||||
stack.push(memStart)
|
stack.push(memStart)
|
||||||
opMstore(&pc, evm.interpreter, &ScopeContext{mem, stack, nil})
|
opMstore(&pc, evm, &ScopeContext{mem, stack, nil})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -581,14 +581,14 @@ func TestOpTstore(t *testing.T) {
|
||||||
stack.push(new(uint256.Int).SetBytes(value))
|
stack.push(new(uint256.Int).SetBytes(value))
|
||||||
// push the location to the stack
|
// push the location to the stack
|
||||||
stack.push(new(uint256.Int))
|
stack.push(new(uint256.Int))
|
||||||
opTstore(&pc, evm.interpreter, &scopeContext)
|
opTstore(&pc, evm, &scopeContext)
|
||||||
// there should be no elements on the stack after TSTORE
|
// there should be no elements on the stack after TSTORE
|
||||||
if stack.len() != 0 {
|
if stack.len() != 0 {
|
||||||
t.Fatal("stack wrong size")
|
t.Fatal("stack wrong size")
|
||||||
}
|
}
|
||||||
// push the location to the stack
|
// push the location to the stack
|
||||||
stack.push(new(uint256.Int))
|
stack.push(new(uint256.Int))
|
||||||
opTload(&pc, evm.interpreter, &scopeContext)
|
opTload(&pc, evm, &scopeContext)
|
||||||
// there should be one element on the stack after TLOAD
|
// there should be one element on the stack after TLOAD
|
||||||
if stack.len() != 1 {
|
if stack.len() != 1 {
|
||||||
t.Fatal("stack wrong size")
|
t.Fatal("stack wrong size")
|
||||||
|
|
@ -613,7 +613,7 @@ func BenchmarkOpKeccak256(bench *testing.B) {
|
||||||
for i := 0; i < bench.N; i++ {
|
for i := 0; i < bench.N; i++ {
|
||||||
stack.push(uint256.NewInt(32))
|
stack.push(uint256.NewInt(32))
|
||||||
stack.push(start)
|
stack.push(start)
|
||||||
opKeccak256(&pc, evm.interpreter, &ScopeContext{mem, stack, nil})
|
opKeccak256(&pc, evm, &ScopeContext{mem, stack, nil})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -707,7 +707,7 @@ func TestRandom(t *testing.T) {
|
||||||
stack = newstack()
|
stack = newstack()
|
||||||
pc = uint64(0)
|
pc = uint64(0)
|
||||||
)
|
)
|
||||||
opRandom(&pc, evm.interpreter, &ScopeContext{nil, stack, nil})
|
opRandom(&pc, evm, &ScopeContext{nil, stack, nil})
|
||||||
if len(stack.data) != 1 {
|
if len(stack.data) != 1 {
|
||||||
t.Errorf("Expected one item on stack after %v, got %d: ", tt.name, len(stack.data))
|
t.Errorf("Expected one item on stack after %v, got %d: ", tt.name, len(stack.data))
|
||||||
}
|
}
|
||||||
|
|
@ -749,7 +749,7 @@ func TestBlobHash(t *testing.T) {
|
||||||
)
|
)
|
||||||
evm.SetTxContext(TxContext{BlobHashes: tt.hashes})
|
evm.SetTxContext(TxContext{BlobHashes: tt.hashes})
|
||||||
stack.push(uint256.NewInt(tt.idx))
|
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 {
|
if len(stack.data) != 1 {
|
||||||
t.Errorf("Expected one item on stack after %v, got %d: ", tt.name, len(stack.data))
|
t.Errorf("Expected one item on stack after %v, got %d: ", tt.name, len(stack.data))
|
||||||
}
|
}
|
||||||
|
|
@ -889,7 +889,7 @@ func TestOpMCopy(t *testing.T) {
|
||||||
mem.Resize(memorySize)
|
mem.Resize(memorySize)
|
||||||
}
|
}
|
||||||
// Do the copy
|
// Do the copy
|
||||||
opMcopy(&pc, evm.interpreter, &ScopeContext{mem, stack, nil})
|
opMcopy(&pc, evm, &ScopeContext{mem, stack, nil})
|
||||||
want := common.FromHex(strings.ReplaceAll(tc.want, " ", ""))
|
want := common.FromHex(strings.ReplaceAll(tc.want, " ", ""))
|
||||||
if have := mem.store; !bytes.Equal(want, have) {
|
if have := mem.store; !bytes.Equal(want, have) {
|
||||||
t.Errorf("case %d: \nwant: %#x\nhave: %#x\n", i, want, have)
|
t.Errorf("case %d: \nwant: %#x\nhave: %#x\n", i, want, have)
|
||||||
|
|
@ -1001,7 +1001,7 @@ func TestOpCLZ(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
stack.push(val)
|
stack.push(val)
|
||||||
opCLZ(&pc, evm.interpreter, &ScopeContext{Stack: stack})
|
opCLZ(&pc, evm, &ScopeContext{Stack: stack})
|
||||||
|
|
||||||
if gotLen := stack.len(); gotLen != 1 {
|
if gotLen := stack.len(); gotLen != 1 {
|
||||||
t.Fatalf("stack length = %d; want 1", gotLen)
|
t.Fatalf("stack length = %d; want 1", gotLen)
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"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/crypto"
|
|
||||||
"github.com/ethereum/go-ethereum/log"
|
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -89,93 +87,27 @@ func (ctx *ScopeContext) ContractCode() []byte {
|
||||||
return ctx.Contract.Code
|
return ctx.Contract.Code
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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.IsOsaka:
|
|
||||||
table = &osakaInstructionSet
|
|
||||||
case evm.chainRules.IsVerkle:
|
|
||||||
// TODO replace with proper instruction set when fork is specified
|
|
||||||
table = &verkleInstructionSet
|
|
||||||
case evm.chainRules.IsPrague:
|
|
||||||
table = &pragueInstructionSet
|
|
||||||
case evm.chainRules.IsCancun:
|
|
||||||
table = &cancunInstructionSet
|
|
||||||
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
|
|
||||||
}
|
|
||||||
var extraEips []int
|
|
||||||
if len(evm.Config.ExtraEips) > 0 {
|
|
||||||
// Deep-copy jumptable to prevent modification of opcodes in other tables
|
|
||||||
table = copyJumpTable(table)
|
|
||||||
}
|
|
||||||
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
|
// 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.
|
// the return byte-slice and an error if one occurred.
|
||||||
//
|
//
|
||||||
// It's important to note that any errors returned by the interpreter should be
|
// It's important to note that any errors returned by the interpreter should be
|
||||||
// considered a revert-and-consume-all-gas operation except for
|
// considered a revert-and-consume-all-gas operation except for
|
||||||
// ErrExecutionReverted which means revert-and-keep-gas-left.
|
// 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
|
// Increment the call depth which is restricted to 1024
|
||||||
in.evm.depth++
|
evm.depth++
|
||||||
defer func() { in.evm.depth-- }()
|
defer func() { evm.depth-- }()
|
||||||
|
|
||||||
// Make sure the readOnly is only set if we aren't in readOnly yet.
|
// 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.
|
// This also makes sure that the readOnly flag isn't removed for child calls.
|
||||||
if readOnly && !in.readOnly {
|
if readOnly && !evm.readOnly {
|
||||||
in.readOnly = true
|
evm.readOnly = true
|
||||||
defer func() { in.readOnly = false }()
|
defer func() { evm.readOnly = false }()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset the previous call's return data. It's unimportant to preserve the old buffer
|
// Reset the previous call's return data. It's unimportant to preserve the old buffer
|
||||||
// as every returning call will return new data anyway.
|
// 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.
|
// Don't bother with the execution if there's no code.
|
||||||
if len(contract.Code) == 0 {
|
if len(contract.Code) == 0 {
|
||||||
|
|
@ -184,7 +116,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
|
||||||
|
|
||||||
var (
|
var (
|
||||||
op OpCode // current opcode
|
op OpCode // current opcode
|
||||||
jumpTable *JumpTable = in.table
|
jumpTable *JumpTable = evm.table
|
||||||
mem = NewMemory() // bound memory
|
mem = NewMemory() // bound memory
|
||||||
stack = newstack() // local stack
|
stack = newstack() // local stack
|
||||||
callContext = &ScopeContext{
|
callContext = &ScopeContext{
|
||||||
|
|
@ -198,11 +130,12 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
|
||||||
pc = uint64(0) // program counter
|
pc = uint64(0) // program counter
|
||||||
cost uint64
|
cost uint64
|
||||||
// copies used by tracer
|
// copies used by tracer
|
||||||
pcCopy uint64 // needed for the deferred EVMLogger
|
pcCopy uint64 // needed for the deferred EVMLogger
|
||||||
gasCopy uint64 // for EVMLogger to log gas remaining before execution
|
gasCopy uint64 // for EVMLogger to log gas remaining before execution
|
||||||
logged bool // deferred EVMLogger should ignore already logged steps
|
logged bool // deferred EVMLogger should ignore already logged steps
|
||||||
res []byte // result of the opcode execution function
|
res []byte // result of the opcode execution function
|
||||||
debug = in.evm.Config.Tracer != nil
|
debug = evm.Config.Tracer != nil
|
||||||
|
isEIP4762 = evm.chainRules.IsEIP4762
|
||||||
)
|
)
|
||||||
// Don't move this deferred function, it's placed before the OnOpcode-deferred method,
|
// 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
|
// so that it gets executed _after_: the OnOpcode needs the stacks before
|
||||||
|
|
@ -218,11 +151,11 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !logged && in.evm.Config.Tracer.OnOpcode != nil {
|
if !logged && evm.Config.Tracer.OnOpcode != nil {
|
||||||
in.evm.Config.Tracer.OnOpcode(pcCopy, byte(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err))
|
evm.Config.Tracer.OnOpcode(pcCopy, byte(op), gasCopy, cost, callContext, evm.returnData, evm.depth, VMErrorFromErr(err))
|
||||||
}
|
}
|
||||||
if logged && in.evm.Config.Tracer.OnFault != nil {
|
if logged && evm.Config.Tracer.OnFault != nil {
|
||||||
in.evm.Config.Tracer.OnFault(pcCopy, byte(op), gasCopy, cost, callContext, in.evm.depth, VMErrorFromErr(err))
|
evm.Config.Tracer.OnFault(pcCopy, byte(op), gasCopy, cost, callContext, evm.depth, VMErrorFromErr(err))
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
@ -237,12 +170,12 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
|
||||||
logged, pcCopy, gasCopy = false, pc, contract.Gas
|
logged, pcCopy, gasCopy = false, pc, contract.Gas
|
||||||
}
|
}
|
||||||
|
|
||||||
if in.evm.chainRules.IsEIP4762 && !contract.IsDeployment && !contract.IsSystemCall {
|
if isEIP4762 && !contract.IsDeployment && !contract.IsSystemCall {
|
||||||
// if the PC ends up in a new "chunk" of verkleized code, charge the
|
// if the PC ends up in a new "chunk" of verkleized code, charge the
|
||||||
// associated costs.
|
// associated costs.
|
||||||
contractAddr := contract.Address()
|
contractAddr := contract.Address()
|
||||||
consumed, wanted := in.evm.TxContext.AccessEvents.CodeChunksRangeGas(contractAddr, pc, 1, uint64(len(contract.Code)), false, contract.Gas)
|
consumed, wanted := evm.TxContext.AccessEvents.CodeChunksRangeGas(contractAddr, pc, 1, uint64(len(contract.Code)), false, contract.Gas)
|
||||||
contract.UseGas(consumed, in.evm.Config.Tracer, tracing.GasChangeWitnessCodeChunk)
|
contract.UseGas(consumed, evm.Config.Tracer, tracing.GasChangeWitnessCodeChunk)
|
||||||
if consumed < wanted {
|
if consumed < wanted {
|
||||||
return nil, ErrOutOfGas
|
return nil, ErrOutOfGas
|
||||||
}
|
}
|
||||||
|
|
@ -287,7 +220,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
|
||||||
// Consume the gas and return an error if not enough gas is available.
|
// 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
|
// cost is explicitly set so that the capture state defer method can get the proper cost
|
||||||
var dynamicCost uint64
|
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
|
cost += dynamicCost // for tracing
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
|
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
|
||||||
|
|
@ -302,11 +235,11 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
|
||||||
|
|
||||||
// Do tracing before potential memory expansion
|
// Do tracing before potential memory expansion
|
||||||
if debug {
|
if debug {
|
||||||
if in.evm.Config.Tracer.OnGasChange != nil {
|
if evm.Config.Tracer.OnGasChange != nil {
|
||||||
in.evm.Config.Tracer.OnGasChange(gasCopy, gasCopy-cost, tracing.GasChangeCallOpCode)
|
evm.Config.Tracer.OnGasChange(gasCopy, gasCopy-cost, tracing.GasChangeCallOpCode)
|
||||||
}
|
}
|
||||||
if in.evm.Config.Tracer.OnOpcode != nil {
|
if evm.Config.Tracer.OnOpcode != nil {
|
||||||
in.evm.Config.Tracer.OnOpcode(pc, byte(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err))
|
evm.Config.Tracer.OnOpcode(pc, byte(op), gasCopy, cost, callContext, evm.returnData, evm.depth, VMErrorFromErr(err))
|
||||||
logged = true
|
logged = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -315,7 +248,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
|
||||||
}
|
}
|
||||||
|
|
||||||
// execute the operation
|
// execute the operation
|
||||||
res, err = operation.execute(&pc, in, callContext)
|
res, err = operation.execute(&pc, evm, callContext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
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
|
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 returns the required size, and whether the operation overflowed a uint64
|
||||||
memorySizeFunc func(*Stack) (size uint64, overflow bool)
|
memorySizeFunc func(*Stack) (size uint64, overflow bool)
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ func runTrace(tracer *tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainCo
|
||||||
|
|
||||||
tracer.OnTxStart(evm.GetVMContext(), types.NewTx(&types.LegacyTx{Gas: gasLimit, GasPrice: vmctx.txCtx.GasPrice}), contract.Caller())
|
tracer.OnTxStart(evm.GetVMContext(), types.NewTx(&types.LegacyTx{Gas: gasLimit, GasPrice: vmctx.txCtx.GasPrice}), contract.Caller())
|
||||||
tracer.OnEnter(0, byte(vm.CALL), contract.Caller(), contract.Address(), []byte{}, startGas, value.ToBig())
|
tracer.OnEnter(0, byte(vm.CALL), contract.Caller(), contract.Address(), []byte{}, startGas, value.ToBig())
|
||||||
ret, err := evm.Interpreter().Run(contract, []byte{}, false)
|
ret, err := evm.Run(contract, []byte{}, false)
|
||||||
tracer.OnExit(0, ret, startGas-contract.Gas, err, true)
|
tracer.OnExit(0, ret, startGas-contract.Gas, err, true)
|
||||||
// Rest gas assumes no refund
|
// Rest gas assumes no refund
|
||||||
tracer.OnTxEnd(&types.Receipt{GasUsed: gasLimit - contract.Gas}, nil)
|
tracer.OnTxEnd(&types.Receipt{GasUsed: gasLimit - contract.Gas}, nil)
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ func TestStoreCapture(t *testing.T) {
|
||||||
contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x0, byte(vm.SSTORE)}
|
contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x0, byte(vm.SSTORE)}
|
||||||
var index common.Hash
|
var index common.Hash
|
||||||
logger.OnTxStart(evm.GetVMContext(), nil, common.Address{})
|
logger.OnTxStart(evm.GetVMContext(), nil, common.Address{})
|
||||||
_, err := evm.Interpreter().Run(contract, []byte{}, false)
|
_, err := evm.Run(contract, []byte{}, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue