github.com/avence12/go-ethereum@v1.5.10-0.20170320123548-1dfd65f6d047/core/vm/interpreter.go (about) 1 // Copyright 2014 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package vm 18 19 import ( 20 "fmt" 21 "math/big" 22 "sync/atomic" 23 "time" 24 25 "github.com/ethereum/go-ethereum/common" 26 "github.com/ethereum/go-ethereum/common/math" 27 "github.com/ethereum/go-ethereum/crypto" 28 "github.com/ethereum/go-ethereum/log" 29 "github.com/ethereum/go-ethereum/params" 30 ) 31 32 // Config are the configuration options for the Interpreter 33 type Config struct { 34 // Debug enabled debugging Interpreter options 35 Debug bool 36 // EnableJit enabled the JIT VM 37 EnableJit bool 38 // ForceJit forces the JIT VM 39 ForceJit bool 40 // Tracer is the op code logger 41 Tracer Tracer 42 // NoRecursion disabled Interpreter call, callcode, 43 // delegate call and create. 44 NoRecursion bool 45 // Disable gas metering 46 DisableGasMetering bool 47 // Enable recording of SHA3/keccak preimages 48 EnablePreimageRecording bool 49 // JumpTable contains the EVM instruction table. This 50 // may me left uninitialised and will be set the default 51 // table. 52 JumpTable [256]operation 53 } 54 55 // Interpreter is used to run Ethereum based contracts and will utilise the 56 // passed environment to query external sources for state information. 57 // The Interpreter will run the byte code VM or JIT VM based on the passed 58 // configuration. 59 type Interpreter struct { 60 env *EVM 61 cfg Config 62 gasTable params.GasTable 63 intPool *intPool 64 } 65 66 // NewInterpreter returns a new instance of the Interpreter. 67 func NewInterpreter(env *EVM, cfg Config) *Interpreter { 68 // We use the STOP instruction whether to see 69 // the jump table was initialised. If it was not 70 // we'll set the default jump table. 71 if !cfg.JumpTable[STOP].valid { 72 cfg.JumpTable = defaultJumpTable 73 } 74 75 return &Interpreter{ 76 env: env, 77 cfg: cfg, 78 gasTable: env.ChainConfig().GasTable(env.BlockNumber), 79 intPool: newIntPool(), 80 } 81 } 82 83 // Run loops and evaluates the contract's code with the given input data 84 func (evm *Interpreter) Run(contract *Contract, input []byte) (ret []byte, err error) { 85 evm.env.depth++ 86 defer func() { evm.env.depth-- }() 87 88 if contract.CodeAddr != nil { 89 if p := PrecompiledContracts[*contract.CodeAddr]; p != nil { 90 return RunPrecompiledContract(p, input, contract) 91 } 92 } 93 94 // Don't bother with the execution if there's no code. 95 if len(contract.Code) == 0 { 96 return nil, nil 97 } 98 99 codehash := contract.CodeHash // codehash is used when doing jump dest caching 100 if codehash == (common.Hash{}) { 101 codehash = crypto.Keccak256Hash(contract.Code) 102 } 103 104 var ( 105 op OpCode // current opcode 106 mem = NewMemory() // bound memory 107 stack = newstack() // local stack 108 // For optimisation reason we're using uint64 as the program counter. 109 // It's theoretically possible to go above 2^64. The YP defines the PC to be uint256. Practically much less so feasible. 110 pc = uint64(0) // program counter 111 cost uint64 112 ) 113 contract.Input = input 114 115 // User defer pattern to check for an error and, based on the error being nil or not, use all gas and return. 116 defer func() { 117 if err != nil && evm.cfg.Debug { 118 // XXX For debugging 119 //fmt.Printf("%04d: %8v cost = %-8d stack = %-8d ERR = %v\n", pc, op, cost, stack.len(), err) 120 // TODO update the tracer 121 g, c := new(big.Int).SetUint64(contract.Gas), new(big.Int).SetUint64(cost) 122 evm.cfg.Tracer.CaptureState(evm.env, pc, op, g, c, mem, stack, contract, evm.env.depth, err) 123 } 124 }() 125 126 log.Debug("EVM running contract", "hash", codehash[:]) 127 tstart := time.Now() 128 defer log.Debug("EVM finished running contract", "hash", codehash[:], "elapsed", time.Since(tstart)) 129 130 // The Interpreter main run loop (contextual). This loop runs until either an 131 // explicit STOP, RETURN or SELFDESTRUCT is executed, an error occurred during 132 // the execution of one of the operations or until the evm.done is set by 133 // the parent context.Context. 134 for atomic.LoadInt32(&evm.env.abort) == 0 { 135 // Get the memory location of pc 136 op = contract.GetOp(pc) 137 138 // get the operation from the jump table matching the opcode 139 operation := evm.cfg.JumpTable[op] 140 141 // if the op is invalid abort the process and return an error 142 if !operation.valid { 143 return nil, fmt.Errorf("invalid opcode %x", op) 144 } 145 146 // validate the stack and make sure there enough stack items available 147 // to perform the operation 148 if err := operation.validateStack(stack); err != nil { 149 return nil, err 150 } 151 152 var memorySize uint64 153 // calculate the new memory size and expand the memory to fit 154 // the operation 155 if operation.memorySize != nil { 156 memSize, overflow := bigUint64(operation.memorySize(stack)) 157 if overflow { 158 return nil, errGasUintOverflow 159 } 160 // memory is expanded in words of 32 bytes. Gas 161 // is also calculated in words. 162 if memorySize, overflow = math.SafeMul(toWordSize(memSize), 32); overflow { 163 return nil, errGasUintOverflow 164 } 165 } 166 167 if !evm.cfg.DisableGasMetering { 168 // consume the gas and return an error if not enough gas is available. 169 // cost is explicitly set so that the capture state defer method cas get the proper cost 170 cost, err = operation.gasCost(evm.gasTable, evm.env, contract, stack, mem, memorySize) 171 if err != nil || !contract.UseGas(cost) { 172 return nil, ErrOutOfGas 173 } 174 } 175 if memorySize > 0 { 176 mem.Resize(memorySize) 177 } 178 179 if evm.cfg.Debug { 180 g, c := new(big.Int).SetUint64(contract.Gas), new(big.Int).SetUint64(cost) 181 evm.cfg.Tracer.CaptureState(evm.env, pc, op, g, c, mem, stack, contract, evm.env.depth, err) 182 } 183 // XXX For debugging 184 //fmt.Printf("%04d: %8v cost = %-8d stack = %-8d\n", pc, op, cost, stack.len()) 185 186 // execute the operation 187 res, err := operation.execute(&pc, evm.env, contract, mem, stack) 188 // verifyPool is a build flag. Pool verification makes sure the integrity 189 // of the integer pool by comparing values to a default value. 190 if verifyPool { 191 verifyIntegerPool(evm.intPool) 192 } 193 switch { 194 case err != nil: 195 return nil, err 196 case operation.halts: 197 return res, nil 198 case !operation.jumps: 199 pc++ 200 } 201 } 202 return nil, nil 203 }