github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/core/vm/interpreter.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 12:09:35</date> 10 //</624342622231597056> 11 12 13 package vm 14 15 import ( 16 "fmt" 17 "sync/atomic" 18 19 "github.com/ethereum/go-ethereum/common/math" 20 "github.com/ethereum/go-ethereum/params" 21 ) 22 23 //config是解释器的配置选项 24 type Config struct { 25 //启用调试的调试解释器选项 26 Debug bool 27 //跟踪程序是操作代码记录器 28 Tracer Tracer 29 //无加密禁用的解释程序调用,调用代码, 30 //委派呼叫并创建。 31 NoRecursion bool 32 //启用sha3/keccak preimages的录制 33 EnablePreimageRecording bool 34 //JumpTable包含EVM指令表。这个 35 //可能未初始化,并将设置为默认值 36 //表。 37 JumpTable [256]operation 38 } 39 40 //解释器用于运行基于以太坊的合同,并将使用 41 //已传递环境以查询外部源以获取状态信息。 42 //解释器将根据传递的 43 //配置。 44 type Interpreter interface { 45 //运行循环并使用给定的输入数据评估契约的代码并返回 46 //返回字节切片,如果出现错误,则返回一个错误。 47 Run(contract *Contract, input []byte) ([]byte, error) 48 //canrun告诉作为参数传递的契约是否可以 49 //由当前解释器运行。这意味着 50 //呼叫方可以执行以下操作: 51 // 52 //'Gangang' 53 //对于u,解释器:=测距解释器 54 //if explorer.canrun(contract.code) 55 //解释器.run(contract.code,input) 56 //} 57 //} 58 //` ` 59 CanRun([]byte) bool 60 //如果解释器处于只读模式,is read only将报告。 61 IsReadOnly() bool 62 //setreadonly在解释器中设置(或取消设置)只读模式。 63 SetReadOnly(bool) 64 } 65 66 //evm interpreter表示evm解释器 67 type EVMInterpreter struct { 68 evm *EVM 69 cfg Config 70 gasTable params.GasTable 71 intPool *intPool 72 73 readOnly bool //是否进行状态修改 74 returnData []byte //最后一次调用的返回数据供后续重用 75 } 76 77 //NewEvminterPreter返回解释器的新实例。 78 func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter { 79 //我们使用停止指令是否看到 80 //跳转表已初始化。如果不是 81 //我们将设置默认跳转表。 82 if !cfg.JumpTable[STOP].valid { 83 switch { 84 case evm.ChainConfig().IsConstantinople(evm.BlockNumber): 85 cfg.JumpTable = constantinopleInstructionSet 86 case evm.ChainConfig().IsByzantium(evm.BlockNumber): 87 cfg.JumpTable = byzantiumInstructionSet 88 case evm.ChainConfig().IsHomestead(evm.BlockNumber): 89 cfg.JumpTable = homesteadInstructionSet 90 default: 91 cfg.JumpTable = frontierInstructionSet 92 } 93 } 94 95 return &EVMInterpreter{ 96 evm: evm, 97 cfg: cfg, 98 gasTable: evm.ChainConfig().GasTable(evm.BlockNumber), 99 } 100 } 101 102 func (in *EVMInterpreter) enforceRestrictions(op OpCode, operation operation, stack *Stack) error { 103 if in.evm.chainRules.IsByzantium { 104 if in.readOnly { 105 //如果解释器在只读模式下工作,请确保否 106 //执行状态修改操作。第三个堆栈项 107 //对于一个调用操作来说是值。从一个转移价值 108 //对其他人的帐户意味着状态被修改,并且应该 109 //返回时出错。 110 if operation.writes || (op == CALL && stack.Back(2).BitLen() > 0) { 111 return errWriteProtection 112 } 113 } 114 } 115 return nil 116 } 117 118 //运行循环并使用给定的输入数据评估契约的代码并返回 119 //返回字节切片,如果出现错误,则返回一个错误。 120 // 121 //需要注意的是,解释程序返回的任何错误都应该 122 //被认为是一种还原和消耗除 123 //errExecutionReverted,这意味着还原并保留气体。 124 func (in *EVMInterpreter) Run(contract *Contract, input []byte) (ret []byte, err error) { 125 if in.intPool == nil { 126 in.intPool = poolOfIntPools.get() 127 defer func() { 128 poolOfIntPools.put(in.intPool) 129 in.intPool = nil 130 }() 131 } 132 133 //增加限制为1024的调用深度 134 in.evm.depth++ 135 defer func() { in.evm.depth-- }() 136 137 //重置上一个呼叫的返回数据。保留旧的缓冲区并不重要 138 //因为每次回电都会返回新的数据。 139 in.returnData = nil 140 141 //如果没有代码,就不必费心执行。 142 if len(contract.Code) == 0 { 143 return nil, nil 144 } 145 146 var ( 147 op OpCode //当前操作码 148 mem = NewMemory() //绑定内存 149 stack = newstack() //本地栈 150 //为了优化,我们使用uint64作为程序计数器。 151 //理论上可以超过2^64。YP定义PC 152 //为UIT2525。实际上不那么可行。 153 pc = uint64(0) //程序计数器 154 cost uint64 155 //追踪器使用的副本 156 pcCopy uint64 //延期追踪器需要 157 gasCopy uint64 //用于示踪剂记录执行前的剩余气体 158 logged bool //延迟跟踪程序应忽略已记录的步骤 159 ) 160 contract.Input = input 161 162 //在执行停止时将堆栈作为int池回收 163 defer func() { in.intPool.put(stack.data...) }() 164 165 if in.cfg.Debug { 166 defer func() { 167 if err != nil { 168 if !logged { 169 in.cfg.Tracer.CaptureState(in.evm, pcCopy, op, gasCopy, cost, mem, stack, contract, in.evm.depth, err) 170 } else { 171 in.cfg.Tracer.CaptureFault(in.evm, pcCopy, op, gasCopy, cost, mem, stack, contract, in.evm.depth, err) 172 } 173 } 174 }() 175 } 176 //解释器主运行循环(上下文)。此循环运行到 177 //执行显式停止、返回或自毁函数,期间发生错误 178 //执行一个操作,或直到完成标志由 179 //父上下文。 180 for atomic.LoadInt32(&in.evm.abort) == 0 { 181 if in.cfg.Debug { 182 //捕获执行前的值以进行跟踪。 183 logged, pcCopy, gasCopy = false, pc, contract.Gas 184 } 185 186 //从跳转表中获取操作并验证堆栈以确保 187 //有足够的堆栈项可用于执行该操作。 188 op = contract.GetOp(pc) 189 operation := in.cfg.JumpTable[op] 190 if !operation.valid { 191 return nil, fmt.Errorf("invalid opcode 0x%x", int(op)) 192 } 193 if err := operation.validateStack(stack); err != nil { 194 return nil, err 195 } 196 //如果操作有效,则强制执行并写入限制 197 if err := in.enforceRestrictions(op, operation, stack); err != nil { 198 return nil, err 199 } 200 201 var memorySize uint64 202 //计算新内存大小并展开内存以适应 203 //手术 204 if operation.memorySize != nil { 205 memSize, overflow := bigUint64(operation.memorySize(stack)) 206 if overflow { 207 return nil, errGasUintOverflow 208 } 209 //内存以32字节的字扩展。气体 210 //也用文字计算。 211 if memorySize, overflow = math.SafeMul(toWordSize(memSize), 32); overflow { 212 return nil, errGasUintOverflow 213 } 214 } 215 //如果没有足够的气体可用,则消耗气体并返回错误。 216 //明确设置成本,以便捕获状态延迟方法可以获得适当的成本 217 cost, err = operation.gasCost(in.gasTable, in.evm, contract, stack, mem, memorySize) 218 if err != nil || !contract.UseGas(cost) { 219 return nil, ErrOutOfGas 220 } 221 if memorySize > 0 { 222 mem.Resize(memorySize) 223 } 224 225 if in.cfg.Debug { 226 in.cfg.Tracer.CaptureState(in.evm, pc, op, gasCopy, cost, mem, stack, contract, in.evm.depth, err) 227 logged = true 228 } 229 230 //执行操作 231 res, err := operation.execute(&pc, in, contract, mem, stack) 232 //VerifyPool是一个生成标志。池验证确保完整性 233 //通过将值与默认值进行比较来获得整数池的值。 234 if verifyPool { 235 verifyIntegerPool(in.intPool) 236 } 237 //如果操作清除返回数据(例如,它有返回数据) 238 //将最后一个返回设置为操作结果。 239 if operation.returns { 240 in.returnData = res 241 } 242 243 switch { 244 case err != nil: 245 return nil, err 246 case operation.reverts: 247 return res, errExecutionReverted 248 case operation.halts: 249 return res, nil 250 case !operation.jumps: 251 pc++ 252 } 253 } 254 return nil, nil 255 } 256 257 //canrun告诉作为参数传递的契约是否可以 258 //由当前解释器运行。 259 func (in *EVMInterpreter) CanRun(code []byte) bool { 260 return true 261 } 262 263 //如果解释器处于只读模式,is read only将报告。 264 func (in *EVMInterpreter) IsReadOnly() bool { 265 return in.readOnly 266 } 267 268 //setreadonly在解释器中设置(或取消设置)只读模式。 269 func (in *EVMInterpreter) SetReadOnly(ro bool) { 270 in.readOnly = ro 271 } 272