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 }