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 &ethapi.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