github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/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 12:09:35</date> 10 //</624342621531148288> 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) ([]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) 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 //提供气体限制信息 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, 1), 136 } 137 138 evm.interpreters[0] = NewEVMInterpreter(evm, vmConfig) 139 evm.interpreter = evm.interpreters[0] 140 141 return evm 142 } 143 144 //取消取消任何正在运行的EVM操作。这可以同时调用,并且 145 //多次打电话是安全的。 146 func (evm *EVM) Cancel() { 147 atomic.StoreInt32(&evm.abort, 1) 148 } 149 150 //解释器返回当前解释器 151 func (evm *EVM) Interpreter() Interpreter { 152 return evm.interpreter 153 } 154 155 //调用执行与给定输入为的addr关联的协定 156 //参数。它还处理任何必要的价值转移,并采取 157 //创建帐户和在 158 //执行错误或值传输失败。 159 func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) { 160 if evm.vmConfig.NoRecursion && evm.depth > 0 { 161 return nil, gas, nil 162 } 163 164 //如果我们试图执行超过调用深度限制,则失败 165 if evm.depth > int(params.CallCreateDepth) { 166 return nil, gas, ErrDepth 167 } 168 //如果我们试图转移的余额超过可用余额,则失败 169 if !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) { 170 return nil, gas, ErrInsufficientBalance 171 } 172 173 var ( 174 to = AccountRef(addr) 175 snapshot = evm.StateDB.Snapshot() 176 ) 177 if !evm.StateDB.Exist(addr) { 178 precompiles := PrecompiledContractsHomestead 179 if evm.ChainConfig().IsByzantium(evm.BlockNumber) { 180 precompiles = PrecompiledContractsByzantium 181 } 182 if precompiles[addr] == nil && evm.ChainConfig().IsEIP158(evm.BlockNumber) && value.Sign() == 0 { 183 //调用一个不存在的帐户,不要做任何事情,只需ping跟踪程序 184 if evm.vmConfig.Debug && evm.depth == 0 { 185 evm.vmConfig.Tracer.CaptureStart(caller.Address(), addr, false, input, gas, value) 186 evm.vmConfig.Tracer.CaptureEnd(ret, 0, 0, nil) 187 } 188 return nil, gas, nil 189 } 190 evm.StateDB.CreateAccount(addr) 191 } 192 evm.Transfer(evm.StateDB, caller.Address(), to.Address(), value) 193 194 //初始化新合同并设置EVM要使用的代码。 195 //契约只是这个执行上下文的作用域环境。 196 contract := NewContract(caller, to, value, gas) 197 contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) 198 199 start := time.Now() 200 201 //在调试模式下捕获跟踪程序开始/结束事件 202 if evm.vmConfig.Debug && evm.depth == 0 { 203 evm.vmConfig.Tracer.CaptureStart(caller.Address(), addr, false, input, gas, value) 204 205 defer func() { //参数的延迟评估 206 evm.vmConfig.Tracer.CaptureEnd(ret, gas-contract.Gas, time.Since(start), err) 207 }() 208 } 209 ret, err = run(evm, contract, input) 210 211 //当EVM返回错误或设置创建代码时 212 //在上面,我们返回快照并消耗所有剩余的气体。另外 213 //当我们在宅基地时,这也算是代码存储气体错误。 214 if err != nil { 215 evm.StateDB.RevertToSnapshot(snapshot) 216 if err != errExecutionReverted { 217 contract.UseGas(contract.Gas) 218 } 219 } 220 return ret, contract.Gas, err 221 } 222 223 //callcode使用给定的输入执行与addr关联的协定 224 //作为参数。它还处理任何必要的价值转移,并采取 225 //创建帐户和在 226 //执行错误或值传输失败。 227 // 228 //callcode与call的区别在于它执行给定的地址' 229 //以调用方为上下文的代码。 230 func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) { 231 if evm.vmConfig.NoRecursion && evm.depth > 0 { 232 return nil, gas, nil 233 } 234 235 //如果我们试图执行超过调用深度限制,则失败 236 if evm.depth > int(params.CallCreateDepth) { 237 return nil, gas, ErrDepth 238 } 239 //如果我们试图转移的余额超过可用余额,则失败 240 if !evm.CanTransfer(evm.StateDB, caller.Address(), value) { 241 return nil, gas, ErrInsufficientBalance 242 } 243 244 var ( 245 snapshot = evm.StateDB.Snapshot() 246 to = AccountRef(caller.Address()) 247 ) 248 //初始化新合同并设置 249 //EVM。合同是此执行上下文的作用域环境 250 //只有。 251 contract := NewContract(caller, to, value, gas) 252 contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) 253 254 ret, err = run(evm, contract, input) 255 if err != nil { 256 evm.StateDB.RevertToSnapshot(snapshot) 257 if err != errExecutionReverted { 258 contract.UseGas(contract.Gas) 259 } 260 } 261 return ret, contract.Gas, err 262 } 263 264 //DelegateCall执行与给定输入的addr关联的协定 265 //作为参数。如果发生执行错误,它将反转状态。 266 // 267 //delegateCall与callcode的区别在于它执行给定的地址' 268 //以调用者为上下文的代码,调用者被设置为调用者的调用者。 269 func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) { 270 if evm.vmConfig.NoRecursion && evm.depth > 0 { 271 return nil, gas, nil 272 } 273 //如果我们试图执行超过调用深度限制,则失败 274 if evm.depth > int(params.CallCreateDepth) { 275 return nil, gas, ErrDepth 276 } 277 278 var ( 279 snapshot = evm.StateDB.Snapshot() 280 to = AccountRef(caller.Address()) 281 ) 282 283 //初始化新合同并使委托值初始化 284 contract := NewContract(caller, to, nil, gas).AsDelegate() 285 contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) 286 287 ret, err = run(evm, contract, input) 288 if err != nil { 289 evm.StateDB.RevertToSnapshot(snapshot) 290 if err != errExecutionReverted { 291 contract.UseGas(contract.Gas) 292 } 293 } 294 return ret, contract.Gas, err 295 } 296 297 //staticCall使用给定的输入执行与addr关联的协定 298 //作为参数,同时不允许在调用期间对状态进行任何修改。 299 //试图执行此类修改的操作码将导致异常 300 //而不是执行修改。 301 func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) { 302 if evm.vmConfig.NoRecursion && evm.depth > 0 { 303 return nil, gas, nil 304 } 305 //如果我们试图执行超过调用深度限制,则失败 306 if evm.depth > int(params.CallCreateDepth) { 307 return nil, gas, ErrDepth 308 } 309 //确保仅当我们不在readonly中时才设置readonly 310 //这还确保不会为删除只读标志 311 //儿童电话。 312 if !evm.interpreter.IsReadOnly() { 313 evm.interpreter.SetReadOnly(true) 314 defer func() { evm.interpreter.SetReadOnly(false) }() 315 } 316 317 var ( 318 to = AccountRef(addr) 319 snapshot = evm.StateDB.Snapshot() 320 ) 321 //初始化新合同并设置 322 //EVM。合同是此执行上下文的作用域环境 323 //只有。 324 contract := NewContract(caller, to, new(big.Int), gas) 325 contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) 326 327 //当EVM返回错误或设置创建代码时 328 //在上面,我们返回快照并消耗所有剩余的气体。另外 329 //当我们在宅基地时,这也算是代码存储气体错误。 330 ret, err = run(evm, contract, input) 331 if err != nil { 332 evm.StateDB.RevertToSnapshot(snapshot) 333 if err != errExecutionReverted { 334 contract.UseGas(contract.Gas) 335 } 336 } 337 return ret, contract.Gas, err 338 } 339 340 //创建使用代码作为部署代码创建新合同。 341 func (evm *EVM) create(caller ContractRef, code []byte, gas uint64, value *big.Int, address common.Address) ([]byte, common.Address, uint64, error) { 342 //深度检查执行。如果我们试图执行上面的 343 //极限。 344 if evm.depth > int(params.CallCreateDepth) { 345 return nil, common.Address{}, gas, ErrDepth 346 } 347 if !evm.CanTransfer(evm.StateDB, caller.Address(), value) { 348 return nil, common.Address{}, gas, ErrInsufficientBalance 349 } 350 nonce := evm.StateDB.GetNonce(caller.Address()) 351 evm.StateDB.SetNonce(caller.Address(), nonce+1) 352 353 //确保指定地址没有现有合同 354 contractHash := evm.StateDB.GetCodeHash(address) 355 if evm.StateDB.GetNonce(address) != 0 || (contractHash != (common.Hash{}) && contractHash != emptyCodeHash) { 356 return nil, common.Address{}, 0, ErrContractAddressCollision 357 } 358 //在该州创建新帐户 359 snapshot := evm.StateDB.Snapshot() 360 evm.StateDB.CreateAccount(address) 361 if evm.ChainConfig().IsEIP158(evm.BlockNumber) { 362 evm.StateDB.SetNonce(address, 1) 363 } 364 evm.Transfer(evm.StateDB, caller.Address(), address, value) 365 366 //初始化新合同并设置 367 //EVM。合同是此执行上下文的作用域环境 368 //只有。 369 contract := NewContract(caller, AccountRef(address), value, gas) 370 contract.SetCallCode(&address, crypto.Keccak256Hash(code), code) 371 372 if evm.vmConfig.NoRecursion && evm.depth > 0 { 373 return nil, address, gas, nil 374 } 375 376 if evm.vmConfig.Debug && evm.depth == 0 { 377 evm.vmConfig.Tracer.CaptureStart(caller.Address(), address, true, code, gas, value) 378 } 379 start := time.Now() 380 381 ret, err := run(evm, contract, nil) 382 383 //检查是否超过了最大代码大小 384 maxCodeSizeExceeded := evm.ChainConfig().IsEIP158(evm.BlockNumber) && len(ret) > params.MaxCodeSize 385 //如果合同创建成功运行且未返回错误 386 //计算存储代码所需的气体。如果代码不能 387 //因气量不足而储存,设置错误并处理 388 //通过下面的错误检查条件。 389 if err == nil && !maxCodeSizeExceeded { 390 createDataGas := uint64(len(ret)) * params.CreateDataGas 391 if contract.UseGas(createDataGas) { 392 evm.StateDB.SetCode(address, ret) 393 } else { 394 err = ErrCodeStoreOutOfGas 395 } 396 } 397 398 //当EVM返回错误或设置创建代码时 399 //在上面,我们返回快照并消耗所有剩余的气体。另外 400 //当我们在宅基地时,这也算是代码存储气体错误。 401 if maxCodeSizeExceeded || (err != nil && (evm.ChainConfig().IsHomestead(evm.BlockNumber) || err != ErrCodeStoreOutOfGas)) { 402 evm.StateDB.RevertToSnapshot(snapshot) 403 if err != errExecutionReverted { 404 contract.UseGas(contract.Gas) 405 } 406 } 407 //如果合同代码大小超过最大值而错误仍然为空,则分配错误。 408 if maxCodeSizeExceeded && err == nil { 409 err = errMaxCodeSizeExceeded 410 } 411 if evm.vmConfig.Debug && evm.depth == 0 { 412 evm.vmConfig.Tracer.CaptureEnd(ret, gas-contract.Gas, time.Since(start), err) 413 } 414 return ret, address, contract.Gas, err 415 416 } 417 418 //创建使用代码作为部署代码创建新合同。 419 func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) { 420 contractAddr = crypto.CreateAddress(caller.Address(), evm.StateDB.GetNonce(caller.Address())) 421 return evm.create(caller, code, gas, value, contractAddr) 422 } 423 424 //Create2使用代码作为部署代码创建新合同。 425 // 426 //create2与create的区别是create2使用sha3(0xff++msg.sender++salt++sha3(init_code))[12:] 427 //而不是通常的发送者和nonce散列作为合同初始化的地址。 428 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) { 429 contractAddr = crypto.CreateAddress2(caller.Address(), common.BigToHash(salt), code) 430 return evm.create(caller, code, gas, endowment, contractAddr) 431 } 432 433 //chainconfig返回环境的链配置 434 func (evm *EVM) ChainConfig() *params.ChainConfig { return evm.chainConfig } 435