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