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, &copy); 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 = &copy
   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  }