github.com/dim4egster/coreth@v0.10.2/core/vm/interpreter.go (about)

     1  // (c) 2019-2020, Ava Labs, Inc.
     2  //
     3  // This file is a derived work, based on the go-ethereum library whose original
     4  // notices appear below.
     5  //
     6  // It is distributed under a license compatible with the licensing terms of the
     7  // original code from which it is derived.
     8  //
     9  // Much love to the original authors for their work.
    10  // **********
    11  // Copyright 2014 The go-ethereum Authors
    12  // This file is part of the go-ethereum library.
    13  //
    14  // The go-ethereum library is free software: you can redistribute it and/or modify
    15  // it under the terms of the GNU Lesser General Public License as published by
    16  // the Free Software Foundation, either version 3 of the License, or
    17  // (at your option) any later version.
    18  //
    19  // The go-ethereum library is distributed in the hope that it will be useful,
    20  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    21  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    22  // GNU Lesser General Public License for more details.
    23  //
    24  // You should have received a copy of the GNU Lesser General Public License
    25  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    26  
    27  package vm
    28  
    29  import (
    30  	"hash"
    31  
    32  	"github.com/dim4egster/coreth/vmerrs"
    33  	"github.com/ethereum/go-ethereum/common"
    34  	"github.com/ethereum/go-ethereum/common/math"
    35  	"github.com/ethereum/go-ethereum/log"
    36  )
    37  
    38  var (
    39  	BuiltinAddr = common.Address{
    40  		1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    41  		0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    42  	}
    43  )
    44  
    45  // Config are the configuration options for the Interpreter
    46  type Config struct {
    47  	Debug                   bool      // Enables debugging
    48  	Tracer                  EVMLogger // Opcode logger
    49  	NoBaseFee               bool      // Forces the EIP-1559 baseFee to 0 (needed for 0 price calls)
    50  	EnablePreimageRecording bool      // Enables recording of SHA3/keccak preimages
    51  
    52  	JumpTable *JumpTable // EVM instruction table, automatically populated if unset
    53  
    54  	ExtraEips []int // Additional EIPS that are to be enabled
    55  
    56  	// AllowUnfinalizedQueries allow unfinalized queries
    57  	AllowUnfinalizedQueries bool
    58  }
    59  
    60  // ScopeContext contains the things that are per-call, such as stack and memory,
    61  // but not transients like pc and gas
    62  type ScopeContext struct {
    63  	Memory   *Memory
    64  	Stack    *Stack
    65  	Contract *Contract
    66  }
    67  
    68  // keccakState wraps sha3.state. In addition to the usual hash methods, it also supports
    69  // Read to get a variable amount of data from the hash state. Read is faster than Sum
    70  // because it doesn't copy the internal state, but also modifies the internal state.
    71  type keccakState interface {
    72  	hash.Hash
    73  	Read([]byte) (int, error)
    74  }
    75  
    76  // EVMInterpreter represents an EVM interpreter
    77  type EVMInterpreter struct {
    78  	evm *EVM
    79  	cfg Config
    80  
    81  	hasher    keccakState // Keccak256 hasher instance shared across opcodes
    82  	hasherBuf common.Hash // Keccak256 hasher result array shared aross opcodes
    83  
    84  	readOnly   bool   // Whether to throw on stateful modifications
    85  	returnData []byte // Last CALL's return data for subsequent reuse
    86  }
    87  
    88  // NewEVMInterpreter returns a new instance of the Interpreter.
    89  func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter {
    90  	// If jump table was not initialised we set the default one.
    91  	if cfg.JumpTable == nil {
    92  		switch {
    93  		case evm.chainRules.IsApricotPhase3:
    94  			cfg.JumpTable = &apricotPhase3InstructionSet
    95  		case evm.chainRules.IsApricotPhase2:
    96  			cfg.JumpTable = &apricotPhase2InstructionSet
    97  		case evm.chainRules.IsApricotPhase1:
    98  			cfg.JumpTable = &apricotPhase1InstructionSet
    99  		case evm.chainRules.IsIstanbul:
   100  			cfg.JumpTable = &istanbulInstructionSet
   101  		case evm.chainRules.IsConstantinople:
   102  			cfg.JumpTable = &constantinopleInstructionSet
   103  		case evm.chainRules.IsByzantium:
   104  			cfg.JumpTable = &byzantiumInstructionSet
   105  		case evm.chainRules.IsEIP158:
   106  			cfg.JumpTable = &spuriousDragonInstructionSet
   107  		case evm.chainRules.IsEIP150:
   108  			cfg.JumpTable = &tangerineWhistleInstructionSet
   109  		case evm.chainRules.IsHomestead:
   110  			cfg.JumpTable = &homesteadInstructionSet
   111  		default:
   112  			cfg.JumpTable = &frontierInstructionSet
   113  		}
   114  		for i, eip := range cfg.ExtraEips {
   115  			copy := *cfg.JumpTable
   116  			if err := EnableEIP(eip, &copy); err != nil {
   117  				// Disable it, so caller can check if it's activated or not
   118  				cfg.ExtraEips = append(cfg.ExtraEips[:i], cfg.ExtraEips[i+1:]...)
   119  				log.Error("EIP activation failed", "eip", eip, "error", err)
   120  			}
   121  			cfg.JumpTable = &copy
   122  		}
   123  	}
   124  
   125  	return &EVMInterpreter{
   126  		evm: evm,
   127  		cfg: cfg,
   128  	}
   129  }
   130  
   131  // Run loops and evaluates the contract's code with the given input data and returns
   132  // the return byte-slice and an error if one occurred.
   133  //
   134  // It's important to note that any errors returned by the interpreter should be
   135  // considered a revert-and-consume-all-gas operation except for
   136  // ErrExecutionReverted which means revert-and-keep-gas-left.
   137  func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (ret []byte, err error) {
   138  	// Deprecate special handling of [BuiltinAddr] as of ApricotPhase2.
   139  	// In ApricotPhase2, the contract deployed in the genesis is overridden by a deprecated precompiled
   140  	// contract which will return an error immediately if its ever called. Therefore, this function should
   141  	// never be called after ApricotPhase2 with [BuiltinAddr] as the contract address.
   142  	if !in.evm.chainRules.IsApricotPhase2 && contract.Address() == BuiltinAddr {
   143  		self := AccountRef(contract.Caller())
   144  		if _, ok := contract.caller.(*Contract); ok {
   145  			contract = contract.AsDelegate()
   146  		}
   147  		contract.self = self
   148  	}
   149  
   150  	// Increment the call depth which is restricted to 1024
   151  	in.evm.depth++
   152  	defer func() { in.evm.depth-- }()
   153  
   154  	// Make sure the readOnly is only set if we aren't in readOnly yet.
   155  	// This also makes sure that the readOnly flag isn't removed for child calls.
   156  	if readOnly && !in.readOnly {
   157  		in.readOnly = true
   158  		defer func() { in.readOnly = false }()
   159  	}
   160  
   161  	// Reset the previous call's return data. It's unimportant to preserve the old buffer
   162  	// as every returning call will return new data anyway.
   163  	in.returnData = nil
   164  
   165  	// Don't bother with the execution if there's no code.
   166  	// Note: this avoids invoking the tracer in any way for simple value
   167  	// transfers to EOA accounts.
   168  	if len(contract.Code) == 0 {
   169  		return nil, nil
   170  	}
   171  
   172  	var (
   173  		op          OpCode        // current opcode
   174  		mem         = NewMemory() // bound memory
   175  		stack       = newstack()  // local stack
   176  		callContext = &ScopeContext{
   177  			Memory:   mem,
   178  			Stack:    stack,
   179  			Contract: contract,
   180  		}
   181  		// For optimisation reason we're using uint64 as the program counter.
   182  		// It's theoretically possible to go above 2^64. The YP defines the PC
   183  		// to be uint256. Practically much less so feasible.
   184  		pc   = uint64(0) // program counter
   185  		cost uint64
   186  		// copies used by tracer
   187  		pcCopy  uint64 // needed for the deferred EVMLogger
   188  		gasCopy uint64 // for EVMLogger to log gas remaining before execution
   189  		logged  bool   // deferred EVMLogger should ignore already logged steps
   190  		res     []byte // result of the opcode execution function
   191  	)
   192  
   193  	// Don't move this deferred function, it's placed before the capturestate-deferred method,
   194  	// so that it get's executed _after_: the capturestate needs the stacks before
   195  	// they are returned to the pools
   196  	defer func() {
   197  		returnStack(stack)
   198  	}()
   199  	contract.Input = input
   200  
   201  	if in.cfg.Debug {
   202  		defer func() {
   203  			if err != nil {
   204  				if !logged {
   205  					in.cfg.Tracer.CaptureState(pcCopy, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err)
   206  				} else {
   207  					in.cfg.Tracer.CaptureFault(pcCopy, op, gasCopy, cost, callContext, in.evm.depth, err)
   208  				}
   209  			}
   210  		}()
   211  	}
   212  	// The Interpreter main run loop (contextual). This loop runs until either an
   213  	// explicit STOP, RETURN or SELFDESTRUCT is executed, an error occurred during
   214  	// the execution of one of the operations or until the done flag is set by the
   215  	// parent context.
   216  	for {
   217  		if in.cfg.Debug {
   218  			// Capture pre-execution values for tracing.
   219  			logged, pcCopy, gasCopy = false, pc, contract.Gas
   220  		}
   221  		// Get the operation from the jump table and validate the stack to ensure there are
   222  		// enough stack items available to perform the operation.
   223  		op = contract.GetOp(pc)
   224  		operation := in.cfg.JumpTable[op]
   225  		cost = operation.constantGas // For tracing
   226  		// Validate stack
   227  		if sLen := stack.len(); sLen < operation.minStack {
   228  			return nil, &ErrStackUnderflow{stackLen: sLen, required: operation.minStack}
   229  		} else if sLen > operation.maxStack {
   230  			return nil, &ErrStackOverflow{stackLen: sLen, limit: operation.maxStack}
   231  		}
   232  		if !contract.UseGas(cost) {
   233  			return nil, vmerrs.ErrOutOfGas
   234  		}
   235  
   236  		if operation.dynamicGas != nil {
   237  			// All ops with a dynamic memory usage also has a dynamic gas cost.
   238  			var memorySize uint64
   239  			// calculate the new memory size and expand the memory to fit
   240  			// the operation
   241  			// Memory check needs to be done prior to evaluating the dynamic gas portion,
   242  			// to detect calculation overflows
   243  			if operation.memorySize != nil {
   244  				memSize, overflow := operation.memorySize(stack)
   245  				if overflow {
   246  					return nil, vmerrs.ErrGasUintOverflow
   247  				}
   248  				// memory is expanded in words of 32 bytes. Gas
   249  				// is also calculated in words.
   250  				if memorySize, overflow = math.SafeMul(toWordSize(memSize), 32); overflow {
   251  					return nil, vmerrs.ErrGasUintOverflow
   252  				}
   253  			}
   254  			// Consume the gas and return an error if not enough gas is available.
   255  			// cost is explicitly set so that the capture state defer method can get the proper cost
   256  			var dynamicCost uint64
   257  			dynamicCost, err = operation.dynamicGas(in.evm, contract, stack, mem, memorySize)
   258  			cost += dynamicCost // for tracing
   259  			if err != nil || !contract.UseGas(dynamicCost) {
   260  				return nil, vmerrs.ErrOutOfGas
   261  			}
   262  			// Do tracing before memory expansion
   263  			if in.cfg.Debug {
   264  				in.cfg.Tracer.CaptureState(pc, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err)
   265  				logged = true
   266  			}
   267  			if memorySize > 0 {
   268  				mem.Resize(memorySize)
   269  			}
   270  		} else if in.cfg.Debug {
   271  			in.cfg.Tracer.CaptureState(pc, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err)
   272  			logged = true
   273  		}
   274  
   275  		// execute the operation
   276  		res, err = operation.execute(&pc, in, callContext)
   277  		if err != nil {
   278  			break
   279  		}
   280  		pc++
   281  	}
   282  	if err == errStopToken {
   283  		err = nil // clear stop token error
   284  	}
   285  
   286  	return res, err
   287  }