github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/core/vm/interpreter.go (about) 1 package vm 2 3 import ( 4 "fmt" 5 "sync/atomic" 6 7 "github.com/quickchainproject/quickchain/common/math" 8 "github.com/quickchainproject/quickchain/params" 9 ) 10 11 // Config are the configuration options for the Interpreter 12 type Config struct { 13 // Debug enabled debugging Interpreter options 14 Debug bool 15 // Tracer is the op code logger 16 Tracer Tracer 17 // NoRecursion disabled Interpreter call, callcode, 18 // delegate call and create. 19 NoRecursion bool 20 // Enable recording of SHA3/keccak preimages 21 EnablePreimageRecording bool 22 // JumpTable contains the EVM instruction table. This 23 // may be left uninitialised and will be set to the default 24 // table. 25 JumpTable [256]operation 26 } 27 28 // Interpreter is used to run Ethereum based contracts and will utilise the 29 // passed environment to query external sources for state information. 30 // The Interpreter will run the byte code VM based on the passed 31 // configuration. 32 type Interpreter struct { 33 evm *EVM 34 cfg Config 35 gasTable params.GasTable 36 intPool *intPool 37 38 readOnly bool // Whether to throw on stateful modifications 39 returnData []byte // Last CALL's return data for subsequent reuse 40 } 41 42 // NewInterpreter returns a new instance of the Interpreter. 43 func NewInterpreter(evm *EVM, cfg Config) *Interpreter { 44 // We use the STOP instruction whether to see 45 // the jump table was initialised. If it was not 46 // we'll set the default jump table. 47 if !cfg.JumpTable[STOP].valid { 48 switch { 49 case evm.ChainConfig().IsConstantinople(evm.BlockNumber): 50 cfg.JumpTable = constantinopleInstructionSet 51 case evm.ChainConfig().IsByzantium(evm.BlockNumber): 52 cfg.JumpTable = byzantiumInstructionSet 53 case evm.ChainConfig().IsHomestead(evm.BlockNumber): 54 cfg.JumpTable = homesteadInstructionSet 55 default: 56 cfg.JumpTable = frontierInstructionSet 57 } 58 } 59 60 return &Interpreter{ 61 evm: evm, 62 cfg: cfg, 63 gasTable: evm.ChainConfig().GasTable(evm.BlockNumber), 64 intPool: newIntPool(), 65 } 66 } 67 68 func (in *Interpreter) enforceRestrictions(op OpCode, operation operation, stack *Stack) error { 69 if in.evm.chainRules.IsByzantium { 70 if in.readOnly { 71 // If the interpreter is operating in readonly mode, make sure no 72 // state-modifying operation is performed. The 3rd stack item 73 // for a call operation is the value. Transferring value from one 74 // account to the others means the state is modified and should also 75 // return with an error. 76 if operation.writes || (op == CALL && stack.Back(2).BitLen() > 0) { 77 return errWriteProtection 78 } 79 } 80 } 81 return nil 82 } 83 84 // Run loops and evaluates the contract's code with the given input data and returns 85 // the return byte-slice and an error if one occurred. 86 // 87 // It's important to note that any errors returned by the interpreter should be 88 // considered a revert-and-consume-all-gas operation except for 89 // errExecutionReverted which means revert-and-keep-gas-left. 90 func (in *Interpreter) Run(contract *Contract, input []byte) (ret []byte, err error) { 91 // Increment the call depth which is restricted to 1024 92 in.evm.depth++ 93 defer func() { in.evm.depth-- }() 94 95 // Reset the previous call's return data. It's unimportant to preserve the old buffer 96 // as every returning call will return new data anyway. 97 in.returnData = nil 98 99 // Don't bother with the execution if there's no code. 100 if len(contract.Code) == 0 { 101 return nil, nil 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 110 // to be uint256. Practically much less so feasible. 111 pc = uint64(0) // program counter 112 cost uint64 113 // copies used by tracer 114 pcCopy uint64 // needed for the deferred Tracer 115 gasCopy uint64 // for Tracer to log gas remaining before execution 116 logged bool // deferred Tracer should ignore already logged steps 117 ) 118 contract.Input = input 119 120 if in.cfg.Debug { 121 defer func() { 122 if err != nil { 123 if !logged { 124 in.cfg.Tracer.CaptureState(in.evm, pcCopy, op, gasCopy, cost, mem, stack, contract, in.evm.depth, err) 125 } else { 126 in.cfg.Tracer.CaptureFault(in.evm, pcCopy, op, gasCopy, cost, mem, stack, contract, in.evm.depth, err) 127 } 128 } 129 }() 130 } 131 // The Interpreter main run loop (contextual). This loop runs until either an 132 // explicit STOP, RETURN or SELFDESTRUCT is executed, an error occurred during 133 // the execution of one of the operations or until the done flag is set by the 134 // parent context. 135 for atomic.LoadInt32(&in.evm.abort) == 0 { 136 if in.cfg.Debug { 137 // Capture pre-execution values for tracing. 138 logged, pcCopy, gasCopy = false, pc, contract.Gas 139 } 140 141 // Get the operation from the jump table and validate the stack to ensure there are 142 // enough stack items available to perform the operation. 143 op = contract.GetOp(pc) 144 operation := in.cfg.JumpTable[op] 145 if !operation.valid { 146 return nil, fmt.Errorf("invalid opcode 0x%x", int(op)) 147 } 148 if err := operation.validateStack(stack); err != nil { 149 return nil, err 150 } 151 // If the operation is valid, enforce and write restrictions 152 if err := in.enforceRestrictions(op, operation, stack); err != nil { 153 return nil, err 154 } 155 156 var memorySize uint64 157 // calculate the new memory size and expand the memory to fit 158 // the operation 159 if operation.memorySize != nil { 160 memSize, overflow := bigUint64(operation.memorySize(stack)) 161 if overflow { 162 return nil, errGasUintOverflow 163 } 164 // memory is expanded in words of 32 bytes. Gas 165 // is also calculated in words. 166 if memorySize, overflow = math.SafeMul(toWordSize(memSize), 32); overflow { 167 return nil, errGasUintOverflow 168 } 169 } 170 // consume the gas and return an error if not enough gas is available. 171 // cost is explicitly set so that the capture state defer method can get the proper cost 172 cost, err = operation.gasCost(in.gasTable, in.evm, contract, stack, mem, memorySize) 173 if err != nil || !contract.UseGas(cost) { 174 return nil, ErrOutOfGas 175 } 176 if memorySize > 0 { 177 mem.Resize(memorySize) 178 } 179 180 if in.cfg.Debug { 181 in.cfg.Tracer.CaptureState(in.evm, pc, op, gasCopy, cost, mem, stack, contract, in.evm.depth, err) 182 logged = true 183 } 184 185 // execute the operation 186 res, err := operation.execute(&pc, in.evm, contract, mem, stack) 187 // verifyPool is a build flag. Pool verification makes sure the integrity 188 // of the integer pool by comparing values to a default value. 189 if verifyPool { 190 verifyIntegerPool(in.intPool) 191 } 192 // if the operation clears the return data (e.g. it has returning data) 193 // set the last return to the result of the operation. 194 if operation.returns { 195 in.returnData = res 196 } 197 198 switch { 199 case err != nil: 200 return nil, err 201 case operation.reverts: 202 return res, errExecutionReverted 203 case operation.halts: 204 return res, nil 205 case !operation.jumps: 206 pc++ 207 } 208 } 209 return nil, nil 210 }