github.com/neatlab/neatio@v1.7.3-0.20220425043230-d903e92fcc75/chain/core/vm/interpreter.go (about)

     1  package vm
     2  
     3  import (
     4  	"fmt"
     5  	"hash"
     6  	"sync/atomic"
     7  
     8  	"github.com/neatlab/neatio/chain/log"
     9  	"github.com/neatlab/neatio/utilities/common"
    10  
    11  	"github.com/neatlab/neatio/utilities/common/math"
    12  )
    13  
    14  type Config struct {
    15  	Debug                   bool
    16  	Tracer                  Tracer
    17  	NoRecursion             bool
    18  	EnablePreimageRecording bool
    19  
    20  	JumpTable [256]operation
    21  
    22  	EWASMInterpreter string
    23  	EVMInterpreter   string
    24  
    25  	ExtraEips []int
    26  }
    27  
    28  type Interpreter interface {
    29  	Run(contract *Contract, input []byte, static bool) ([]byte, error)
    30  
    31  	CanRun([]byte) bool
    32  }
    33  
    34  type keccakState interface {
    35  	hash.Hash
    36  	Read([]byte) (int, error)
    37  }
    38  
    39  type EVMInterpreter struct {
    40  	evm *EVM
    41  	cfg Config
    42  
    43  	intPool *intPool
    44  
    45  	hasher    keccakState
    46  	hasherBuf common.Hash
    47  
    48  	readOnly   bool
    49  	returnData []byte
    50  }
    51  
    52  func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter {
    53  
    54  	if !cfg.JumpTable[STOP].valid {
    55  		var jt JumpTable
    56  		switch {
    57  		case evm.chainRules.IsIstanbul:
    58  			jt = istanbulInstructionSet
    59  		case evm.chainRules.IsConstantinople:
    60  			jt = constantinopleInstructionSet
    61  		case evm.chainRules.IsByzantium:
    62  			jt = byzantiumInstructionSet
    63  		case evm.chainRules.IsEIP158:
    64  			jt = spuriousDragonInstructionSet
    65  		case evm.chainRules.IsEIP150:
    66  			jt = tangerineWhistleInstructionSet
    67  		case evm.chainRules.IsHomestead:
    68  			jt = homesteadInstructionSet
    69  		default:
    70  			jt = frontierInstructionSet
    71  		}
    72  		for i, eip := range cfg.ExtraEips {
    73  			if err := EnableEIP(eip, &jt); err != nil {
    74  
    75  				cfg.ExtraEips = append(cfg.ExtraEips[:i], cfg.ExtraEips[i+1:]...)
    76  				log.Error("EIP activation failed", "eip", eip, "error", err)
    77  			}
    78  		}
    79  		cfg.JumpTable = jt
    80  	}
    81  
    82  	return &EVMInterpreter{
    83  		evm: evm,
    84  		cfg: cfg,
    85  	}
    86  }
    87  
    88  func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (ret []byte, err error) {
    89  	if in.intPool == nil {
    90  		in.intPool = poolOfIntPools.get()
    91  		defer func() {
    92  			poolOfIntPools.put(in.intPool)
    93  			in.intPool = nil
    94  		}()
    95  	}
    96  
    97  	in.evm.depth++
    98  	defer func() { in.evm.depth-- }()
    99  
   100  	if readOnly && !in.readOnly {
   101  		in.readOnly = true
   102  		defer func() { in.readOnly = false }()
   103  	}
   104  
   105  	in.returnData = nil
   106  
   107  	if len(contract.Code) == 0 {
   108  		return nil, nil
   109  	}
   110  
   111  	var (
   112  		op    OpCode
   113  		mem   = NewMemory()
   114  		stack = newstack()
   115  
   116  		pc   = uint64(0)
   117  		cost uint64
   118  
   119  		pcCopy  uint64
   120  		gasCopy uint64
   121  		logged  bool
   122  		res     []byte
   123  	)
   124  	contract.Input = input
   125  
   126  	defer func() { in.intPool.put(stack.data...) }()
   127  
   128  	if in.cfg.Debug {
   129  		defer func() {
   130  			if err != nil {
   131  				if !logged {
   132  					in.cfg.Tracer.CaptureState(in.evm, pcCopy, op, gasCopy, cost, mem, stack, contract, in.evm.depth, err)
   133  				} else {
   134  					in.cfg.Tracer.CaptureFault(in.evm, pcCopy, op, gasCopy, cost, mem, stack, contract, in.evm.depth, err)
   135  				}
   136  			}
   137  		}()
   138  	}
   139  
   140  	for atomic.LoadInt32(&in.evm.abort) == 0 {
   141  		if in.cfg.Debug {
   142  
   143  			logged, pcCopy, gasCopy = false, pc, contract.Gas
   144  		}
   145  
   146  		op = contract.GetOp(pc)
   147  		operation := in.cfg.JumpTable[op]
   148  		if !operation.valid {
   149  			return nil, fmt.Errorf("invalid opcode 0x%x", int(op))
   150  		}
   151  
   152  		if sLen := stack.len(); sLen < operation.minStack {
   153  			return nil, fmt.Errorf("stack underflow (%d <=> %d)", sLen, operation.minStack)
   154  		} else if sLen > operation.maxStack {
   155  			return nil, fmt.Errorf("stack limit reached %d (%d)", sLen, operation.maxStack)
   156  		}
   157  
   158  		if in.readOnly && in.evm.chainRules.IsByzantium {
   159  
   160  			if operation.writes || (op == CALL && stack.Back(2).Sign() != 0) {
   161  				return nil, ErrWriteProtection
   162  			}
   163  		}
   164  
   165  		cost = operation.constantGas
   166  		if !contract.UseGas(operation.constantGas) {
   167  			return nil, ErrOutOfGas
   168  		}
   169  
   170  		var memorySize uint64
   171  
   172  		if operation.memorySize != nil {
   173  			memSize, overflow := operation.memorySize(stack)
   174  			if overflow {
   175  				return nil, errGasUintOverflow
   176  			}
   177  
   178  			if memorySize, overflow = math.SafeMul(toWordSize(memSize), 32); overflow {
   179  				return nil, errGasUintOverflow
   180  			}
   181  		}
   182  
   183  		if operation.dynamicGas != nil {
   184  			var dynamicCost uint64
   185  			dynamicCost, err = operation.dynamicGas(in.evm, contract, stack, mem, memorySize)
   186  			cost += dynamicCost
   187  			if err != nil || !contract.UseGas(dynamicCost) {
   188  				return nil, ErrOutOfGas
   189  			}
   190  		}
   191  		if memorySize > 0 {
   192  			mem.Resize(memorySize)
   193  		}
   194  
   195  		if in.cfg.Debug {
   196  			in.cfg.Tracer.CaptureState(in.evm, pc, op, gasCopy, cost, mem, stack, contract, in.evm.depth, err)
   197  			logged = true
   198  		}
   199  
   200  		res, err = operation.execute(&pc, in, contract, mem, stack)
   201  
   202  		if verifyPool {
   203  			verifyIntegerPool(in.intPool)
   204  		}
   205  
   206  		if operation.returns {
   207  			in.returnData = res
   208  		}
   209  
   210  		switch {
   211  		case err != nil:
   212  			return nil, err
   213  		case operation.reverts:
   214  			return res, ErrExecutionReverted
   215  		case operation.halts:
   216  			return res, nil
   217  		case !operation.jumps:
   218  			pc++
   219  		}
   220  	}
   221  	return nil, nil
   222  }
   223  
   224  func (in *EVMInterpreter) CanRun(code []byte) bool {
   225  	return true
   226  }