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