github.com/cryptotooltop/go-ethereum@v0.0.0-20231103184714-151d1922f3e5/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 "hash" 21 "sync/atomic" 22 23 "github.com/scroll-tech/go-ethereum/common" 24 "github.com/scroll-tech/go-ethereum/common/math" 25 "github.com/scroll-tech/go-ethereum/log" 26 ) 27 28 // Config are the configuration options for the Interpreter 29 type Config struct { 30 Debug bool // Enables debugging 31 Tracer EVMLogger // Opcode logger 32 NoRecursion bool // Disables call, callcode, delegate call and create 33 NoBaseFee bool // Forces the EIP-1559 baseFee to 0 (needed for 0 price calls) 34 EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages 35 36 JumpTable [256]*operation // EVM instruction table, automatically populated if unset 37 38 ExtraEips []int // Additional EIPS that are to be enabled 39 } 40 41 // ScopeContext contains the things that are per-call, such as stack and memory, 42 // but not transients like pc and gas 43 type ScopeContext struct { 44 Memory *Memory 45 Stack *Stack 46 Contract *Contract 47 } 48 49 // keccakState wraps sha3.state. In addition to the usual hash methods, it also supports 50 // Read to get a variable amount of data from the hash state. Read is faster than Sum 51 // because it doesn't copy the internal state, but also modifies the internal state. 52 type keccakState interface { 53 hash.Hash 54 Read([]byte) (int, error) 55 } 56 57 // EVMInterpreter represents an EVM interpreter 58 type EVMInterpreter struct { 59 evm *EVM 60 cfg Config 61 62 hasher keccakState // Keccak256 hasher instance shared across opcodes 63 hasherBuf common.Hash // Keccak256 hasher result array shared aross opcodes 64 65 readOnly bool // Whether to throw on stateful modifications 66 returnData []byte // Last CALL's return data for subsequent reuse 67 } 68 69 // NewEVMInterpreter returns a new instance of the Interpreter. 70 func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter { 71 // We use the STOP instruction whether to see 72 // the jump table was initialised. If it was not 73 // we'll set the default jump table. 74 if cfg.JumpTable[STOP] == nil { 75 var jt JumpTable 76 switch { 77 case evm.chainRules.IsShanghai: 78 jt = shanghaiInstructionSet 79 case evm.chainRules.IsLondon: 80 jt = londonInstructionSet 81 case evm.chainRules.IsBerlin: 82 jt = berlinInstructionSet 83 case evm.chainRules.IsIstanbul: 84 jt = istanbulInstructionSet 85 case evm.chainRules.IsConstantinople: 86 jt = constantinopleInstructionSet 87 case evm.chainRules.IsByzantium: 88 jt = byzantiumInstructionSet 89 case evm.chainRules.IsEIP158: 90 jt = spuriousDragonInstructionSet 91 case evm.chainRules.IsEIP150: 92 jt = tangerineWhistleInstructionSet 93 case evm.chainRules.IsHomestead: 94 jt = homesteadInstructionSet 95 default: 96 jt = frontierInstructionSet 97 } 98 for i, eip := range cfg.ExtraEips { 99 if err := EnableEIP(eip, &jt); err != nil { 100 // Disable it, so caller can check if it's activated or not 101 cfg.ExtraEips = append(cfg.ExtraEips[:i], cfg.ExtraEips[i+1:]...) 102 log.Error("EIP activation failed", "eip", eip, "error", err) 103 } 104 } 105 cfg.JumpTable = jt 106 } 107 108 return &EVMInterpreter{ 109 evm: evm, 110 cfg: cfg, 111 } 112 } 113 114 // Run loops and evaluates the contract's code with the given input data and returns 115 // the return byte-slice and an error if one occurred. 116 // 117 // It's important to note that any errors returned by the interpreter should be 118 // considered a revert-and-consume-all-gas operation except for 119 // ErrExecutionReverted which means revert-and-keep-gas-left. 120 func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (ret []byte, err error) { 121 122 // Increment the call depth which is restricted to 1024 123 in.evm.depth++ 124 defer func() { in.evm.depth-- }() 125 126 // Make sure the readOnly is only set if we aren't in readOnly yet. 127 // This also makes sure that the readOnly flag isn't removed for child calls. 128 if readOnly && !in.readOnly { 129 in.readOnly = true 130 defer func() { in.readOnly = false }() 131 } 132 133 // Reset the previous call's return data. It's unimportant to preserve the old buffer 134 // as every returning call will return new data anyway. 135 in.returnData = nil 136 137 // Don't bother with the execution if there's no code. 138 if len(contract.Code) == 0 { 139 return nil, nil 140 } 141 142 var ( 143 op OpCode // current opcode 144 mem = NewMemory() // bound memory 145 stack = newstack() // local stack 146 callContext = &ScopeContext{ 147 Memory: mem, 148 Stack: stack, 149 Contract: contract, 150 } 151 // For optimisation reason we're using uint64 as the program counter. 152 // It's theoretically possible to go above 2^64. The YP defines the PC 153 // to be uint256. Practically much less so feasible. 154 pc = uint64(0) // program counter 155 cost uint64 156 // copies used by tracer 157 pcCopy uint64 // needed for the deferred EVMLogger 158 gasCopy uint64 // for EVMLogger to log gas remaining before execution 159 logged bool // deferred EVMLogger should ignore already logged steps 160 res []byte // result of the opcode execution function 161 ) 162 // Don't move this deferrred function, it's placed before the capturestate-deferred method, 163 // so that it get's executed _after_: the capturestate needs the stacks before 164 // they are returned to the pools 165 defer func() { 166 returnStack(stack) 167 }() 168 contract.Input = input 169 170 if in.cfg.Debug { 171 defer func() { 172 if err != nil { 173 if !logged { 174 in.cfg.Tracer.CaptureState(pcCopy, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err) 175 } else { 176 in.cfg.Tracer.CaptureFault(pcCopy, op, gasCopy, cost, callContext, in.evm.depth, err) 177 } 178 } 179 }() 180 } 181 // The Interpreter main run loop (contextual). This loop runs until either an 182 // explicit STOP, RETURN or SELFDESTRUCT is executed, an error occurred during 183 // the execution of one of the operations or until the done flag is set by the 184 // parent context. 185 steps := 0 186 for { 187 steps++ 188 if steps%1000 == 0 && atomic.LoadInt32(&in.evm.abort) != 0 { 189 break 190 } 191 if in.cfg.Debug { 192 // Capture pre-execution values for tracing. 193 logged, pcCopy, gasCopy = false, pc, contract.Gas 194 } 195 196 // Get the operation from the jump table and validate the stack to ensure there are 197 // enough stack items available to perform the operation. 198 op = contract.GetOp(pc) 199 operation := in.cfg.JumpTable[op] 200 if operation == nil { 201 return nil, &ErrInvalidOpCode{opcode: op} 202 } 203 // Validate stack 204 if sLen := stack.len(); sLen < operation.minStack { 205 return nil, &ErrStackUnderflow{stackLen: sLen, required: operation.minStack} 206 } else if sLen > operation.maxStack { 207 return nil, &ErrStackOverflow{stackLen: sLen, limit: operation.maxStack} 208 } 209 // If the operation is valid, enforce write restrictions 210 if in.readOnly && in.evm.chainRules.IsByzantium { 211 // If the interpreter is operating in readonly mode, make sure no 212 // state-modifying operation is performed. The 3rd stack item 213 // for a call operation is the value. Transferring value from one 214 // account to the others means the state is modified and should also 215 // return with an error. 216 if operation.writes || (op == CALL && stack.Back(2).Sign() != 0) { 217 return nil, ErrWriteProtection 218 } 219 } 220 // Static portion of gas 221 cost = operation.constantGas // For tracing 222 if !contract.UseGas(operation.constantGas) { 223 return nil, ErrOutOfGas 224 } 225 226 var memorySize uint64 227 // calculate the new memory size and expand the memory to fit 228 // the operation 229 // Memory check needs to be done prior to evaluating the dynamic gas portion, 230 // to detect calculation overflows 231 if operation.memorySize != nil { 232 memSize, overflow := operation.memorySize(stack) 233 if overflow { 234 return nil, ErrGasUintOverflow 235 } 236 // memory is expanded in words of 32 bytes. Gas 237 // is also calculated in words. 238 if memorySize, overflow = math.SafeMul(toWordSize(memSize), 32); overflow { 239 return nil, ErrGasUintOverflow 240 } 241 } 242 // Dynamic portion of gas 243 // consume the gas and return an error if not enough gas is available. 244 // cost is explicitly set so that the capture state defer method can get the proper cost 245 if operation.dynamicGas != nil { 246 var dynamicCost uint64 247 dynamicCost, err = operation.dynamicGas(in.evm, contract, stack, mem, memorySize) 248 cost += dynamicCost // total cost, for debug tracing 249 if err != nil || !contract.UseGas(dynamicCost) { 250 return nil, ErrOutOfGas 251 } 252 // Do tracing before memory expansion 253 if in.cfg.Debug { 254 in.cfg.Tracer.CaptureState(pc, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err) 255 logged = true 256 } 257 if memorySize > 0 { 258 mem.Resize(memorySize) 259 } 260 } else if in.cfg.Debug { 261 in.cfg.Tracer.CaptureState(pc, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err) 262 logged = true 263 } 264 265 // execute the operation 266 res, err = operation.execute(&pc, in, callContext) 267 // if the operation clears the return data (e.g. it has returning data) 268 // set the last return to the result of the operation. 269 if operation.returns { 270 in.returnData = res 271 } 272 273 if in.cfg.Debug { 274 in.cfg.Tracer.CaptureStateAfter(pc, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err) 275 } 276 277 switch { 278 case err != nil: 279 return nil, err 280 case operation.reverts: 281 return res, ErrExecutionReverted 282 case operation.halts: 283 return res, nil 284 case !operation.jumps: 285 pc++ 286 } 287 } 288 return nil, nil 289 }