github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/core/vm/evm.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 19:16:36</date> 10 //</624450082183319552> 11 12 13 package vm 14 15 import ( 16 "math/big" 17 "sync/atomic" 18 "time" 19 20 "github.com/ethereum/go-ethereum/common" 21 "github.com/ethereum/go-ethereum/crypto" 22 "github.com/ethereum/go-ethereum/params" 23 ) 24 25 //create使用EmptyCodeHash来确保已不允许部署 26 //已部署的合同地址(在帐户提取之后相关)。 27 var emptyCodeHash = crypto.Keccak256Hash(nil) 28 29 type ( 30 //cantransferfunc是传递保护函数的签名 31 CanTransferFunc func(StateDB, common.Address, *big.Int) bool 32 //transferFunc是传递函数的签名 33 TransferFunc func(StateDB, common.Address, common.Address, *big.Int) 34 //gethashfunc返回区块链中的第n个区块哈希 35 //并由blockhash evm op代码使用。 36 GetHashFunc func(uint64) common.Hash 37 ) 38 39 //Run运行给定的合同,并负责运行回退到字节码解释器的预编译。 40 func run(evm *EVM, contract *Contract, input []byte, readOnly bool) ([]byte, error) { 41 if contract.CodeAddr != nil { 42 precompiles := PrecompiledContractsHomestead 43 if evm.ChainConfig().IsByzantium(evm.BlockNumber) { 44 precompiles = PrecompiledContractsByzantium 45 } 46 if p := precompiles[*contract.CodeAddr]; p != nil { 47 return RunPrecompiledContract(p, input, contract) 48 } 49 } 50 for _, interpreter := range evm.interpreters { 51 if interpreter.CanRun(contract.Code) { 52 if evm.interpreter != interpreter { 53 //确保解释器指针设置回原处 54 //返回到当前值。 55 defer func(i Interpreter) { 56 evm.interpreter = i 57 }(evm.interpreter) 58 evm.interpreter = interpreter 59 } 60 return interpreter.Run(contract, input, readOnly) 61 } 62 } 63 return nil, ErrNoCompatibleInterpreter 64 } 65 66 //上下文为EVM提供辅助信息。一旦提供 67 //它不应该被修改。 68 type Context struct { 69 //CanTransfer返回帐户是否包含 70 //足够的乙醚转移价值 71 CanTransfer CanTransferFunc 72 //将乙醚从一个帐户转移到另一个帐户 73 Transfer TransferFunc 74 //GetHash返回与n对应的哈希 75 GetHash GetHashFunc 76 77 //消息信息 78 Origin common.Address //提供源站信息 79 GasPrice *big.Int //为Gasprice提供信息 80 81 //阻止信息 82 Coinbase common.Address //为CoinBase提供信息 83 GasLimit uint64 //Provides information for GASLIMIT 84 BlockNumber *big.Int //提供数字信息 85 Time *big.Int //提供时间信息 86 Difficulty *big.Int //为困难提供信息 87 } 88 89 //EVM是以太坊虚拟机基础对象,它提供 90 //在给定状态下运行合同所需的工具 91 //提供的上下文。应该注意的是,任何错误 92 //通过任何调用生成的应被视为 93 //恢复状态并消耗所有气体操作,不检查 94 //应执行特定错误。翻译使 95 //确保生成的任何错误都被视为错误代码。 96 // 97 //EVM不应该被重用,也不是线程安全的。 98 type EVM struct { 99 //上下文提供辅助区块链相关信息 100 Context 101 //statedb提供对底层状态的访问 102 StateDB StateDB 103 //深度是当前调用堆栈 104 depth int 105 106 //chainconfig包含有关当前链的信息 107 chainConfig *params.ChainConfig 108 //链规则包含当前纪元的链规则 109 chainRules params.Rules 110 //用于初始化的虚拟机配置选项 111 //EVM。 112 vmConfig Config 113 //全局(到此上下文)以太坊虚拟机 114 //在整个Tx执行过程中使用。 115 interpreters []Interpreter 116 interpreter Interpreter 117 //abort用于中止EVM调用操作 118 //注:必须按原子顺序设置 119 abort int32 120 //callgastemp保留当前呼叫可用的气体。这是需要的,因为 121 //根据63/64规则和更高版本,可用气体在GasCall*中计算。 122 //在opcall*中应用。 123 callGasTemp uint64 124 } 125 126 //new evm返回新的evm。返回的EVM不是线程安全的,应该 127 //只能使用一次。 128 func NewEVM(ctx Context, statedb StateDB, chainConfig *params.ChainConfig, vmConfig Config) *EVM { 129 evm := &EVM{ 130 Context: ctx, 131 StateDB: statedb, 132 vmConfig: vmConfig, 133 chainConfig: chainConfig, 134 chainRules: chainConfig.Rules(ctx.BlockNumber), 135 interpreters: make([]Interpreter, 0, 1), 136 } 137 138 if chainConfig.IsEWASM(ctx.BlockNumber) { 139 //由EVM-C和货车PRS实施。 140 //如果vmconfig.ewasminterper!=“{” 141 //extIntopts:=strings.split(vmconfig.ewasInterpreter,“:”) 142 //路径:=extintopts[0] 143 //选项:=[]字符串 144 //如果len(extintopts)>1 145 //选项=extintopts[1..] 146 //} 147 //evm.interpreters=append(evm.interpreters,newevmvcinterpreter(evm,vmconfig,options))。 148 //}否则{ 149 //evm.interpreters=append(evm.interpreters,newewasInterpreter(evm,vmconfig))。 150 //} 151 panic("No supported ewasm interpreter yet.") 152 } 153 154 //vmconfig.evminterpreter将由evm-c使用,此处不检查 155 //因为我们总是希望将内置的EVM作为故障转移选项。 156 evm.interpreters = append(evm.interpreters, NewEVMInterpreter(evm, vmConfig)) 157 evm.interpreter = evm.interpreters[0] 158 159 return evm 160 } 161 162 //取消取消任何正在运行的EVM操作。这可以同时调用,并且 163 //多次打电话是安全的。 164 func (evm *EVM) Cancel() { 165 atomic.StoreInt32(&evm.abort, 1) 166 } 167 168 //解释器返回当前解释器 169 func (evm *EVM) Interpreter() Interpreter { 170 return evm.interpreter 171 } 172 173 //调用执行与给定输入为的addr关联的协定 174 //参数。它还处理任何必要的价值转移,并采取 175 //创建帐户和在 176 //执行错误或值传输失败。 177 func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) { 178 if evm.vmConfig.NoRecursion && evm.depth > 0 { 179 return nil, gas, nil 180 } 181 182 //如果我们试图执行超过调用深度限制,则失败 183 if evm.depth > int(params.CallCreateDepth) { 184 return nil, gas, ErrDepth 185 } 186 //如果我们试图转移的余额超过可用余额,则失败 187 if !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) { 188 return nil, gas, ErrInsufficientBalance 189 } 190 191 var ( 192 to = AccountRef(addr) 193 snapshot = evm.StateDB.Snapshot() 194 ) 195 if !evm.StateDB.Exist(addr) { 196 precompiles := PrecompiledContractsHomestead 197 if evm.ChainConfig().IsByzantium(evm.BlockNumber) { 198 precompiles = PrecompiledContractsByzantium 199 } 200 if precompiles[addr] == nil && evm.ChainConfig().IsEIP158(evm.BlockNumber) && value.Sign() == 0 { 201 //调用一个不存在的帐户,不要做任何事情,只需ping跟踪程序 202 if evm.vmConfig.Debug && evm.depth == 0 { 203 evm.vmConfig.Tracer.CaptureStart(caller.Address(), addr, false, input, gas, value) 204 evm.vmConfig.Tracer.CaptureEnd(ret, 0, 0, nil) 205 } 206 return nil, gas, nil 207 } 208 evm.StateDB.CreateAccount(addr) 209 } 210 evm.Transfer(evm.StateDB, caller.Address(), to.Address(), value) 211 //初始化新合同并设置EVM要使用的代码。 212 //契约只是这个执行上下文的作用域环境。 213 contract := NewContract(caller, to, value, gas) 214 contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) 215 216 //即使帐户没有代码,我们也需要继续,因为它可能是预编译的 217 start := time.Now() 218 219 //在调试模式下捕获跟踪程序开始/结束事件 220 if evm.vmConfig.Debug && evm.depth == 0 { 221 evm.vmConfig.Tracer.CaptureStart(caller.Address(), addr, false, input, gas, value) 222 223 defer func() { //参数的延迟评估 224 evm.vmConfig.Tracer.CaptureEnd(ret, gas-contract.Gas, time.Since(start), err) 225 }() 226 } 227 ret, err = run(evm, contract, input, false) 228 229 //当EVM返回错误或设置创建代码时 230 //在上面,我们返回快照并消耗所有剩余的气体。另外 231 //当我们在宅基地时,这也算是代码存储气体错误。 232 if err != nil { 233 evm.StateDB.RevertToSnapshot(snapshot) 234 if err != errExecutionReverted { 235 contract.UseGas(contract.Gas) 236 } 237 } 238 return ret, contract.Gas, err 239 } 240 241 //callcode使用给定的输入执行与addr关联的协定 242 //作为参数。它还处理任何必要的价值转移,并采取 243 //创建帐户和在 244 //执行错误或值传输失败。 245 // 246 //callcode与call的区别在于它执行给定的地址' 247 //以调用方为上下文的代码。 248 func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) { 249 if evm.vmConfig.NoRecursion && evm.depth > 0 { 250 return nil, gas, nil 251 } 252 253 //如果我们试图执行超过调用深度限制,则失败 254 if evm.depth > int(params.CallCreateDepth) { 255 return nil, gas, ErrDepth 256 } 257 //如果我们试图转移的余额超过可用余额,则失败 258 if !evm.CanTransfer(evm.StateDB, caller.Address(), value) { 259 return nil, gas, ErrInsufficientBalance 260 } 261 262 var ( 263 snapshot = evm.StateDB.Snapshot() 264 to = AccountRef(caller.Address()) 265 ) 266 //初始化新合同并设置 267 //EVM。合同是此执行上下文的作用域环境 268 //只有。 269 contract := NewContract(caller, to, value, gas) 270 contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) 271 272 ret, err = run(evm, contract, input, false) 273 if err != nil { 274 evm.StateDB.RevertToSnapshot(snapshot) 275 if err != errExecutionReverted { 276 contract.UseGas(contract.Gas) 277 } 278 } 279 return ret, contract.Gas, err 280 } 281 282 //DelegateCall执行与给定输入的addr关联的协定 283 //作为参数。如果发生执行错误,它将反转状态。 284 // 285 //delegateCall与callcode的区别在于它执行给定的地址' 286 //以调用者为上下文的代码,调用者被设置为调用者的调用者。 287 func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) { 288 if evm.vmConfig.NoRecursion && evm.depth > 0 { 289 return nil, gas, nil 290 } 291 //如果我们试图执行超过调用深度限制,则失败 292 if evm.depth > int(params.CallCreateDepth) { 293 return nil, gas, ErrDepth 294 } 295 296 var ( 297 snapshot = evm.StateDB.Snapshot() 298 to = AccountRef(caller.Address()) 299 ) 300 301 //初始化新合同并使委托值初始化 302 contract := NewContract(caller, to, nil, gas).AsDelegate() 303 contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) 304 305 ret, err = run(evm, contract, input, false) 306 if err != nil { 307 evm.StateDB.RevertToSnapshot(snapshot) 308 if err != errExecutionReverted { 309 contract.UseGas(contract.Gas) 310 } 311 } 312 return ret, contract.Gas, err 313 } 314 315 //staticCall使用给定的输入执行与addr关联的协定 316 //作为参数,同时不允许在调用期间对状态进行任何修改。 317 //试图执行此类修改的操作码将导致异常 318 //而不是执行修改。 319 func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) { 320 if evm.vmConfig.NoRecursion && evm.depth > 0 { 321 return nil, gas, nil 322 } 323 //如果我们试图执行超过调用深度限制,则失败 324 if evm.depth > int(params.CallCreateDepth) { 325 return nil, gas, ErrDepth 326 } 327 328 var ( 329 to = AccountRef(addr) 330 snapshot = evm.StateDB.Snapshot() 331 ) 332 //初始化新合同并设置 333 //EVM。合同是此执行上下文的作用域环境 334 //只有。 335 contract := NewContract(caller, to, new(big.Int), gas) 336 contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) 337 338 //我们在这里做一个零的加法平衡,只是为了触发一个触摸。 339 //在拜占庭时代,所有空的东西都不见了。 340 //但是,在其他网络、测试和潜力方面是否正确以及重要? 341 //未来情景 342 evm.StateDB.AddBalance(addr, bigZero) 343 344 //当EVM返回错误或设置创建代码时 345 //在上面,我们返回快照并消耗所有剩余的气体。另外 346 //当我们在宅基地时,这也算是代码存储气体错误。 347 ret, err = run(evm, contract, input, true) 348 if err != nil { 349 evm.StateDB.RevertToSnapshot(snapshot) 350 if err != errExecutionReverted { 351 contract.UseGas(contract.Gas) 352 } 353 } 354 return ret, contract.Gas, err 355 } 356 357 type codeAndHash struct { 358 code []byte 359 hash common.Hash 360 } 361 362 func (c *codeAndHash) Hash() common.Hash { 363 if c.hash == (common.Hash{}) { 364 c.hash = crypto.Keccak256Hash(c.code) 365 } 366 return c.hash 367 } 368 369 //创建使用代码作为部署代码创建新合同。 370 func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, value *big.Int, address common.Address) ([]byte, common.Address, uint64, error) { 371 //深度检查执行。如果我们试图执行上面的 372 //极限。 373 if evm.depth > int(params.CallCreateDepth) { 374 return nil, common.Address{}, gas, ErrDepth 375 } 376 if !evm.CanTransfer(evm.StateDB, caller.Address(), value) { 377 return nil, common.Address{}, gas, ErrInsufficientBalance 378 } 379 nonce := evm.StateDB.GetNonce(caller.Address()) 380 evm.StateDB.SetNonce(caller.Address(), nonce+1) 381 382 //确保指定地址没有现有合同 383 contractHash := evm.StateDB.GetCodeHash(address) 384 if evm.StateDB.GetNonce(address) != 0 || (contractHash != (common.Hash{}) && contractHash != emptyCodeHash) { 385 return nil, common.Address{}, 0, ErrContractAddressCollision 386 } 387 //在该州创建新帐户 388 snapshot := evm.StateDB.Snapshot() 389 evm.StateDB.CreateAccount(address) 390 if evm.ChainConfig().IsEIP158(evm.BlockNumber) { 391 evm.StateDB.SetNonce(address, 1) 392 } 393 evm.Transfer(evm.StateDB, caller.Address(), address, value) 394 395 //初始化新合同并设置 396 //EVM。合同是此执行上下文的作用域环境 397 //只有。 398 contract := NewContract(caller, AccountRef(address), value, gas) 399 contract.SetCodeOptionalHash(&address, codeAndHash) 400 401 if evm.vmConfig.NoRecursion && evm.depth > 0 { 402 return nil, address, gas, nil 403 } 404 405 if evm.vmConfig.Debug && evm.depth == 0 { 406 evm.vmConfig.Tracer.CaptureStart(caller.Address(), address, true, codeAndHash.code, gas, value) 407 } 408 start := time.Now() 409 410 ret, err := run(evm, contract, nil, false) 411 412 //检查是否超过了最大代码大小 413 maxCodeSizeExceeded := evm.ChainConfig().IsEIP158(evm.BlockNumber) && len(ret) > params.MaxCodeSize 414 //如果合同创建成功运行且未返回错误 415 //计算存储代码所需的气体。如果代码不能 416 //因气量不足而储存,设置错误并处理 417 //通过下面的错误检查条件。 418 if err == nil && !maxCodeSizeExceeded { 419 createDataGas := uint64(len(ret)) * params.CreateDataGas 420 if contract.UseGas(createDataGas) { 421 evm.StateDB.SetCode(address, ret) 422 } else { 423 err = ErrCodeStoreOutOfGas 424 } 425 } 426 427 //当EVM返回错误或设置创建代码时 428 //在上面,我们返回快照并消耗所有剩余的气体。另外 429 //当我们在宅基地时,这也算是代码存储气体错误。 430 if maxCodeSizeExceeded || (err != nil && (evm.ChainConfig().IsHomestead(evm.BlockNumber) || err != ErrCodeStoreOutOfGas)) { 431 evm.StateDB.RevertToSnapshot(snapshot) 432 if err != errExecutionReverted { 433 contract.UseGas(contract.Gas) 434 } 435 } 436 //如果合同代码大小超过最大值而错误仍然为空,则分配错误。 437 if maxCodeSizeExceeded && err == nil { 438 err = errMaxCodeSizeExceeded 439 } 440 if evm.vmConfig.Debug && evm.depth == 0 { 441 evm.vmConfig.Tracer.CaptureEnd(ret, gas-contract.Gas, time.Since(start), err) 442 } 443 return ret, address, contract.Gas, err 444 445 } 446 447 //创建使用代码作为部署代码创建新合同。 448 func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) { 449 contractAddr = crypto.CreateAddress(caller.Address(), evm.StateDB.GetNonce(caller.Address())) 450 return evm.create(caller, &codeAndHash{code: code}, gas, value, contractAddr) 451 } 452 453 //Create2使用代码作为部署代码创建新合同。 454 // 455 //create2与create的区别是create2使用sha3(0xff++msg.sender++salt++sha3(init_code))[12:] 456 //而不是通常的发送者和nonce散列作为合同初始化的地址。 457 func (evm *EVM) Create2(caller ContractRef, code []byte, gas uint64, endowment *big.Int, salt *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) { 458 codeAndHash := &codeAndHash{code: code} 459 contractAddr = crypto.CreateAddress2(caller.Address(), common.BigToHash(salt), codeAndHash.Hash().Bytes()) 460 return evm.create(caller, codeAndHash, gas, endowment, contractAddr) 461 } 462 463 //chainconfig返回环境的链配置 464 func (evm *EVM) ChainConfig() *params.ChainConfig { return evm.chainConfig } 465