github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/eth/api_tracer.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 //版权所有2017 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 eth 26 27 import ( 28 "bytes" 29 "context" 30 "errors" 31 "fmt" 32 "io/ioutil" 33 "runtime" 34 "sync" 35 "time" 36 37 "github.com/ethereum/go-ethereum/common" 38 "github.com/ethereum/go-ethereum/common/hexutil" 39 "github.com/ethereum/go-ethereum/core" 40 "github.com/ethereum/go-ethereum/core/rawdb" 41 "github.com/ethereum/go-ethereum/core/state" 42 "github.com/ethereum/go-ethereum/core/types" 43 "github.com/ethereum/go-ethereum/core/vm" 44 "github.com/ethereum/go-ethereum/eth/tracers" 45 "github.com/ethereum/go-ethereum/internal/ethapi" 46 "github.com/ethereum/go-ethereum/log" 47 "github.com/ethereum/go-ethereum/rlp" 48 "github.com/ethereum/go-ethereum/rpc" 49 "github.com/ethereum/go-ethereum/trie" 50 ) 51 52 const ( 53 //DefaultTraceTimeout是单个事务可以执行的时间量 54 //默认情况下,在强制中止之前。 55 defaultTraceTimeout = 5 * time.Second 56 57 //defaulttracereexec是跟踪程序愿意返回的块数。 58 //重新执行以产生运行特定 59 //痕迹。 60 defaultTraceReexec = uint64(128) 61 ) 62 63 //traceconfig保存跟踪函数的额外参数。 64 type TraceConfig struct { 65 *vm.LogConfig 66 Tracer *string 67 Timeout *string 68 Reexec *uint64 69 } 70 71 //txtracesult是单个事务跟踪的结果。 72 type txTraceResult struct { 73 Result interface{} `json:"result,omitempty"` //示踪剂产生的示踪结果 74 Error string `json:"error,omitempty"` //示踪剂产生的示踪失效 75 } 76 77 //当整个链为 78 //被追踪。 79 type blockTraceTask struct { 80 statedb *state.StateDB //准备跟踪的中间状态 81 block *types.Block //用于跟踪事务的块 82 rootref common.Hash //为此任务保留的trie根引用 83 results []*txTraceResult //跟踪结果按任务进行 84 } 85 86 //blocktraceresult represets当一个完整的 87 //正在跟踪链。 88 type blockTraceResult struct { 89 Block hexutil.Uint64 `json:"block"` //与此跟踪对应的块号 90 Hash common.Hash `json:"hash"` //与此跟踪对应的块哈希 91 Traces []*txTraceResult `json:"traces"` //跟踪任务生成的结果 92 } 93 94 //txtracetask表示当整个块 95 //正在跟踪。 96 type txTraceTask struct { 97 statedb *state.StateDB //准备跟踪的中间状态 98 index int //块中的事务偏移量 99 } 100 101 //tracechain返回在执行evm期间创建的结构化日志 102 //在两个块之间(不包括start),并将它们作为JSON对象返回。 103 func (api *PrivateDebugAPI) TraceChain(ctx context.Context, start, end rpc.BlockNumber, config *TraceConfig) (*rpc.Subscription, error) { 104 //获取要跟踪的块间隔 105 var from, to *types.Block 106 107 switch start { 108 case rpc.PendingBlockNumber: 109 from = api.eth.miner.PendingBlock() 110 case rpc.LatestBlockNumber: 111 from = api.eth.blockchain.CurrentBlock() 112 default: 113 from = api.eth.blockchain.GetBlockByNumber(uint64(start)) 114 } 115 switch end { 116 case rpc.PendingBlockNumber: 117 to = api.eth.miner.PendingBlock() 118 case rpc.LatestBlockNumber: 119 to = api.eth.blockchain.CurrentBlock() 120 default: 121 to = api.eth.blockchain.GetBlockByNumber(uint64(end)) 122 } 123 //如果我们找到了所有的区块,就追踪这条链。 124 if from == nil { 125 return nil, fmt.Errorf("starting block #%d not found", start) 126 } 127 if to == nil { 128 return nil, fmt.Errorf("end block #%d not found", end) 129 } 130 if from.Number().Cmp(to.Number()) >= 0 { 131 return nil, fmt.Errorf("end block (#%d) needs to come after start block (#%d)", end, start) 132 } 133 return api.traceChain(ctx, from, to, config) 134 } 135 136 //tracechain根据提供的配置配置配置新的跟踪程序,以及 137 //执行中包含的所有事务。返回值将是一个项目 138 //每个事务,取决于请求的跟踪程序。 139 func (api *PrivateDebugAPI) traceChain(ctx context.Context, start, end *types.Block, config *TraceConfig) (*rpc.Subscription, error) { 140 //跟踪链是一个**长**的操作,只处理订阅 141 notifier, supported := rpc.NotifierFromContext(ctx) 142 if !supported { 143 return &rpc.Subscription{}, rpc.ErrNotificationsUnsupported 144 } 145 sub := notifier.CreateSubscription() 146 147 //在进行任何工作之前,确保我们有一个有效的启动状态 148 origin := start.NumberU64() 149 database := state.NewDatabase(api.eth.ChainDb()) 150 151 if number := start.NumberU64(); number > 0 { 152 start = api.eth.blockchain.GetBlock(start.ParentHash(), start.NumberU64()-1) 153 if start == nil { 154 return nil, fmt.Errorf("parent block #%d not found", number-1) 155 } 156 } 157 statedb, err := state.New(start.Root(), database) 158 if err != nil { 159 //如果缺少起始状态,则允许重新执行一些块。 160 reexec := defaultTraceReexec 161 if config != nil && config.Reexec != nil { 162 reexec = *config.Reexec 163 } 164 //查找具有可用状态的最新块 165 for i := uint64(0); i < reexec; i++ { 166 start = api.eth.blockchain.GetBlock(start.ParentHash(), start.NumberU64()-1) 167 if start == nil { 168 break 169 } 170 if statedb, err = state.New(start.Root(), database); err == nil { 171 break 172 } 173 } 174 //如果我们还没有州政府的支持,那就纾困吧。 175 if err != nil { 176 switch err.(type) { 177 case *trie.MissingNodeError: 178 return nil, errors.New("required historical state unavailable") 179 default: 180 return nil, err 181 } 182 } 183 } 184 //为每个块同时执行链中包含的所有事务 185 blocks := int(end.NumberU64() - origin) 186 187 threads := runtime.NumCPU() 188 if threads > blocks { 189 threads = blocks 190 } 191 var ( 192 pend = new(sync.WaitGroup) 193 tasks = make(chan *blockTraceTask, threads) 194 results = make(chan *blockTraceTask, threads) 195 ) 196 for th := 0; th < threads; th++ { 197 pend.Add(1) 198 go func() { 199 defer pend.Done() 200 201 //获取并执行下一个块跟踪任务 202 for task := range tasks { 203 signer := types.MakeSigner(api.config, task.block.Number()) 204 205 //跟踪包含在 206 for i, tx := range task.block.Transactions() { 207 msg, _ := tx.AsMessage(signer) 208 vmctx := core.NewEVMContext(msg, task.block.Header(), api.eth.blockchain, nil) 209 210 res, err := api.traceTx(ctx, msg, vmctx, task.statedb, config) 211 if err != nil { 212 task.results[i] = &txTraceResult{Error: err.Error()} 213 log.Warn("Tracing failed", "hash", tx.Hash(), "block", task.block.NumberU64(), "err", err) 214 break 215 } 216 task.statedb.Finalise(true) 217 task.results[i] = &txTraceResult{Result: res} 218 } 219 //将结果返回给用户或在拆卸时中止 220 select { 221 case results <- task: 222 case <-notifier.Closed(): 223 return 224 } 225 } 226 }() 227 } 228 //启动一个GODUTIN将所有的块输入示踪剂 229 begin := time.Now() 230 231 go func() { 232 var ( 233 logged time.Time 234 number uint64 235 traced uint64 236 failed error 237 proot common.Hash 238 ) 239 //确保所有出口通道上的物品都被正确清理干净。 240 defer func() { 241 close(tasks) 242 pend.Wait() 243 244 switch { 245 case failed != nil: 246 log.Warn("Chain tracing failed", "start", start.NumberU64(), "end", end.NumberU64(), "transactions", traced, "elapsed", time.Since(begin), "err", failed) 247 case number < end.NumberU64(): 248 log.Warn("Chain tracing aborted", "start", start.NumberU64(), "end", end.NumberU64(), "abort", number, "transactions", traced, "elapsed", time.Since(begin)) 249 default: 250 log.Info("Chain tracing finished", "start", start.NumberU64(), "end", end.NumberU64(), "transactions", traced, "elapsed", time.Since(begin)) 251 } 252 close(results) 253 }() 254 //同时将所有块都输入跟踪程序以及快速处理 255 for number = start.NumberU64() + 1; number <= end.NumberU64(); number++ { 256 //如果请求中断,则停止跟踪 257 select { 258 case <-notifier.Closed(): 259 return 260 default: 261 } 262 //如果经过足够长的时间,则打印进度日志 263 if time.Since(logged) > 8*time.Second { 264 if number > origin { 265 nodes, imgs := database.TrieDB().Size() 266 log.Info("Tracing chain segment", "start", origin, "end", end.NumberU64(), "current", number, "transactions", traced, "elapsed", time.Since(begin), "memory", nodes+imgs) 267 } else { 268 log.Info("Preparing state for chain trace", "block", number, "start", origin, "elapsed", time.Since(begin)) 269 } 270 logged = time.Now() 271 } 272 //检索下一个要跟踪的块 273 block := api.eth.blockchain.GetBlockByNumber(number) 274 if block == nil { 275 failed = fmt.Errorf("block #%d not found", number) 276 break 277 } 278 //将块发送到并发跟踪程序(如果不是在快进阶段) 279 if number > origin { 280 txs := block.Transactions() 281 282 select { 283 case tasks <- &blockTraceTask{statedb: statedb.Copy(), block: block, rootref: proot, results: make([]*txTraceResult, len(txs))}: 284 case <-notifier.Closed(): 285 return 286 } 287 traced += uint64(len(txs)) 288 } 289 //快速生成下一个状态快照,无需跟踪 290 _, _, _, err := api.eth.blockchain.Processor().Process(block, statedb, vm.Config{}) 291 if err != nil { 292 failed = err 293 break 294 } 295 //最终确定状态,以便将任何修改写入trie 296 root, err := statedb.Commit(true) 297 if err != nil { 298 failed = err 299 break 300 } 301 if err := statedb.Reset(root); err != nil { 302 failed = err 303 break 304 } 305 //两次,一次给我们,一次给出纳员 306 database.TrieDB().Reference(root, common.Hash{}) 307 if number >= origin { 308 database.TrieDB().Reference(root, common.Hash{}) 309 } 310 //取消引用我们自己已经完成的所有尝试 311 if proot != (common.Hash{}) { 312 database.TrieDB().Dereference(proot) 313 } 314 proot = root 315 316 //托多(卡拉贝拉):我们需要预成像吗?他们不会积累太多吗? 317 } 318 }() 319 320 //继续读取跟踪结果并将其传输给用户 321 go func() { 322 var ( 323 done = make(map[uint64]*blockTraceResult) 324 next = origin + 1 325 ) 326 for res := range results { 327 //排队等待下一个接收结果 328 result := &blockTraceResult{ 329 Block: hexutil.Uint64(res.block.NumberU64()), 330 Hash: res.block.Hash(), 331 Traces: res.results, 332 } 333 done[uint64(result.Block)] = result 334 335 //取消引用此任务在内存中保留的任何paret尝试 336 database.TrieDB().Dereference(res.rootref) 337 338 //流完成对用户的跟踪,在第一个错误上中止 339 for result, ok := done[next]; ok; result, ok = done[next] { 340 if len(result.Traces) > 0 || next == end.NumberU64() { 341 notifier.Notify(sub.ID, result) 342 } 343 delete(done, next) 344 next++ 345 } 346 } 347 }() 348 return sub, nil 349 } 350 351 //traceBlockByNumber返回在执行期间创建的结构化日志 352 //EVM并将其作为JSON对象返回。 353 func (api *PrivateDebugAPI) TraceBlockByNumber(ctx context.Context, number rpc.BlockNumber, config *TraceConfig) ([]*txTraceResult, error) { 354 //获取要跟踪的块 355 var block *types.Block 356 357 switch number { 358 case rpc.PendingBlockNumber: 359 block = api.eth.miner.PendingBlock() 360 case rpc.LatestBlockNumber: 361 block = api.eth.blockchain.CurrentBlock() 362 default: 363 block = api.eth.blockchain.GetBlockByNumber(uint64(number)) 364 } 365 //如果找到块,跟踪它 366 if block == nil { 367 return nil, fmt.Errorf("block #%d not found", number) 368 } 369 return api.traceBlock(ctx, block, config) 370 } 371 372 //traceBlockByHash返回在执行期间创建的结构化日志 373 //EVM并将其作为JSON对象返回。 374 func (api *PrivateDebugAPI) TraceBlockByHash(ctx context.Context, hash common.Hash, config *TraceConfig) ([]*txTraceResult, error) { 375 block := api.eth.blockchain.GetBlockByHash(hash) 376 if block == nil { 377 return nil, fmt.Errorf("block #%x not found", hash) 378 } 379 return api.traceBlock(ctx, block, config) 380 } 381 382 //traceblock返回在执行evm期间创建的结构化日志 383 //并将它们作为JSON对象返回。 384 func (api *PrivateDebugAPI) TraceBlock(ctx context.Context, blob []byte, config *TraceConfig) ([]*txTraceResult, error) { 385 block := new(types.Block) 386 if err := rlp.Decode(bytes.NewReader(blob), block); err != nil { 387 return nil, fmt.Errorf("could not decode block: %v", err) 388 } 389 return api.traceBlock(ctx, block, config) 390 } 391 392 //traceblockfromfile返回在执行期间创建的结构化日志 393 //EVM并将其作为JSON对象返回。 394 func (api *PrivateDebugAPI) TraceBlockFromFile(ctx context.Context, file string, config *TraceConfig) ([]*txTraceResult, error) { 395 blob, err := ioutil.ReadFile(file) 396 if err != nil { 397 return nil, fmt.Errorf("could not read file: %v", err) 398 } 399 return api.TraceBlock(ctx, blob, config) 400 } 401 402 //跟踪块根据提供的配置配置配置新的跟踪程序,以及 403 //执行中包含的所有事务。返回值将是一个项目 404 //每个事务,取决于请求的跟踪程序。 405 //跟踪块根据提供的配置配置配置新的跟踪程序,以及 406 //执行中包含的所有事务。返回值将是一个项目 407 //每个事务,取决于请求的跟踪程序。 408 func (api *PrivateDebugAPI) traceBlock(ctx context.Context, block *types.Block, config *TraceConfig) ([]*txTraceResult, error) { 409 //创建父状态数据库 410 bi := api.eth.blockchain.GetHeaderByNumber(0).BlockInterval 411 if err := api.eth.engine.VerifyHeader(api.eth.blockchain, block.Header(), true, bi); err != nil { 412 return nil, err 413 } 414 parent := api.eth.blockchain.GetBlock(block.ParentHash(), block.NumberU64()-1) 415 if parent == nil { 416 return nil, fmt.Errorf("parent %x not found", block.ParentHash()) 417 } 418 reexec := defaultTraceReexec 419 if config != nil && config.Reexec != nil { 420 reexec = *config.Reexec 421 } 422 statedb, err := api.computeStateDB(parent, reexec) 423 if err != nil { 424 return nil, err 425 } 426 //同时执行块内包含的所有事务 427 var ( 428 signer = types.MakeSigner(api.config, block.Number()) 429 430 txs = block.Transactions() 431 results = make([]*txTraceResult, len(txs)) 432 433 pend = new(sync.WaitGroup) 434 jobs = make(chan *txTraceTask, len(txs)) 435 ) 436 threads := runtime.NumCPU() 437 if threads > len(txs) { 438 threads = len(txs) 439 } 440 for th := 0; th < threads; th++ { 441 pend.Add(1) 442 go func() { 443 defer pend.Done() 444 445 //获取并执行下一个事务跟踪任务 446 for task := range jobs { 447 msg, _ := txs[task.index].AsMessage(signer) 448 vmctx := core.NewEVMContext(msg, block.Header(), api.eth.blockchain, nil) 449 450 res, err := api.traceTx(ctx, msg, vmctx, task.statedb, config) 451 if err != nil { 452 results[task.index] = &txTraceResult{Error: err.Error()} 453 continue 454 } 455 results[task.index] = &txTraceResult{Result: res} 456 } 457 }() 458 } 459 //将事务输入跟踪程序并返回 460 var failed error 461 for i, tx := range txs { 462 //发送跟踪任务以供执行 463 jobs <- &txTraceTask{statedb: statedb.Copy(), index: i} 464 465 //快速生成下一个状态快照,无需跟踪 466 msg, _ := tx.AsMessage(signer) 467 vmctx := core.NewEVMContext(msg, block.Header(), api.eth.blockchain, nil) 468 469 vmenv := vm.NewEVM(vmctx, statedb, api.config, vm.Config{}) 470 if _, _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil { 471 failed = err 472 break 473 } 474 //最终确定状态,以便将任何修改写入trie 475 statedb.Finalise(true) 476 } 477 close(jobs) 478 pend.Wait() 479 480 //如果执行失败,则中止 481 if failed != nil { 482 return nil, failed 483 } 484 return results, nil 485 } 486 //ComputeTestedB检索与某个块关联的状态数据库。 487 //如果给定块没有本地可用的状态,则有许多块 488 //试图重新执行以生成所需状态。 489 func (api *PrivateDebugAPI) computeStateDB(block *types.Block, reexec uint64) (*state.StateDB, error) { 490 //如果我们的状态完全可用,请使用 491 statedb, err := api.eth.blockchain.StateAt(block.Root()) 492 if err == nil { 493 return statedb, nil 494 } 495 //否则,尝试重新执行块,直到找到状态或达到限制 496 origin := block.NumberU64() 497 database := state.NewDatabase(api.eth.ChainDb()) 498 499 for i := uint64(0); i < reexec; i++ { 500 block = api.eth.blockchain.GetBlock(block.ParentHash(), block.NumberU64()-1) 501 if block == nil { 502 break 503 } 504 if statedb, err = state.New(block.Root(), database); err == nil { 505 break 506 } 507 } 508 if err != nil { 509 switch err.(type) { 510 case *trie.MissingNodeError: 511 return nil, errors.New("required historical state unavailable") 512 default: 513 return nil, err 514 } 515 } 516 //状态在历史点可用,重新生成 517 var ( 518 start = time.Now() 519 logged time.Time 520 proot common.Hash 521 ) 522 for block.NumberU64() < origin { 523 //如果经过足够长的时间,则打印进度日志 524 if time.Since(logged) > 8*time.Second { 525 log.Info("Regenerating historical state", "block", block.NumberU64()+1, "target", origin, "elapsed", time.Since(start)) 526 logged = time.Now() 527 } 528 //检索下一个块以重新生成并处理它 529 if block = api.eth.blockchain.GetBlockByNumber(block.NumberU64() + 1); block == nil { 530 return nil, fmt.Errorf("block #%d not found", block.NumberU64()+1) 531 } 532 _, _, _, err := api.eth.blockchain.Processor().Process(block, statedb, vm.Config{}) 533 if err != nil { 534 return nil, err 535 } 536 //最终确定状态,以便将任何修改写入trie 537 root, err := statedb.Commit(true) 538 if err != nil { 539 return nil, err 540 } 541 if err := statedb.Reset(root); err != nil { 542 return nil, err 543 } 544 database.TrieDB().Reference(root, common.Hash{}) 545 if proot != (common.Hash{}) { 546 database.TrieDB().Dereference(proot) 547 } 548 proot = root 549 } 550 nodes, imgs := database.TrieDB().Size() 551 log.Info("Historical state regenerated", "block", block.NumberU64(), "elapsed", time.Since(start), "nodes", nodes, "preimages", imgs) 552 return statedb, nil 553 } 554 555 //traceTransaction返回执行evm期间创建的结构化日志 556 //并将它们作为JSON对象返回。 557 func (api *PrivateDebugAPI) TraceTransaction(ctx context.Context, hash common.Hash, config *TraceConfig) (interface{}, error) { 558 //检索事务并组装其EVM上下文 559 tx, blockHash, _, index := rawdb.ReadTransaction(api.eth.ChainDb(), hash) 560 if tx == nil { 561 return nil, fmt.Errorf("transaction %x not found", hash) 562 } 563 reexec := defaultTraceReexec 564 if config != nil && config.Reexec != nil { 565 reexec = *config.Reexec 566 } 567 msg, vmctx, statedb, err := api.computeTxEnv(blockHash, int(index), reexec) 568 if err != nil { 569 return nil, err 570 } 571 //跟踪事务和返回 572 return api.traceTx(ctx, msg, vmctx, statedb, config) 573 } 574 575 //tracetx根据提供的配置配置配置新的跟踪程序,以及 576 //在提供的环境中执行给定的消息。返回值将 577 //取决于示踪剂。 578 func (api *PrivateDebugAPI) traceTx(ctx context.Context, message core.Message, vmctx vm.Context, statedb *state.StateDB, config *TraceConfig) (interface{}, error) { 579 //组装结构化记录器或JavaScript跟踪程序 580 var ( 581 tracer vm.Tracer 582 err error 583 ) 584 switch { 585 case config != nil && config.Tracer != nil: 586 //定义单个事务跟踪的有意义的超时 587 timeout := defaultTraceTimeout 588 if config.Timeout != nil { 589 if timeout, err = time.ParseDuration(*config.Timeout); err != nil { 590 return nil, err 591 } 592 } 593 //构造要用其执行的javascript跟踪程序 594 if tracer, err = tracers.New(*config.Tracer); err != nil { 595 return nil, err 596 } 597 //处理超时和RPC取消 598 deadlineCtx, cancel := context.WithTimeout(ctx, timeout) 599 go func() { 600 <-deadlineCtx.Done() 601 tracer.(*tracers.Tracer).Stop(errors.New("execution timeout")) 602 }() 603 defer cancel() 604 605 case config == nil: 606 tracer = vm.NewStructLogger(nil) 607 608 default: 609 tracer = vm.NewStructLogger(config.LogConfig) 610 } 611 //在启用跟踪的情况下运行事务。 612 vmenv := vm.NewEVM(vmctx, statedb, api.config, vm.Config{Debug: true, Tracer: tracer}) 613 614 ret, gas, failed, err := core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas())) 615 if err != nil { 616 return nil, fmt.Errorf("tracing failed: %v", err) 617 } 618 //根据跟踪类型、格式和返回输出 619 switch tracer := tracer.(type) { 620 case *vm.StructLogger: 621 return ðapi.ExecutionResult{ 622 Gas: gas, 623 Failed: failed, 624 ReturnValue: fmt.Sprintf("%x", ret), 625 StructLogs: ethapi.FormatLogs(tracer.StructLogs()), 626 }, nil 627 628 case *tracers.Tracer: 629 return tracer.GetResult() 630 631 default: 632 panic(fmt.Sprintf("bad tracer type %T", tracer)) 633 } 634 } 635 636 //computetxenv返回特定事务的执行环境。 637 func (api *PrivateDebugAPI) computeTxEnv(blockHash common.Hash, txIndex int, reexec uint64) (core.Message, vm.Context, *state.StateDB, error) { 638 //创建父状态数据库 639 block := api.eth.blockchain.GetBlockByHash(blockHash) 640 if block == nil { 641 return nil, vm.Context{}, nil, fmt.Errorf("block %x not found", blockHash) 642 } 643 parent := api.eth.blockchain.GetBlock(block.ParentHash(), block.NumberU64()-1) 644 if parent == nil { 645 return nil, vm.Context{}, nil, fmt.Errorf("parent %x not found", block.ParentHash()) 646 } 647 statedb, err := api.computeStateDB(parent, reexec) 648 if err != nil { 649 return nil, vm.Context{}, nil, err 650 } 651 //重新计算达到目标索引的事务。 652 signer := types.MakeSigner(api.config, block.Number()) 653 654 for idx, tx := range block.Transactions() { 655 //组装事务调用消息并返回请求的偏移量 656 msg, _ := tx.AsMessage(signer) 657 context := core.NewEVMContext(msg, block.Header(), api.eth.blockchain, nil) 658 if idx == txIndex { 659 return msg, context, statedb, nil 660 } 661 //尚未搜索到事务,请在当前状态的基础上执行 662 vmenv := vm.NewEVM(context, statedb, api.config, vm.Config{}) 663 if _, _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { 664 return nil, vm.Context{}, nil, fmt.Errorf("tx %x failed: %v", tx.Hash(), err) 665 } 666 //确保对国家进行任何修改 667 statedb.Finalise(true) 668 } 669 return nil, vm.Context{}, nil, fmt.Errorf("tx index %d out of range for block %x", txIndex, blockHash) 670 }