mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 18:32:23 +00:00
Tosca CT integration
This commit is contained in:
parent
d6e91e2e05
commit
6b8469282d
3 changed files with 302 additions and 111 deletions
|
|
@ -125,6 +125,9 @@ type EVM struct {
|
|||
// available gas is calculated in gasCall* according to the 63/64 rule and later
|
||||
// applied in opCall*.
|
||||
callGasTemp uint64
|
||||
|
||||
// An optional override to intercept EVM calls.
|
||||
CallContext CallContextInterceptor
|
||||
}
|
||||
|
||||
// NewEVM returns a new EVM. The returned EVM is not thread safe and should
|
||||
|
|
@ -181,6 +184,9 @@ func (evm *EVM) Interpreter() *EVMInterpreter {
|
|||
// the necessary steps to create accounts and reverses the state in case of an
|
||||
// execution error or failed value transfer.
|
||||
func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas uint64, value *uint256.Int) (ret []byte, leftOverGas uint64, err error) {
|
||||
if evm.CallContext != nil {
|
||||
return evm.CallContext.Call(evm, caller, addr, input, new(big.Int).SetUint64(gas), value.ToBig())
|
||||
}
|
||||
// Capture the tracer start/end events in debug mode
|
||||
if evm.Config.Tracer != nil {
|
||||
evm.captureBegin(evm.depth, CALL, caller.Address(), addr, input, gas, value.ToBig())
|
||||
|
|
@ -253,6 +259,9 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
|
|||
// CallCode differs from Call in the sense that it executes the given address'
|
||||
// code with the caller as context.
|
||||
func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, gas uint64, value *uint256.Int) (ret []byte, leftOverGas uint64, err error) {
|
||||
if evm.CallContext != nil {
|
||||
return evm.CallContext.CallCode(evm, caller, addr, input, new(big.Int).SetUint64(gas), value.ToBig())
|
||||
}
|
||||
// Invoke tracer hooks that signal entering/exiting a call frame
|
||||
if evm.Config.Tracer != nil {
|
||||
evm.captureBegin(evm.depth, CALLCODE, caller.Address(), addr, input, gas, value.ToBig())
|
||||
|
|
@ -304,6 +313,9 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
|
|||
// DelegateCall differs from CallCode in the sense that it executes the given address'
|
||||
// code with the caller as context and the caller is set to the caller of the caller.
|
||||
func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) {
|
||||
if evm.CallContext != nil {
|
||||
return evm.CallContext.DelegateCall(evm, caller, addr, input, new(big.Int).SetUint64(gas))
|
||||
}
|
||||
// Invoke tracer hooks that signal entering/exiting a call frame
|
||||
if evm.Config.Tracer != nil {
|
||||
// NOTE: caller must, at all times be a contract. It should never happen
|
||||
|
|
@ -349,6 +361,9 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
|
|||
// Opcodes that attempt to perform such modifications will result in exceptions
|
||||
// instead of performing the modifications.
|
||||
func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) {
|
||||
if evm.CallContext != nil {
|
||||
return evm.CallContext.StaticCall(evm, caller, addr, input, new(big.Int).SetUint64(gas))
|
||||
}
|
||||
// Invoke tracer hooks that signal entering/exiting a call frame
|
||||
if evm.Config.Tracer != nil {
|
||||
evm.captureBegin(evm.depth, STATICCALL, caller.Address(), addr, input, gas, nil)
|
||||
|
|
@ -520,6 +535,9 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
|
|||
|
||||
// Create creates a new contract using code as deployment code.
|
||||
func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *uint256.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {
|
||||
if evm.CallContext != nil {
|
||||
return evm.CallContext.Create(evm, caller, code, new(big.Int).SetUint64(gas), value.ToBig())
|
||||
}
|
||||
contractAddr = crypto.CreateAddress(caller.Address(), evm.StateDB.GetNonce(caller.Address()))
|
||||
return evm.create(caller, &codeAndHash{code: code}, gas, value, contractAddr, CREATE)
|
||||
}
|
||||
|
|
@ -529,6 +547,9 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *uint2
|
|||
// 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.
|
||||
func (evm *EVM) Create2(caller ContractRef, code []byte, gas uint64, endowment *uint256.Int, salt *uint256.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {
|
||||
if evm.CallContext != nil {
|
||||
return evm.CallContext.Create2(evm, caller, code, new(big.Int).SetUint64(gas), endowment.ToBig(), salt)
|
||||
}
|
||||
codeAndHash := &codeAndHash{code: code}
|
||||
contractAddr = crypto.CreateAddress2(caller.Address(), salt.Bytes32(), codeAndHash.Hash().Bytes())
|
||||
return evm.create(caller, codeAndHash, gas, endowment, contractAddr, CREATE2)
|
||||
|
|
|
|||
|
|
@ -147,7 +147,11 @@ func NewEVMInterpreter(evm *EVM) *EVMInterpreter {
|
|||
// It's important to note that any errors returned by the interpreter should be
|
||||
// considered a revert-and-consume-all-gas operation except for
|
||||
// ErrExecutionReverted which means revert-and-keep-gas-left.
|
||||
func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (ret []byte, err error) {
|
||||
func (in *EVMInterpreter) run(state *InterpreterState, input []byte, readOnly bool) (ret []byte, err error) {
|
||||
defer func() {
|
||||
state.finished = true
|
||||
}()
|
||||
|
||||
// Increment the call depth which is restricted to 1024
|
||||
in.evm.depth++
|
||||
defer func() { in.evm.depth-- }()
|
||||
|
|
@ -164,38 +168,15 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
|
|||
in.returnData = nil
|
||||
|
||||
// Don't bother with the execution if there's no code.
|
||||
if len(contract.Code) == 0 {
|
||||
if len(state.Contract.Code) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var (
|
||||
op OpCode // current opcode
|
||||
mem = NewMemory() // bound memory
|
||||
stack = newstack() // local stack
|
||||
callContext = &ScopeContext{
|
||||
Memory: mem,
|
||||
Stack: stack,
|
||||
Contract: contract,
|
||||
}
|
||||
// For optimisation reason we're using uint64 as the program counter.
|
||||
// It's theoretically possible to go above 2^64. The YP defines the PC
|
||||
// to be uint256. Practically much less so feasible.
|
||||
pc = uint64(0) // program counter
|
||||
cost uint64
|
||||
// copies used by tracer
|
||||
pcCopy uint64 // needed for the deferred EVMLogger
|
||||
gasCopy uint64 // for EVMLogger to log gas remaining before execution
|
||||
logged bool // deferred EVMLogger should ignore already logged steps
|
||||
res []byte // result of the opcode execution function
|
||||
debug = in.evm.Config.Tracer != nil
|
||||
)
|
||||
// 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
|
||||
// they are returned to the pools
|
||||
defer func() {
|
||||
returnStack(stack)
|
||||
}()
|
||||
contract.Input = input
|
||||
gethState := NewGethState(state.Contract, state.Memory, state.Stack, state.pc)
|
||||
gethState.Contract.Input = input
|
||||
|
||||
debug := in.evm.Config.Tracer != nil
|
||||
var logged bool
|
||||
|
||||
if debug {
|
||||
defer func() { // this deferred method handles exit-with-error
|
||||
|
|
@ -203,101 +184,125 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
|
|||
return
|
||||
}
|
||||
if !logged && in.evm.Config.Tracer.OnOpcode != nil {
|
||||
in.evm.Config.Tracer.OnOpcode(pcCopy, byte(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err))
|
||||
in.evm.Config.Tracer.OnOpcode(gethState.pcCopy, byte(gethState.op), gethState.gasCopy, gethState.cost, gethState.CallContext, in.returnData, in.evm.depth, VMErrorFromErr(err))
|
||||
}
|
||||
if logged && in.evm.Config.Tracer.OnFault != nil {
|
||||
in.evm.Config.Tracer.OnFault(pcCopy, byte(op), gasCopy, cost, callContext, in.evm.depth, VMErrorFromErr(err))
|
||||
in.evm.Config.Tracer.OnFault(gethState.pcCopy, byte(gethState.op), gethState.gasCopy, gethState.cost, gethState.CallContext, in.evm.depth, VMErrorFromErr(err))
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// The Interpreter main run loop (contextual). This loop runs until either an
|
||||
// explicit STOP, RETURN or SELFDESTRUCT is executed, an error occurred during
|
||||
// the execution of one of the operations or until the done flag is set by the
|
||||
// parent context.
|
||||
steps := 0
|
||||
for {
|
||||
if debug {
|
||||
// Capture pre-execution values for tracing.
|
||||
logged, pcCopy, gasCopy = false, pc, contract.Gas
|
||||
}
|
||||
// Get the operation from the jump table and validate the stack to ensure there are
|
||||
// enough stack items available to perform the operation.
|
||||
op = contract.GetOp(pc)
|
||||
operation := in.table[op]
|
||||
cost = operation.constantGas // For tracing
|
||||
// Validate stack
|
||||
if sLen := stack.len(); sLen < operation.minStack {
|
||||
return nil, &ErrStackUnderflow{stackLen: sLen, required: operation.minStack}
|
||||
} else if sLen > operation.maxStack {
|
||||
return nil, &ErrStackOverflow{stackLen: sLen, limit: operation.maxStack}
|
||||
}
|
||||
if !contract.UseGas(cost, in.evm.Config.Tracer, tracing.GasChangeIgnored) {
|
||||
return nil, ErrOutOfGas
|
||||
}
|
||||
|
||||
if operation.dynamicGas != nil {
|
||||
// All ops with a dynamic memory usage also has a dynamic gas cost.
|
||||
var memorySize uint64
|
||||
// calculate the new memory size and expand the memory to fit
|
||||
// the operation
|
||||
// Memory check needs to be done prior to evaluating the dynamic gas portion,
|
||||
// to detect calculation overflows
|
||||
if operation.memorySize != nil {
|
||||
memSize, overflow := operation.memorySize(stack)
|
||||
if overflow {
|
||||
return nil, ErrGasUintOverflow
|
||||
}
|
||||
// memory is expanded in words of 32 bytes. Gas
|
||||
// is also calculated in words.
|
||||
if memorySize, overflow = math.SafeMul(toWordSize(memSize), 32); overflow {
|
||||
return nil, ErrGasUintOverflow
|
||||
}
|
||||
}
|
||||
// Consume the gas and return an error if not enough gas is available.
|
||||
// cost is explicitly set so that the capture state defer method can get the proper cost
|
||||
var dynamicCost uint64
|
||||
dynamicCost, err = operation.dynamicGas(in.evm, contract, stack, mem, memorySize)
|
||||
cost += dynamicCost // for tracing
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
|
||||
}
|
||||
if !contract.UseGas(dynamicCost, in.evm.Config.Tracer, tracing.GasChangeIgnored) {
|
||||
return nil, ErrOutOfGas
|
||||
}
|
||||
|
||||
// Do tracing before memory expansion
|
||||
if debug {
|
||||
if in.evm.Config.Tracer.OnGasChange != nil {
|
||||
in.evm.Config.Tracer.OnGasChange(gasCopy, gasCopy-cost, tracing.GasChangeCallOpCode)
|
||||
}
|
||||
if in.evm.Config.Tracer.OnOpcode != nil {
|
||||
in.evm.Config.Tracer.OnOpcode(pc, byte(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err))
|
||||
logged = true
|
||||
}
|
||||
}
|
||||
if memorySize > 0 {
|
||||
mem.Resize(memorySize)
|
||||
}
|
||||
} else if debug {
|
||||
if in.evm.Config.Tracer.OnGasChange != nil {
|
||||
in.evm.Config.Tracer.OnGasChange(gasCopy, gasCopy-cost, tracing.GasChangeCallOpCode)
|
||||
}
|
||||
if in.evm.Config.Tracer.OnOpcode != nil {
|
||||
in.evm.Config.Tracer.OnOpcode(pc, byte(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err))
|
||||
logged = true
|
||||
}
|
||||
}
|
||||
|
||||
// execute the operation
|
||||
res, err = operation.execute(&pc, in, callContext)
|
||||
if err != nil {
|
||||
steps++
|
||||
if in.evm.abort.Load() {
|
||||
break
|
||||
}
|
||||
|
||||
if !in.Step(gethState) {
|
||||
break
|
||||
}
|
||||
pc++
|
||||
}
|
||||
|
||||
if err == errStopToken {
|
||||
err = nil // clear stop token error
|
||||
if gethState.Err == errStopToken {
|
||||
gethState.Err = nil // clear stop token error
|
||||
}
|
||||
|
||||
return res, err
|
||||
return gethState.Result, gethState.Err
|
||||
}
|
||||
|
||||
func (in *EVMInterpreter) Step(state *GethState) bool {
|
||||
debug := in.evm.Config.Tracer != nil
|
||||
if debug {
|
||||
// Capture pre-execution values for tracing.
|
||||
state.logged, state.pcCopy, state.gasCopy = false, state.Pc, state.Contract.Gas
|
||||
}
|
||||
// Get the operation from the jump table and validate the stack to ensure there are
|
||||
// enough stack items available to perform the operation.
|
||||
state.op = state.Contract.GetOp(state.Pc)
|
||||
operation := in.table[state.op]
|
||||
cost := operation.constantGas // For tracing
|
||||
// Validate stack
|
||||
if sLen := state.Stack.len(); sLen < operation.minStack {
|
||||
state.Err = &ErrStackUnderflow{stackLen: sLen, required: operation.minStack}
|
||||
return false
|
||||
|
||||
} else if sLen > operation.maxStack {
|
||||
state.Err = &ErrStackOverflow{stackLen: sLen, limit: operation.maxStack}
|
||||
return false
|
||||
}
|
||||
if !state.Contract.UseGas(cost, in.evm.Config.Tracer, tracing.GasChangeIgnored) {
|
||||
state.Err = ErrOutOfGas
|
||||
return false
|
||||
}
|
||||
|
||||
if operation.dynamicGas != nil {
|
||||
// All ops with a dynamic memory usage also has a dynamic gas cost.
|
||||
var memorySize uint64
|
||||
// calculate the new memory size and expand the memory to fit
|
||||
// the operation
|
||||
// Memory check needs to be done prior to evaluating the dynamic gas portion,
|
||||
// to detect calculation overflows
|
||||
if operation.memorySize != nil {
|
||||
memSize, overflow := operation.memorySize(state.Stack)
|
||||
if overflow {
|
||||
state.Err = ErrGasUintOverflow
|
||||
return false
|
||||
}
|
||||
// memory is expanded in words of 32 bytes. Gas
|
||||
// is also calculated in words.
|
||||
if memorySize, overflow = math.SafeMul(toWordSize(memSize), 32); overflow {
|
||||
state.Err = ErrGasUintOverflow
|
||||
return false
|
||||
}
|
||||
}
|
||||
// Consume the gas and return an error if not enough gas is available.
|
||||
// cost is explicitly set so that the capture state defer method can get the proper cost
|
||||
var dynamicCost uint64
|
||||
dynamicCost, state.Err = operation.dynamicGas(in.evm, state.Contract, state.Stack, state.Memory, memorySize)
|
||||
cost += dynamicCost // for tracing
|
||||
if state.Err != nil {
|
||||
state.Err = fmt.Errorf("%w: %v", ErrOutOfGas, state.Err)
|
||||
return false
|
||||
}
|
||||
if !state.Contract.UseGas(dynamicCost, in.evm.Config.Tracer, tracing.GasChangeIgnored) {
|
||||
state.Err = ErrOutOfGas
|
||||
return false
|
||||
}
|
||||
|
||||
// Do tracing before memory expansion
|
||||
if debug {
|
||||
if in.evm.Config.Tracer.OnGasChange != nil {
|
||||
in.evm.Config.Tracer.OnGasChange(state.gasCopy, state.gasCopy-cost, tracing.GasChangeCallOpCode)
|
||||
}
|
||||
if in.evm.Config.Tracer.OnOpcode != nil {
|
||||
in.evm.Config.Tracer.OnOpcode(state.Pc, byte(state.op), state.gasCopy, cost, state.CallContext, in.returnData, in.evm.depth, VMErrorFromErr(state.Err))
|
||||
state.logged = true
|
||||
}
|
||||
}
|
||||
if memorySize > 0 {
|
||||
state.Memory.Resize(memorySize)
|
||||
}
|
||||
} else if debug {
|
||||
if in.evm.Config.Tracer.OnGasChange != nil {
|
||||
in.evm.Config.Tracer.OnGasChange(state.gasCopy, state.gasCopy-cost, tracing.GasChangeCallOpCode)
|
||||
}
|
||||
if in.evm.Config.Tracer.OnOpcode != nil {
|
||||
in.evm.Config.Tracer.OnOpcode(state.Pc, byte(state.op), state.gasCopy, cost, state.CallContext, in.returnData, in.evm.depth, VMErrorFromErr(state.Err))
|
||||
state.logged = true
|
||||
}
|
||||
}
|
||||
|
||||
// execute the operation
|
||||
state.Result, state.Err = operation.execute(&state.Pc, in, state.CallContext)
|
||||
if state.Err != nil {
|
||||
return false
|
||||
}
|
||||
state.Pc++
|
||||
|
||||
return state.Err == nil
|
||||
}
|
||||
|
|
|
|||
165
core/vm/tosca_ct_integration.go
Normal file
165
core/vm/tosca_ct_integration.go
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
package vm
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
// Error
|
||||
var ErrStopToken = errStopToken
|
||||
|
||||
// Gas table
|
||||
func MemoryGasCost(mem *Memory, wordSize uint64) (uint64, error) {
|
||||
return memoryGasCost(mem, wordSize)
|
||||
}
|
||||
|
||||
// Stack
|
||||
func NewStack() *Stack {
|
||||
return newstack()
|
||||
}
|
||||
|
||||
func (st *Stack) Len() int {
|
||||
return st.len()
|
||||
}
|
||||
|
||||
func (st *Stack) Push(d *uint256.Int) {
|
||||
st.push(d)
|
||||
}
|
||||
|
||||
// EVM
|
||||
func (evm *EVM) GetDepth() int {
|
||||
return evm.depth
|
||||
}
|
||||
|
||||
func (evm *EVM) SetDepth(depth int) {
|
||||
evm.depth = depth
|
||||
}
|
||||
|
||||
// Interpreter
|
||||
func (g *EVMInterpreter) SetLastCallReturnData(data []byte) {
|
||||
g.returnData = data
|
||||
}
|
||||
|
||||
func (g *EVMInterpreter) GetLastCallReturnData() []byte {
|
||||
return g.returnData
|
||||
}
|
||||
|
||||
func (g *EVMInterpreter) SetReadOnly(readOnly bool) {
|
||||
g.readOnly = readOnly
|
||||
}
|
||||
|
||||
func (g *EVMInterpreter) IsReadOnly() bool {
|
||||
return g.readOnly
|
||||
}
|
||||
|
||||
// CallContext Call interceptor
|
||||
|
||||
// CallContext provides a basic interface for the EVM calling conventions. The EVM
|
||||
// depends on this context being implemented for doing subcalls and initialising new EVM contracts.
|
||||
type CallContextInterceptor interface {
|
||||
// Call calls another contract.
|
||||
Call(env *EVM, me ContractRef, addr common.Address, data []byte, gas, value *big.Int) ([]byte, uint64, error)
|
||||
// CallCode takes another contracts code and execute within our own context
|
||||
CallCode(env *EVM, me ContractRef, addr common.Address, data []byte, gas, value *big.Int) ([]byte, uint64, error)
|
||||
// DelegateCall is same as CallCode except sender and value is propagated from parent to child scope
|
||||
DelegateCall(env *EVM, me ContractRef, addr common.Address, data []byte, gas *big.Int) ([]byte, uint64, error)
|
||||
// Create creates a new contract
|
||||
Create(env *EVM, me ContractRef, data []byte, gas, value *big.Int) ([]byte, common.Address, uint64, error)
|
||||
|
||||
StaticCall(env *EVM, me ContractRef, addr common.Address, input []byte, gas *big.Int) ([]byte, uint64, error)
|
||||
Create2(env *EVM, me ContractRef, code []byte, gas *big.Int, value *big.Int, salt *uint256.Int) ([]byte, common.Address, uint64, error)
|
||||
}
|
||||
|
||||
// Interpreter interface
|
||||
// EVMInterpreter defines an interface for different interpreter implementations.
|
||||
type GethEVMInterpreter interface {
|
||||
// Run the contract's code with the given input data and returns the return byte-slice
|
||||
// and an error if one occurred.
|
||||
Run(contract *Contract, input []byte, readOnly bool) (ret []byte, err error)
|
||||
}
|
||||
|
||||
type InterpreterFactory func(evm *EVM, cfg Config) GethEVMInterpreter
|
||||
|
||||
var interpreter_registry = map[string]InterpreterFactory{}
|
||||
|
||||
func RegisterInterpreterFactory(name string, factory InterpreterFactory) {
|
||||
interpreter_registry[strings.ToLower(name)] = factory
|
||||
}
|
||||
|
||||
func NewInterpreter(name string, evm *EVM, cfg Config) GethEVMInterpreter {
|
||||
factory, found := interpreter_registry[strings.ToLower(name)]
|
||||
if !found {
|
||||
log.Error("no factory for interpreter registered", "name", name)
|
||||
}
|
||||
return factory(evm, cfg)
|
||||
}
|
||||
|
||||
func init() {
|
||||
factory := func(evm *EVM, cfg Config) GethEVMInterpreter {
|
||||
return NewEVMInterpreter(evm)
|
||||
}
|
||||
RegisterInterpreterFactory("", factory)
|
||||
RegisterInterpreterFactory("geth", factory)
|
||||
}
|
||||
|
||||
// Abstracted interpreter with single step execution.
|
||||
|
||||
// GethState represents the internal state of the interpreter.
|
||||
type GethState struct {
|
||||
Contract *Contract // processed contract
|
||||
Memory *Memory // bound memory
|
||||
Stack *Stack // local stack
|
||||
// For optimisation reason we're using uint64 as the program counter.
|
||||
// It's theoretically possible to go above 2^64. The YP defines the PC
|
||||
// to be uint256. Practically much less so feasible.
|
||||
Pc uint64 // program counter
|
||||
Result []byte // result of the opcode execution function
|
||||
Err error
|
||||
CallContext *ScopeContext
|
||||
ReadOnly bool
|
||||
Halted bool
|
||||
|
||||
op OpCode // current opcode
|
||||
cost uint64
|
||||
|
||||
// copies used by tracer
|
||||
pcCopy uint64 // needed for the deferred Tracer
|
||||
gasCopy uint64 // for Tracer to log gas remaining before execution
|
||||
logged bool // deferred Tracer should ignore already logged steps
|
||||
}
|
||||
|
||||
func NewGethState(contract *Contract, memory *Memory, stack *Stack, Pc uint64) *GethState {
|
||||
return &GethState{
|
||||
Contract: contract,
|
||||
Memory: memory,
|
||||
Stack: stack,
|
||||
Pc: Pc,
|
||||
CallContext: &ScopeContext{
|
||||
Memory: memory,
|
||||
Stack: stack,
|
||||
Contract: contract,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type InterpreterState struct {
|
||||
Contract *Contract
|
||||
Stack *Stack
|
||||
Memory *Memory
|
||||
pc uint64
|
||||
finished bool
|
||||
}
|
||||
|
||||
func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (ret []byte, err error) {
|
||||
state := InterpreterState{
|
||||
Contract: contract,
|
||||
Stack: NewStack(),
|
||||
Memory: NewMemory(),
|
||||
}
|
||||
defer returnStack(state.Stack)
|
||||
return in.run(&state, input, readOnly)
|
||||
}
|
||||
Loading…
Reference in a new issue