github.com/palisadeinc/bor@v0.0.0-20230615125219-ab7196213d15/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 "context" 21 "errors" 22 "hash" 23 "time" 24 25 "github.com/ethereum/go-ethereum/common" 26 "github.com/ethereum/go-ethereum/common/math" 27 "github.com/ethereum/go-ethereum/log" 28 "github.com/ethereum/go-ethereum/metrics" 29 30 lru "github.com/hashicorp/golang-lru" 31 ) 32 33 var ( 34 opcodeCommitInterruptCounter = metrics.NewRegisteredCounter("worker/opcodeCommitInterrupt", nil) 35 ErrInterrupt = errors.New("EVM execution interrupted") 36 ErrNoCache = errors.New("no tx cache found") 37 ErrNoCurrentTx = errors.New("no current tx found in interruptCtx") 38 ) 39 40 const ( 41 // These are keys for the interruptCtx 42 InterruptCtxDelayKey = "delay" 43 InterruptCtxOpcodeDelayKey = "opcodeDelay" 44 45 // InterruptedTxCacheSize is size of lru cache for interrupted txs 46 InterruptedTxCacheSize = 90000 47 ) 48 49 // Config are the configuration options for the Interpreter 50 type Config struct { 51 Debug bool // Enables debugging 52 Tracer EVMLogger // Opcode logger 53 NoBaseFee bool // Forces the EIP-1559 baseFee to 0 (needed for 0 price calls) 54 EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages 55 56 JumpTable *JumpTable // EVM instruction table, automatically populated if unset 57 58 ExtraEips []int // Additional EIPS that are to be enabled 59 60 // parallel EVM configs 61 ParallelEnable bool 62 ParallelSpeculativeProcesses int 63 } 64 65 // ScopeContext contains the things that are per-call, such as stack and memory, 66 // but not transients like pc and gas 67 type ScopeContext struct { 68 Memory *Memory 69 Stack *Stack 70 Contract *Contract 71 } 72 73 // keccakState wraps sha3.state. In addition to the usual hash methods, it also supports 74 // Read to get a variable amount of data from the hash state. Read is faster than Sum 75 // because it doesn't copy the internal state, but also modifies the internal state. 76 type keccakState interface { 77 hash.Hash 78 Read([]byte) (int, error) 79 } 80 81 // EVMInterpreter represents an EVM interpreter 82 type EVMInterpreter struct { 83 evm *EVM 84 cfg Config 85 86 hasher keccakState // Keccak256 hasher instance shared across opcodes 87 hasherBuf common.Hash // Keccak256 hasher result array shared aross opcodes 88 89 readOnly bool // Whether to throw on stateful modifications 90 returnData []byte // Last CALL's return data for subsequent reuse 91 } 92 93 // TxCacher is an wrapper of lru.cache for caching transactions that get interrupted 94 type TxCache struct { 95 Cache *lru.Cache 96 } 97 98 type txCacheKey struct{} 99 type InterruptedTxContext_currenttxKey struct{} 100 101 // SetCurrentTxOnContext sets the current tx on the context 102 func SetCurrentTxOnContext(ctx context.Context, txHash common.Hash) context.Context { 103 return context.WithValue(ctx, InterruptedTxContext_currenttxKey{}, txHash) 104 } 105 106 // GetCurrentTxFromContext gets the current tx from the context 107 func GetCurrentTxFromContext(ctx context.Context) (common.Hash, error) { 108 val := ctx.Value(InterruptedTxContext_currenttxKey{}) 109 if val == nil { 110 return common.Hash{}, ErrNoCurrentTx 111 } 112 113 c, ok := val.(common.Hash) 114 if !ok { 115 return common.Hash{}, ErrNoCurrentTx 116 } 117 118 return c, nil 119 } 120 121 // GetCache returns the txCache from the context 122 func GetCache(ctx context.Context) (*TxCache, error) { 123 val := ctx.Value(txCacheKey{}) 124 if val == nil { 125 return nil, ErrNoCache 126 } 127 128 c, ok := val.(*TxCache) 129 if !ok { 130 return nil, ErrNoCache 131 } 132 133 return c, nil 134 } 135 136 // PutCache puts the txCache into the context 137 func PutCache(ctx context.Context, cache *TxCache) context.Context { 138 return context.WithValue(ctx, txCacheKey{}, cache) 139 } 140 141 // NewEVMInterpreter returns a new instance of the Interpreter. 142 func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter { 143 // If jump table was not initialised we set the default one. 144 if cfg.JumpTable == nil { 145 switch { 146 case evm.chainRules.IsMerge: 147 cfg.JumpTable = &mergeInstructionSet 148 case evm.chainRules.IsLondon: 149 cfg.JumpTable = &londonInstructionSet 150 case evm.chainRules.IsBerlin: 151 cfg.JumpTable = &berlinInstructionSet 152 case evm.chainRules.IsIstanbul: 153 cfg.JumpTable = &istanbulInstructionSet 154 case evm.chainRules.IsConstantinople: 155 cfg.JumpTable = &constantinopleInstructionSet 156 case evm.chainRules.IsByzantium: 157 cfg.JumpTable = &byzantiumInstructionSet 158 case evm.chainRules.IsEIP158: 159 cfg.JumpTable = &spuriousDragonInstructionSet 160 case evm.chainRules.IsEIP150: 161 cfg.JumpTable = &tangerineWhistleInstructionSet 162 case evm.chainRules.IsHomestead: 163 cfg.JumpTable = &homesteadInstructionSet 164 default: 165 cfg.JumpTable = &frontierInstructionSet 166 } 167 for i, eip := range cfg.ExtraEips { 168 copy := *cfg.JumpTable 169 if err := EnableEIP(eip, ©); err != nil { 170 // Disable it, so caller can check if it's activated or not 171 cfg.ExtraEips = append(cfg.ExtraEips[:i], cfg.ExtraEips[i+1:]...) 172 log.Error("EIP activation failed", "eip", eip, "error", err) 173 } 174 cfg.JumpTable = © 175 } 176 } 177 178 return &EVMInterpreter{ 179 evm: evm, 180 cfg: cfg, 181 } 182 } 183 184 // PreRun is a wrapper around Run that allows for a delay to be injected before each opcode when induced by tests else it calls the lagace Run() method 185 func (in *EVMInterpreter) PreRun(contract *Contract, input []byte, readOnly bool, interruptCtx context.Context) (ret []byte, err error) { 186 var opcodeDelay interface{} 187 188 if interruptCtx != nil { 189 if interruptCtx.Value(InterruptCtxOpcodeDelayKey) != nil { 190 opcodeDelay = interruptCtx.Value(InterruptCtxOpcodeDelayKey) 191 } 192 } 193 194 if opcodeDelay != nil { 195 return in.RunWithDelay(contract, input, readOnly, interruptCtx, opcodeDelay.(uint)) 196 } 197 198 return in.Run(contract, input, readOnly, interruptCtx) 199 } 200 201 // Run loops and evaluates the contract's code with the given input data and returns 202 // the return byte-slice and an error if one occurred. 203 // 204 // It's important to note that any errors returned by the interpreter should be 205 // considered a revert-and-consume-all-gas operation except for 206 // ErrExecutionReverted which means revert-and-keep-gas-left. 207 // nolint: gocognit 208 func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool, interruptCtx context.Context) (ret []byte, err error) { 209 // Increment the call depth which is restricted to 1024 210 in.evm.depth++ 211 defer func() { in.evm.depth-- }() 212 213 // Make sure the readOnly is only set if we aren't in readOnly yet. 214 // This also makes sure that the readOnly flag isn't removed for child calls. 215 if readOnly && !in.readOnly { 216 in.readOnly = true 217 defer func() { in.readOnly = false }() 218 } 219 220 // Reset the previous call's return data. It's unimportant to preserve the old buffer 221 // as every returning call will return new data anyway. 222 in.returnData = nil 223 224 // Don't bother with the execution if there's no code. 225 if len(contract.Code) == 0 { 226 return nil, nil 227 } 228 229 var ( 230 op OpCode // current opcode 231 mem = NewMemory() // bound memory 232 stack = newstack() // local stack 233 callContext = &ScopeContext{ 234 Memory: mem, 235 Stack: stack, 236 Contract: contract, 237 } 238 // For optimisation reason we're using uint64 as the program counter. 239 // It's theoretically possible to go above 2^64. The YP defines the PC 240 // to be uint256. Practically much less so feasible. 241 pc = uint64(0) // program counter 242 cost uint64 243 // copies used by tracer 244 pcCopy uint64 // needed for the deferred EVMLogger 245 gasCopy uint64 // for EVMLogger to log gas remaining before execution 246 logged bool // deferred EVMLogger should ignore already logged steps 247 res []byte // result of the opcode execution function 248 ) 249 // Don't move this deferrred function, it's placed before the capturestate-deferred method, 250 // so that it get's executed _after_: the capturestate needs the stacks before 251 // they are returned to the pools 252 defer func() { 253 returnStack(stack) 254 }() 255 256 contract.Input = input 257 258 if in.cfg.Debug { 259 defer func() { 260 if err != nil { 261 if !logged { 262 in.cfg.Tracer.CaptureState(pcCopy, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err) 263 } else { 264 in.cfg.Tracer.CaptureFault(pcCopy, op, gasCopy, cost, callContext, in.evm.depth, err) 265 } 266 } 267 }() 268 } 269 // The Interpreter main run loop (contextual). This loop runs until either an 270 // explicit STOP, RETURN or SELFDESTRUCT is executed, an error occurred during 271 // the execution of one of the operations or until the done flag is set by the 272 // parent context. 273 for { 274 if interruptCtx != nil { 275 // case of interrupting by timeout 276 select { 277 case <-interruptCtx.Done(): 278 txHash, _ := GetCurrentTxFromContext(interruptCtx) 279 interruptedTxCache, _ := GetCache(interruptCtx) 280 281 if interruptedTxCache == nil { 282 break 283 } 284 285 // if the tx is already in the cache, it means that it has been interrupted before and we will not interrupt it again 286 found, _ := interruptedTxCache.Cache.ContainsOrAdd(txHash, true) 287 if found { 288 interruptedTxCache.Cache.Remove(txHash) 289 } else { 290 // if the tx is not in the cache, it means that it has not been interrupted before and we will interrupt it 291 opcodeCommitInterruptCounter.Inc(1) 292 log.Warn("OPCODE Level interrupt") 293 294 return nil, ErrInterrupt 295 } 296 default: 297 } 298 } 299 300 if in.cfg.Debug { 301 // Capture pre-execution values for tracing. 302 logged, pcCopy, gasCopy = false, pc, contract.Gas 303 } 304 // Get the operation from the jump table and validate the stack to ensure there are 305 // enough stack items available to perform the operation. 306 op = contract.GetOp(pc) 307 operation := in.cfg.JumpTable[op] 308 cost = operation.constantGas // For tracing 309 // Validate stack 310 if sLen := stack.len(); sLen < operation.minStack { 311 return nil, &ErrStackUnderflow{stackLen: sLen, required: operation.minStack} 312 } else if sLen > operation.maxStack { 313 return nil, &ErrStackOverflow{stackLen: sLen, limit: operation.maxStack} 314 } 315 316 if !contract.UseGas(cost) { 317 return nil, ErrOutOfGas 318 } 319 // nolint : nestif 320 if operation.dynamicGas != nil { 321 // All ops with a dynamic memory usage also has a dynamic gas cost. 322 var memorySize uint64 323 // calculate the new memory size and expand the memory to fit 324 // the operation 325 // Memory check needs to be done prior to evaluating the dynamic gas portion, 326 // to detect calculation overflows 327 if operation.memorySize != nil { 328 memSize, overflow := operation.memorySize(stack) 329 if overflow { 330 return nil, ErrGasUintOverflow 331 } 332 // memory is expanded in words of 32 bytes. Gas 333 // is also calculated in words. 334 if memorySize, overflow = math.SafeMul(toWordSize(memSize), 32); overflow { 335 return nil, ErrGasUintOverflow 336 } 337 } 338 // Consume the gas and return an error if not enough gas is available. 339 // cost is explicitly set so that the capture state defer method can get the proper cost 340 var dynamicCost uint64 341 dynamicCost, err = operation.dynamicGas(in.evm, contract, stack, mem, memorySize) 342 cost += dynamicCost // for tracing 343 if err != nil || !contract.UseGas(dynamicCost) { 344 return nil, ErrOutOfGas 345 } 346 if memorySize > 0 { 347 mem.Resize(memorySize) 348 } 349 } 350 351 if in.cfg.Debug { 352 in.cfg.Tracer.CaptureState(pc, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err) 353 354 logged = true 355 } 356 // execute the operation 357 res, err = operation.execute(&pc, in, callContext) 358 if err != nil { 359 break 360 } 361 pc++ 362 } 363 364 if err == errStopToken { 365 err = nil // clear stop token error 366 } 367 368 return res, err 369 } 370 371 // nolint: gocognit 372 // RunWithDelay is Run() with a delay between each opcode. Only used by testcases. 373 func (in *EVMInterpreter) RunWithDelay(contract *Contract, input []byte, readOnly bool, interruptCtx context.Context, opcodeDelay uint) (ret []byte, err error) { 374 // Increment the call depth which is restricted to 1024 375 in.evm.depth++ 376 defer func() { in.evm.depth-- }() 377 378 // Make sure the readOnly is only set if we aren't in readOnly yet. 379 // This also makes sure that the readOnly flag isn't removed for child calls. 380 if readOnly && !in.readOnly { 381 in.readOnly = true 382 defer func() { in.readOnly = false }() 383 } 384 385 // Reset the previous call's return data. It's unimportant to preserve the old buffer 386 // as every returning call will return new data anyway. 387 in.returnData = nil 388 389 // Don't bother with the execution if there's no code. 390 if len(contract.Code) == 0 { 391 return nil, nil 392 } 393 394 var ( 395 op OpCode // current opcode 396 mem = NewMemory() // bound memory 397 stack = newstack() // local stack 398 callContext = &ScopeContext{ 399 Memory: mem, 400 Stack: stack, 401 Contract: contract, 402 } 403 // For optimisation reason we're using uint64 as the program counter. 404 // It's theoretically possible to go above 2^64. The YP defines the PC 405 // to be uint256. Practically much less so feasible. 406 pc = uint64(0) // program counter 407 cost uint64 408 // copies used by tracer 409 pcCopy uint64 // needed for the deferred EVMLogger 410 gasCopy uint64 // for EVMLogger to log gas remaining before execution 411 logged bool // deferred EVMLogger should ignore already logged steps 412 res []byte // result of the opcode execution function 413 ) 414 // Don't move this deferrred function, it's placed before the capturestate-deferred method, 415 // so that it get's executed _after_: the capturestate needs the stacks before 416 // they are returned to the pools 417 defer func() { 418 returnStack(stack) 419 }() 420 contract.Input = input 421 422 if in.cfg.Debug { 423 defer func() { 424 if err != nil { 425 if !logged { 426 in.cfg.Tracer.CaptureState(pcCopy, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err) 427 } else { 428 in.cfg.Tracer.CaptureFault(pcCopy, op, gasCopy, cost, callContext, in.evm.depth, err) 429 } 430 } 431 }() 432 } 433 // The Interpreter main run loop (contextual). This loop runs until either an 434 // explicit STOP, RETURN or SELFDESTRUCT is executed, an error occurred during 435 // the execution of one of the operations or until the done flag is set by the 436 // parent context. 437 for { 438 if interruptCtx != nil { 439 // case of interrupting by timeout 440 select { 441 case <-interruptCtx.Done(): 442 txHash, _ := GetCurrentTxFromContext(interruptCtx) 443 interruptedTxCache, _ := GetCache(interruptCtx) 444 445 if interruptedTxCache == nil { 446 break 447 } 448 449 // if the tx is already in the cache, it means that it has been interrupted before and we will not interrupt it again 450 found, _ := interruptedTxCache.Cache.ContainsOrAdd(txHash, true) 451 log.Info("FOUND", "found", found, "txHash", txHash) 452 453 if found { 454 interruptedTxCache.Cache.Remove(txHash) 455 } else { 456 // if the tx is not in the cache, it means that it has not been interrupted before and we will interrupt it 457 opcodeCommitInterruptCounter.Inc(1) 458 log.Warn("OPCODE Level interrupt") 459 460 return nil, ErrInterrupt 461 } 462 default: 463 } 464 } 465 466 time.Sleep(time.Duration(opcodeDelay) * time.Millisecond) 467 468 if in.cfg.Debug { 469 // Capture pre-execution values for tracing. 470 logged, pcCopy, gasCopy = false, pc, contract.Gas 471 } 472 // Get the operation from the jump table and validate the stack to ensure there are 473 // enough stack items available to perform the operation. 474 op = contract.GetOp(pc) 475 operation := in.cfg.JumpTable[op] 476 cost = operation.constantGas // For tracing 477 // Validate stack 478 if sLen := stack.len(); sLen < operation.minStack { 479 return nil, &ErrStackUnderflow{stackLen: sLen, required: operation.minStack} 480 } else if sLen > operation.maxStack { 481 return nil, &ErrStackOverflow{stackLen: sLen, limit: operation.maxStack} 482 } 483 if !contract.UseGas(cost) { 484 return nil, ErrOutOfGas 485 } 486 if operation.dynamicGas != nil { 487 // All ops with a dynamic memory usage also has a dynamic gas cost. 488 var memorySize uint64 489 // calculate the new memory size and expand the memory to fit 490 // the operation 491 // Memory check needs to be done prior to evaluating the dynamic gas portion, 492 // to detect calculation overflows 493 if operation.memorySize != nil { 494 memSize, overflow := operation.memorySize(stack) 495 if overflow { 496 return nil, ErrGasUintOverflow 497 } 498 // memory is expanded in words of 32 bytes. Gas 499 // is also calculated in words. 500 if memorySize, overflow = math.SafeMul(toWordSize(memSize), 32); overflow { 501 return nil, ErrGasUintOverflow 502 } 503 } 504 // Consume the gas and return an error if not enough gas is available. 505 // cost is explicitly set so that the capture state defer method can get the proper cost 506 var dynamicCost uint64 507 dynamicCost, err = operation.dynamicGas(in.evm, contract, stack, mem, memorySize) 508 cost += dynamicCost // for tracing 509 if err != nil || !contract.UseGas(dynamicCost) { 510 return nil, ErrOutOfGas 511 } 512 if memorySize > 0 { 513 mem.Resize(memorySize) 514 } 515 } 516 if in.cfg.Debug { 517 in.cfg.Tracer.CaptureState(pc, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err) 518 logged = true 519 } 520 // execute the operation 521 res, err = operation.execute(&pc, in, callContext) 522 if err != nil { 523 break 524 } 525 pc++ 526 } 527 528 if err == errStopToken { 529 err = nil // clear stop token error 530 } 531 532 return res, err 533 }