github.com/FUSIONFoundation/efsn@v3.6.2-0.20200916075423-dbb5dd5d2cc7+incompatible/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 "sync/atomic" 22 23 "github.com/FusionFoundation/efsn/common/math" 24 "github.com/FusionFoundation/efsn/params" 25 ) 26 27 // Config are the configuration options for the Interpreter 28 type Config struct { 29 // Debug enabled debugging Interpreter options 30 Debug bool 31 // Tracer is the op code logger 32 Tracer Tracer 33 // NoRecursion disabled Interpreter call, callcode, 34 // delegate call and create. 35 NoRecursion bool 36 // Enable recording of SHA3/keccak preimages 37 EnablePreimageRecording bool 38 // JumpTable contains the EVM instruction table. This 39 // may be left uninitialised and will be set to the default 40 // table. 41 JumpTable [256]operation 42 43 // Type of the EWASM interpreter 44 EWASMInterpreter string 45 // Type of the EVM interpreter 46 EVMInterpreter string 47 } 48 49 // Interpreter is used to run Ethereum based contracts and will utilise the 50 // passed environment to query external sources for state information. 51 // The Interpreter will run the byte code VM based on the passed 52 // configuration. 53 type Interpreter interface { 54 // Run loops and evaluates the contract's code with the given input data and returns 55 // the return byte-slice and an error if one occurred. 56 Run(contract *Contract, input []byte, static bool) ([]byte, error) 57 // CanRun tells if the contract, passed as an argument, can be 58 // run by the current interpreter. This is meant so that the 59 // caller can do something like: 60 // 61 // ```golang 62 // for _, interpreter := range interpreters { 63 // if interpreter.CanRun(contract.code) { 64 // interpreter.Run(contract.code, input) 65 // } 66 // } 67 // ``` 68 CanRun([]byte) bool 69 } 70 71 // EVMInterpreter represents an EVM interpreter 72 type EVMInterpreter struct { 73 evm *EVM 74 cfg Config 75 gasTable params.GasTable 76 intPool *intPool 77 78 readOnly bool // Whether to throw on stateful modifications 79 returnData []byte // Last CALL's return data for subsequent reuse 80 } 81 82 // NewEVMInterpreter returns a new instance of the Interpreter. 83 func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter { 84 // We use the STOP instruction whether to see 85 // the jump table was initialised. If it was not 86 // we'll set the default jump table. 87 if !cfg.JumpTable[STOP].valid { 88 switch { 89 case evm.ChainConfig().IsConstantinople(evm.BlockNumber): 90 cfg.JumpTable = constantinopleInstructionSet 91 case evm.ChainConfig().IsByzantium(evm.BlockNumber): 92 cfg.JumpTable = byzantiumInstructionSet 93 case evm.ChainConfig().IsHomestead(evm.BlockNumber): 94 cfg.JumpTable = homesteadInstructionSet 95 default: 96 cfg.JumpTable = frontierInstructionSet 97 } 98 } 99 100 return &EVMInterpreter{ 101 evm: evm, 102 cfg: cfg, 103 gasTable: evm.ChainConfig().GasTable(evm.BlockNumber), 104 } 105 } 106 107 func (in *EVMInterpreter) enforceRestrictions(op OpCode, operation operation, stack *Stack) error { 108 if in.evm.chainRules.IsByzantium { 109 if in.readOnly { 110 // If the interpreter is operating in readonly mode, make sure no 111 // state-modifying operation is performed. The 3rd stack item 112 // for a call operation is the value. Transferring value from one 113 // account to the others means the state is modified and should also 114 // return with an error. 115 if operation.writes || (op == CALL && stack.Back(2).BitLen() > 0) { 116 return errWriteProtection 117 } 118 } 119 } 120 return nil 121 } 122 123 // Run loops and evaluates the contract's code with the given input data and returns 124 // the return byte-slice and an error if one occurred. 125 // 126 // It's important to note that any errors returned by the interpreter should be 127 // considered a revert-and-consume-all-gas operation except for 128 // errExecutionReverted which means revert-and-keep-gas-left. 129 func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (ret []byte, err error) { 130 if in.intPool == nil { 131 in.intPool = poolOfIntPools.get() 132 defer func() { 133 poolOfIntPools.put(in.intPool) 134 in.intPool = nil 135 }() 136 } 137 138 // Increment the call depth which is restricted to 1024 139 in.evm.depth++ 140 defer func() { in.evm.depth-- }() 141 142 // Make sure the readOnly is only set if we aren't in readOnly yet. 143 // This makes also sure that the readOnly flag isn't removed for child calls. 144 if readOnly && !in.readOnly { 145 in.readOnly = true 146 defer func() { in.readOnly = false }() 147 } 148 149 // Reset the previous call's return data. It's unimportant to preserve the old buffer 150 // as every returning call will return new data anyway. 151 in.returnData = nil 152 153 // Don't bother with the execution if there's no code. 154 if len(contract.Code) == 0 { 155 return nil, nil 156 } 157 158 var ( 159 op OpCode // current opcode 160 mem = NewMemory() // bound memory 161 stack = newstack() // local stack 162 // For optimisation reason we're using uint64 as the program counter. 163 // It's theoretically possible to go above 2^64. The YP defines the PC 164 // to be uint256. Practically much less so feasible. 165 pc = uint64(0) // program counter 166 cost uint64 167 // copies used by tracer 168 pcCopy uint64 // needed for the deferred Tracer 169 gasCopy uint64 // for Tracer to log gas remaining before execution 170 logged bool // deferred Tracer should ignore already logged steps 171 ) 172 contract.Input = input 173 174 // Reclaim the stack as an int pool when the execution stops 175 defer func() { in.intPool.put(stack.data...) }() 176 177 if in.cfg.Debug { 178 defer func() { 179 if err != nil { 180 if !logged { 181 in.cfg.Tracer.CaptureState(in.evm, pcCopy, op, gasCopy, cost, mem, stack, contract, in.evm.depth, err) 182 } else { 183 in.cfg.Tracer.CaptureFault(in.evm, pcCopy, op, gasCopy, cost, mem, stack, contract, in.evm.depth, err) 184 } 185 } 186 }() 187 } 188 // The Interpreter main run loop (contextual). This loop runs until either an 189 // explicit STOP, RETURN or SELFDESTRUCT is executed, an error occurred during 190 // the execution of one of the operations or until the done flag is set by the 191 // parent context. 192 for atomic.LoadInt32(&in.evm.abort) == 0 { 193 if in.cfg.Debug { 194 // Capture pre-execution values for tracing. 195 logged, pcCopy, gasCopy = false, pc, contract.Gas 196 } 197 198 // Get the operation from the jump table and validate the stack to ensure there are 199 // enough stack items available to perform the operation. 200 op = contract.GetOp(pc) 201 operation := in.cfg.JumpTable[op] 202 if !operation.valid { 203 return nil, fmt.Errorf("invalid opcode 0x%x", int(op)) 204 } 205 if err := operation.validateStack(stack); err != nil { 206 return nil, err 207 } 208 // If the operation is valid, enforce and write restrictions 209 if err := in.enforceRestrictions(op, operation, stack); err != nil { 210 return nil, err 211 } 212 213 var memorySize uint64 214 // calculate the new memory size and expand the memory to fit 215 // the operation 216 if operation.memorySize != nil { 217 memSize, overflow := bigUint64(operation.memorySize(stack)) 218 if overflow { 219 return nil, errGasUintOverflow 220 } 221 // memory is expanded in words of 32 bytes. Gas 222 // is also calculated in words. 223 if memorySize, overflow = math.SafeMul(toWordSize(memSize), 32); overflow { 224 return nil, errGasUintOverflow 225 } 226 } 227 // consume the gas and return an error if not enough gas is available. 228 // cost is explicitly set so that the capture state defer method can get the proper cost 229 cost, err = operation.gasCost(in.gasTable, in.evm, contract, stack, mem, memorySize) 230 if err != nil || !contract.UseGas(cost) { 231 return nil, ErrOutOfGas 232 } 233 if memorySize > 0 { 234 mem.Resize(memorySize) 235 } 236 237 if in.cfg.Debug { 238 in.cfg.Tracer.CaptureState(in.evm, pc, op, gasCopy, cost, mem, stack, contract, in.evm.depth, err) 239 logged = true 240 } 241 242 // execute the operation 243 res, err := operation.execute(&pc, in, contract, mem, stack) 244 // verifyPool is a build flag. Pool verification makes sure the integrity 245 // of the integer pool by comparing values to a default value. 246 if verifyPool { 247 verifyIntegerPool(in.intPool) 248 } 249 // if the operation clears the return data (e.g. it has returning data) 250 // set the last return to the result of the operation. 251 if operation.returns { 252 in.returnData = res 253 } 254 255 switch { 256 case err != nil: 257 return nil, err 258 case operation.reverts: 259 return res, errExecutionReverted 260 case operation.halts: 261 return res, nil 262 case !operation.jumps: 263 pc++ 264 } 265 } 266 return nil, nil 267 } 268 269 // CanRun tells if the contract, passed as an argument, can be 270 // run by the current interpreter. 271 func (in *EVMInterpreter) CanRun(code []byte) bool { 272 return true 273 }