github.com/shrimpyuk/bor@v0.2.15-0.20220224151350-fb4ec6020bae/eth/tracers/api.go (about)

     1  // Copyright 2021 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package tracers
    18  
    19  import (
    20  	"bufio"
    21  	"bytes"
    22  	"context"
    23  	"errors"
    24  	"fmt"
    25  	"io/ioutil"
    26  	"os"
    27  	"runtime"
    28  	"sync"
    29  	"time"
    30  
    31  	"github.com/ethereum/go-ethereum/common"
    32  	"github.com/ethereum/go-ethereum/common/hexutil"
    33  	"github.com/ethereum/go-ethereum/consensus"
    34  	"github.com/ethereum/go-ethereum/core"
    35  	"github.com/ethereum/go-ethereum/core/rawdb"
    36  	"github.com/ethereum/go-ethereum/core/state"
    37  	"github.com/ethereum/go-ethereum/core/types"
    38  	"github.com/ethereum/go-ethereum/core/vm"
    39  	"github.com/ethereum/go-ethereum/ethdb"
    40  	"github.com/ethereum/go-ethereum/internal/ethapi"
    41  	"github.com/ethereum/go-ethereum/log"
    42  	"github.com/ethereum/go-ethereum/params"
    43  	"github.com/ethereum/go-ethereum/rlp"
    44  	"github.com/ethereum/go-ethereum/rpc"
    45  )
    46  
    47  const (
    48  	// defaultTraceTimeout is the amount of time a single transaction can execute
    49  	// by default before being forcefully aborted.
    50  	defaultTraceTimeout = 5 * time.Second
    51  
    52  	// defaultTraceReexec is the number of blocks the tracer is willing to go back
    53  	// and reexecute to produce missing historical state necessary to run a specific
    54  	// trace.
    55  	defaultTraceReexec = uint64(128)
    56  )
    57  
    58  // Backend interface provides the common API services (that are provided by
    59  // both full and light clients) with access to necessary functions.
    60  type Backend interface {
    61  	HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error)
    62  	HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error)
    63  	BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error)
    64  	BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error)
    65  	GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error)
    66  	RPCGasCap() uint64
    67  	ChainConfig() *params.ChainConfig
    68  	Engine() consensus.Engine
    69  	ChainDb() ethdb.Database
    70  	StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, checkLive bool) (*state.StateDB, error)
    71  	StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, error)
    72  }
    73  
    74  // API is the collection of tracing APIs exposed over the private debugging endpoint.
    75  type API struct {
    76  	backend Backend
    77  }
    78  
    79  // NewAPI creates a new API definition for the tracing methods of the Ethereum service.
    80  func NewAPI(backend Backend) *API {
    81  	return &API{backend: backend}
    82  }
    83  
    84  type chainContext struct {
    85  	api *API
    86  	ctx context.Context
    87  }
    88  
    89  func (context *chainContext) Engine() consensus.Engine {
    90  	return context.api.backend.Engine()
    91  }
    92  
    93  func (context *chainContext) GetHeader(hash common.Hash, number uint64) *types.Header {
    94  	header, err := context.api.backend.HeaderByNumber(context.ctx, rpc.BlockNumber(number))
    95  	if err != nil {
    96  		return nil
    97  	}
    98  	if header.Hash() == hash {
    99  		return header
   100  	}
   101  	header, err = context.api.backend.HeaderByHash(context.ctx, hash)
   102  	if err != nil {
   103  		return nil
   104  	}
   105  	return header
   106  }
   107  
   108  // chainContext construts the context reader which is used by the evm for reading
   109  // the necessary chain context.
   110  func (api *API) chainContext(ctx context.Context) core.ChainContext {
   111  	return &chainContext{api: api, ctx: ctx}
   112  }
   113  
   114  // blockByNumber is the wrapper of the chain access function offered by the backend.
   115  // It will return an error if the block is not found.
   116  func (api *API) blockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) {
   117  	block, err := api.backend.BlockByNumber(ctx, number)
   118  	if err != nil {
   119  		return nil, err
   120  	}
   121  	if block == nil {
   122  		return nil, fmt.Errorf("block #%d not found", number)
   123  	}
   124  	return block, nil
   125  }
   126  
   127  // blockByHash is the wrapper of the chain access function offered by the backend.
   128  // It will return an error if the block is not found.
   129  func (api *API) blockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) {
   130  	block, err := api.backend.BlockByHash(ctx, hash)
   131  	if err != nil {
   132  		return nil, err
   133  	}
   134  	if block == nil {
   135  		return nil, fmt.Errorf("block %s not found", hash.Hex())
   136  	}
   137  	return block, nil
   138  }
   139  
   140  // blockByNumberAndHash is the wrapper of the chain access function offered by
   141  // the backend. It will return an error if the block is not found.
   142  //
   143  // Note this function is friendly for the light client which can only retrieve the
   144  // historical(before the CHT) header/block by number.
   145  func (api *API) blockByNumberAndHash(ctx context.Context, number rpc.BlockNumber, hash common.Hash) (*types.Block, error) {
   146  	block, err := api.blockByNumber(ctx, number)
   147  	if err != nil {
   148  		return nil, err
   149  	}
   150  	if block.Hash() == hash {
   151  		return block, nil
   152  	}
   153  	return api.blockByHash(ctx, hash)
   154  }
   155  
   156  // TraceConfig holds extra parameters to trace functions.
   157  type TraceConfig struct {
   158  	*vm.LogConfig
   159  	Tracer  *string
   160  	Timeout *string
   161  	Reexec  *uint64
   162  }
   163  
   164  // TraceCallConfig is the config for traceCall API. It holds one more
   165  // field to override the state for tracing.
   166  type TraceCallConfig struct {
   167  	*vm.LogConfig
   168  	Tracer         *string
   169  	Timeout        *string
   170  	Reexec         *uint64
   171  	StateOverrides *ethapi.StateOverride
   172  }
   173  
   174  // StdTraceConfig holds extra parameters to standard-json trace functions.
   175  type StdTraceConfig struct {
   176  	vm.LogConfig
   177  	Reexec *uint64
   178  	TxHash common.Hash
   179  }
   180  
   181  // txTraceResult is the result of a single transaction trace.
   182  type txTraceResult struct {
   183  	Result interface{} `json:"result,omitempty"` // Trace results produced by the tracer
   184  	Error  string      `json:"error,omitempty"`  // Trace failure produced by the tracer
   185  }
   186  
   187  // blockTraceTask represents a single block trace task when an entire chain is
   188  // being traced.
   189  type blockTraceTask struct {
   190  	statedb *state.StateDB   // Intermediate state prepped for tracing
   191  	block   *types.Block     // Block to trace the transactions from
   192  	rootref common.Hash      // Trie root reference held for this task
   193  	results []*txTraceResult // Trace results procudes by the task
   194  }
   195  
   196  // blockTraceResult represets the results of tracing a single block when an entire
   197  // chain is being traced.
   198  type blockTraceResult struct {
   199  	Block  hexutil.Uint64   `json:"block"`  // Block number corresponding to this trace
   200  	Hash   common.Hash      `json:"hash"`   // Block hash corresponding to this trace
   201  	Traces []*txTraceResult `json:"traces"` // Trace results produced by the task
   202  }
   203  
   204  // txTraceTask represents a single transaction trace task when an entire block
   205  // is being traced.
   206  type txTraceTask struct {
   207  	statedb *state.StateDB // Intermediate state prepped for tracing
   208  	index   int            // Transaction offset in the block
   209  }
   210  
   211  // TraceChain returns the structured logs created during the execution of EVM
   212  // between two blocks (excluding start) and returns them as a JSON object.
   213  func (api *API) TraceChain(ctx context.Context, start, end rpc.BlockNumber, config *TraceConfig) (*rpc.Subscription, error) { // Fetch the block interval that we want to trace
   214  	from, err := api.blockByNumber(ctx, start)
   215  	if err != nil {
   216  		return nil, err
   217  	}
   218  	to, err := api.blockByNumber(ctx, end)
   219  	if err != nil {
   220  		return nil, err
   221  	}
   222  	if from.Number().Cmp(to.Number()) >= 0 {
   223  		return nil, fmt.Errorf("end block (#%d) needs to come after start block (#%d)", end, start)
   224  	}
   225  	return api.traceChain(ctx, from, to, config)
   226  }
   227  
   228  // traceChain configures a new tracer according to the provided configuration, and
   229  // executes all the transactions contained within. The return value will be one item
   230  // per transaction, dependent on the requested tracer.
   231  func (api *API) traceChain(ctx context.Context, start, end *types.Block, config *TraceConfig) (*rpc.Subscription, error) {
   232  	// Tracing a chain is a **long** operation, only do with subscriptions
   233  	notifier, supported := rpc.NotifierFromContext(ctx)
   234  	if !supported {
   235  		return &rpc.Subscription{}, rpc.ErrNotificationsUnsupported
   236  	}
   237  	sub := notifier.CreateSubscription()
   238  
   239  	// Prepare all the states for tracing. Note this procedure can take very
   240  	// long time. Timeout mechanism is necessary.
   241  	reexec := defaultTraceReexec
   242  	if config != nil && config.Reexec != nil {
   243  		reexec = *config.Reexec
   244  	}
   245  	blocks := int(end.NumberU64() - start.NumberU64())
   246  	threads := runtime.NumCPU()
   247  	if threads > blocks {
   248  		threads = blocks
   249  	}
   250  	var (
   251  		pend     = new(sync.WaitGroup)
   252  		tasks    = make(chan *blockTraceTask, threads)
   253  		results  = make(chan *blockTraceTask, threads)
   254  		localctx = context.Background()
   255  	)
   256  	for th := 0; th < threads; th++ {
   257  		pend.Add(1)
   258  		go func() {
   259  			defer pend.Done()
   260  
   261  			// Fetch and execute the next block trace tasks
   262  			for task := range tasks {
   263  				signer := types.MakeSigner(api.backend.ChainConfig(), task.block.Number())
   264  				blockCtx := core.NewEVMBlockContext(task.block.Header(), api.chainContext(localctx), nil)
   265  				// Trace all the transactions contained within
   266  				for i, tx := range task.block.Transactions() {
   267  					msg, _ := tx.AsMessage(signer, task.block.BaseFee())
   268  					txctx := &Context{
   269  						BlockHash: task.block.Hash(),
   270  						TxIndex:   i,
   271  						TxHash:    tx.Hash(),
   272  					}
   273  					res, err := api.traceTx(localctx, msg, txctx, blockCtx, task.statedb, config)
   274  					if err != nil {
   275  						task.results[i] = &txTraceResult{Error: err.Error()}
   276  						log.Warn("Tracing failed", "hash", tx.Hash(), "block", task.block.NumberU64(), "err", err)
   277  						break
   278  					}
   279  					// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
   280  					task.statedb.Finalise(api.backend.ChainConfig().IsEIP158(task.block.Number()))
   281  					task.results[i] = &txTraceResult{Result: res}
   282  				}
   283  				// Stream the result back to the user or abort on teardown
   284  				select {
   285  				case results <- task:
   286  				case <-notifier.Closed():
   287  					return
   288  				}
   289  			}
   290  		}()
   291  	}
   292  	// Start a goroutine to feed all the blocks into the tracers
   293  	var (
   294  		begin     = time.Now()
   295  		derefTodo []common.Hash // list of hashes to dereference from the db
   296  		derefsMu  sync.Mutex    // mutex for the derefs
   297  	)
   298  
   299  	go func() {
   300  		var (
   301  			logged  time.Time
   302  			number  uint64
   303  			traced  uint64
   304  			failed  error
   305  			parent  common.Hash
   306  			statedb *state.StateDB
   307  		)
   308  		// Ensure everything is properly cleaned up on any exit path
   309  		defer func() {
   310  			close(tasks)
   311  			pend.Wait()
   312  
   313  			switch {
   314  			case failed != nil:
   315  				log.Warn("Chain tracing failed", "start", start.NumberU64(), "end", end.NumberU64(), "transactions", traced, "elapsed", time.Since(begin), "err", failed)
   316  			case number < end.NumberU64():
   317  				log.Warn("Chain tracing aborted", "start", start.NumberU64(), "end", end.NumberU64(), "abort", number, "transactions", traced, "elapsed", time.Since(begin))
   318  			default:
   319  				log.Info("Chain tracing finished", "start", start.NumberU64(), "end", end.NumberU64(), "transactions", traced, "elapsed", time.Since(begin))
   320  			}
   321  			close(results)
   322  		}()
   323  		// Feed all the blocks both into the tracer, as well as fast process concurrently
   324  		for number = start.NumberU64(); number < end.NumberU64(); number++ {
   325  			// Stop tracing if interruption was requested
   326  			select {
   327  			case <-notifier.Closed():
   328  				return
   329  			default:
   330  			}
   331  			// clean out any derefs
   332  			derefsMu.Lock()
   333  			for _, h := range derefTodo {
   334  				statedb.Database().TrieDB().Dereference(h)
   335  			}
   336  			derefTodo = derefTodo[:0]
   337  			derefsMu.Unlock()
   338  
   339  			// Print progress logs if long enough time elapsed
   340  			if time.Since(logged) > 8*time.Second {
   341  				logged = time.Now()
   342  				log.Info("Tracing chain segment", "start", start.NumberU64(), "end", end.NumberU64(), "current", number, "transactions", traced, "elapsed", time.Since(begin))
   343  			}
   344  			// Retrieve the parent state to trace on top
   345  			block, err := api.blockByNumber(localctx, rpc.BlockNumber(number))
   346  			if err != nil {
   347  				failed = err
   348  				break
   349  			}
   350  			// Prepare the statedb for tracing. Don't use the live database for
   351  			// tracing to avoid persisting state junks into the database.
   352  			statedb, err = api.backend.StateAtBlock(localctx, block, reexec, statedb, false)
   353  			if err != nil {
   354  				failed = err
   355  				break
   356  			}
   357  			if statedb.Database().TrieDB() != nil {
   358  				// Hold the reference for tracer, will be released at the final stage
   359  				statedb.Database().TrieDB().Reference(block.Root(), common.Hash{})
   360  
   361  				// Release the parent state because it's already held by the tracer
   362  				if parent != (common.Hash{}) {
   363  					statedb.Database().TrieDB().Dereference(parent)
   364  				}
   365  			}
   366  			parent = block.Root()
   367  
   368  			next, err := api.blockByNumber(localctx, rpc.BlockNumber(number+1))
   369  			if err != nil {
   370  				failed = err
   371  				break
   372  			}
   373  			// Send the block over to the concurrent tracers (if not in the fast-forward phase)
   374  			txs := next.Transactions()
   375  			select {
   376  			case tasks <- &blockTraceTask{statedb: statedb.Copy(), block: next, rootref: block.Root(), results: make([]*txTraceResult, len(txs))}:
   377  			case <-notifier.Closed():
   378  				return
   379  			}
   380  			traced += uint64(len(txs))
   381  		}
   382  	}()
   383  
   384  	// Keep reading the trace results and stream the to the user
   385  	go func() {
   386  		var (
   387  			done = make(map[uint64]*blockTraceResult)
   388  			next = start.NumberU64() + 1
   389  		)
   390  		for res := range results {
   391  			// Queue up next received result
   392  			result := &blockTraceResult{
   393  				Block:  hexutil.Uint64(res.block.NumberU64()),
   394  				Hash:   res.block.Hash(),
   395  				Traces: res.results,
   396  			}
   397  			// Schedule any parent tries held in memory by this task for dereferencing
   398  			done[uint64(result.Block)] = result
   399  			derefsMu.Lock()
   400  			derefTodo = append(derefTodo, res.rootref)
   401  			derefsMu.Unlock()
   402  			// Stream completed traces to the user, aborting on the first error
   403  			for result, ok := done[next]; ok; result, ok = done[next] {
   404  				if len(result.Traces) > 0 || next == end.NumberU64() {
   405  					notifier.Notify(sub.ID, result)
   406  				}
   407  				delete(done, next)
   408  				next++
   409  			}
   410  		}
   411  	}()
   412  	return sub, nil
   413  }
   414  
   415  // TraceBlockByNumber returns the structured logs created during the execution of
   416  // EVM and returns them as a JSON object.
   417  func (api *API) TraceBlockByNumber(ctx context.Context, number rpc.BlockNumber, config *TraceConfig) ([]*txTraceResult, error) {
   418  	block, err := api.blockByNumber(ctx, number)
   419  	if err != nil {
   420  		return nil, err
   421  	}
   422  	return api.traceBlock(ctx, block, config)
   423  }
   424  
   425  // TraceBlockByHash returns the structured logs created during the execution of
   426  // EVM and returns them as a JSON object.
   427  func (api *API) TraceBlockByHash(ctx context.Context, hash common.Hash, config *TraceConfig) ([]*txTraceResult, error) {
   428  	block, err := api.blockByHash(ctx, hash)
   429  	if err != nil {
   430  		return nil, err
   431  	}
   432  	return api.traceBlock(ctx, block, config)
   433  }
   434  
   435  // TraceBlock returns the structured logs created during the execution of EVM
   436  // and returns them as a JSON object.
   437  func (api *API) TraceBlock(ctx context.Context, blob []byte, config *TraceConfig) ([]*txTraceResult, error) {
   438  	block := new(types.Block)
   439  	if err := rlp.Decode(bytes.NewReader(blob), block); err != nil {
   440  		return nil, fmt.Errorf("could not decode block: %v", err)
   441  	}
   442  	return api.traceBlock(ctx, block, config)
   443  }
   444  
   445  // TraceBlockFromFile returns the structured logs created during the execution of
   446  // EVM and returns them as a JSON object.
   447  func (api *API) TraceBlockFromFile(ctx context.Context, file string, config *TraceConfig) ([]*txTraceResult, error) {
   448  	blob, err := ioutil.ReadFile(file)
   449  	if err != nil {
   450  		return nil, fmt.Errorf("could not read file: %v", err)
   451  	}
   452  	return api.TraceBlock(ctx, blob, config)
   453  }
   454  
   455  // TraceBadBlock returns the structured logs created during the execution of
   456  // EVM against a block pulled from the pool of bad ones and returns them as a JSON
   457  // object.
   458  func (api *API) TraceBadBlock(ctx context.Context, hash common.Hash, config *TraceConfig) ([]*txTraceResult, error) {
   459  	block := rawdb.ReadBadBlock(api.backend.ChainDb(), hash)
   460  	if block == nil {
   461  		return nil, fmt.Errorf("bad block %#x not found", hash)
   462  	}
   463  	return api.traceBlock(ctx, block, config)
   464  }
   465  
   466  // StandardTraceBlockToFile dumps the structured logs created during the
   467  // execution of EVM to the local file system and returns a list of files
   468  // to the caller.
   469  func (api *API) StandardTraceBlockToFile(ctx context.Context, hash common.Hash, config *StdTraceConfig) ([]string, error) {
   470  	block, err := api.blockByHash(ctx, hash)
   471  	if err != nil {
   472  		return nil, err
   473  	}
   474  	return api.standardTraceBlockToFile(ctx, block, config)
   475  }
   476  
   477  // IntermediateRoots executes a block (bad- or canon- or side-), and returns a list
   478  // of intermediate roots: the stateroot after each transaction.
   479  func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config *TraceConfig) ([]common.Hash, error) {
   480  	block, _ := api.blockByHash(ctx, hash)
   481  	if block == nil {
   482  		// Check in the bad blocks
   483  		block = rawdb.ReadBadBlock(api.backend.ChainDb(), hash)
   484  	}
   485  	if block == nil {
   486  		return nil, fmt.Errorf("block %#x not found", hash)
   487  	}
   488  	if block.NumberU64() == 0 {
   489  		return nil, errors.New("genesis is not traceable")
   490  	}
   491  	parent, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(block.NumberU64()-1), block.ParentHash())
   492  	if err != nil {
   493  		return nil, err
   494  	}
   495  	reexec := defaultTraceReexec
   496  	if config != nil && config.Reexec != nil {
   497  		reexec = *config.Reexec
   498  	}
   499  	statedb, err := api.backend.StateAtBlock(ctx, parent, reexec, nil, true)
   500  	if err != nil {
   501  		return nil, err
   502  	}
   503  	var (
   504  		roots              []common.Hash
   505  		signer             = types.MakeSigner(api.backend.ChainConfig(), block.Number())
   506  		chainConfig        = api.backend.ChainConfig()
   507  		vmctx              = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
   508  		deleteEmptyObjects = chainConfig.IsEIP158(block.Number())
   509  	)
   510  	for i, tx := range block.Transactions() {
   511  		var (
   512  			msg, _    = tx.AsMessage(signer, block.BaseFee())
   513  			txContext = core.NewEVMTxContext(msg)
   514  			vmenv     = vm.NewEVM(vmctx, txContext, statedb, chainConfig, vm.Config{})
   515  		)
   516  		statedb.Prepare(tx.Hash(), i)
   517  		if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil {
   518  			log.Warn("Tracing intermediate roots did not complete", "txindex", i, "txhash", tx.Hash(), "err", err)
   519  			// We intentionally don't return the error here: if we do, then the RPC server will not
   520  			// return the roots. Most likely, the caller already knows that a certain transaction fails to
   521  			// be included, but still want the intermediate roots that led to that point.
   522  			// It may happen the tx_N causes an erroneous state, which in turn causes tx_N+M to not be
   523  			// executable.
   524  			// N.B: This should never happen while tracing canon blocks, only when tracing bad blocks.
   525  			return roots, nil
   526  		}
   527  		// calling IntermediateRoot will internally call Finalize on the state
   528  		// so any modifications are written to the trie
   529  		roots = append(roots, statedb.IntermediateRoot(deleteEmptyObjects))
   530  	}
   531  	return roots, nil
   532  }
   533  
   534  // StandardTraceBadBlockToFile dumps the structured logs created during the
   535  // execution of EVM against a block pulled from the pool of bad ones to the
   536  // local file system and returns a list of files to the caller.
   537  func (api *API) StandardTraceBadBlockToFile(ctx context.Context, hash common.Hash, config *StdTraceConfig) ([]string, error) {
   538  	block := rawdb.ReadBadBlock(api.backend.ChainDb(), hash)
   539  	if block == nil {
   540  		return nil, fmt.Errorf("bad block %#x not found", hash)
   541  	}
   542  	return api.standardTraceBlockToFile(ctx, block, config)
   543  }
   544  
   545  // traceBlock configures a new tracer according to the provided configuration, and
   546  // executes all the transactions contained within. The return value will be one item
   547  // per transaction, dependent on the requestd tracer.
   548  func (api *API) traceBlock(ctx context.Context, block *types.Block, config *TraceConfig) ([]*txTraceResult, error) {
   549  	if block.NumberU64() == 0 {
   550  		return nil, errors.New("genesis is not traceable")
   551  	}
   552  	parent, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(block.NumberU64()-1), block.ParentHash())
   553  	if err != nil {
   554  		return nil, err
   555  	}
   556  	reexec := defaultTraceReexec
   557  	if config != nil && config.Reexec != nil {
   558  		reexec = *config.Reexec
   559  	}
   560  	statedb, err := api.backend.StateAtBlock(ctx, parent, reexec, nil, true)
   561  	if err != nil {
   562  		return nil, err
   563  	}
   564  	// Execute all the transaction contained within the block concurrently
   565  	var (
   566  		signer  = types.MakeSigner(api.backend.ChainConfig(), block.Number())
   567  		txs     = block.Transactions()
   568  		results = make([]*txTraceResult, len(txs))
   569  
   570  		pend = new(sync.WaitGroup)
   571  		jobs = make(chan *txTraceTask, len(txs))
   572  	)
   573  	threads := runtime.NumCPU()
   574  	if threads > len(txs) {
   575  		threads = len(txs)
   576  	}
   577  	blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
   578  	blockHash := block.Hash()
   579  	for th := 0; th < threads; th++ {
   580  		pend.Add(1)
   581  		go func() {
   582  			defer pend.Done()
   583  			// Fetch and execute the next transaction trace tasks
   584  			for task := range jobs {
   585  				msg, _ := txs[task.index].AsMessage(signer, block.BaseFee())
   586  				txctx := &Context{
   587  					BlockHash: blockHash,
   588  					TxIndex:   task.index,
   589  					TxHash:    txs[task.index].Hash(),
   590  				}
   591  				res, err := api.traceTx(ctx, msg, txctx, blockCtx, task.statedb, config)
   592  				if err != nil {
   593  					results[task.index] = &txTraceResult{Error: err.Error()}
   594  					continue
   595  				}
   596  				results[task.index] = &txTraceResult{Result: res}
   597  			}
   598  		}()
   599  	}
   600  	// Feed the transactions into the tracers and return
   601  	var failed error
   602  	for i, tx := range txs {
   603  		// Send the trace task over for execution
   604  		jobs <- &txTraceTask{statedb: statedb.Copy(), index: i}
   605  
   606  		// Generate the next state snapshot fast without tracing
   607  		msg, _ := tx.AsMessage(signer, block.BaseFee())
   608  		statedb.Prepare(tx.Hash(), i)
   609  		vmenv := vm.NewEVM(blockCtx, core.NewEVMTxContext(msg), statedb, api.backend.ChainConfig(), vm.Config{})
   610  		if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil {
   611  			failed = err
   612  			break
   613  		}
   614  		// Finalize the state so any modifications are written to the trie
   615  		// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
   616  		statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number()))
   617  	}
   618  	close(jobs)
   619  	pend.Wait()
   620  
   621  	// If execution failed in between, abort
   622  	if failed != nil {
   623  		return nil, failed
   624  	}
   625  	return results, nil
   626  }
   627  
   628  // standardTraceBlockToFile configures a new tracer which uses standard JSON output,
   629  // and traces either a full block or an individual transaction. The return value will
   630  // be one filename per transaction traced.
   631  func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block, config *StdTraceConfig) ([]string, error) {
   632  	// If we're tracing a single transaction, make sure it's present
   633  	if config != nil && config.TxHash != (common.Hash{}) {
   634  		if !containsTx(block, config.TxHash) {
   635  			return nil, fmt.Errorf("transaction %#x not found in block", config.TxHash)
   636  		}
   637  	}
   638  	if block.NumberU64() == 0 {
   639  		return nil, errors.New("genesis is not traceable")
   640  	}
   641  	parent, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(block.NumberU64()-1), block.ParentHash())
   642  	if err != nil {
   643  		return nil, err
   644  	}
   645  	reexec := defaultTraceReexec
   646  	if config != nil && config.Reexec != nil {
   647  		reexec = *config.Reexec
   648  	}
   649  	statedb, err := api.backend.StateAtBlock(ctx, parent, reexec, nil, true)
   650  	if err != nil {
   651  		return nil, err
   652  	}
   653  	// Retrieve the tracing configurations, or use default values
   654  	var (
   655  		logConfig vm.LogConfig
   656  		txHash    common.Hash
   657  	)
   658  	if config != nil {
   659  		logConfig = config.LogConfig
   660  		txHash = config.TxHash
   661  	}
   662  	logConfig.Debug = true
   663  
   664  	// Execute transaction, either tracing all or just the requested one
   665  	var (
   666  		dumps       []string
   667  		signer      = types.MakeSigner(api.backend.ChainConfig(), block.Number())
   668  		chainConfig = api.backend.ChainConfig()
   669  		vmctx       = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
   670  		canon       = true
   671  	)
   672  	// Check if there are any overrides: the caller may wish to enable a future
   673  	// fork when executing this block. Note, such overrides are only applicable to the
   674  	// actual specified block, not any preceding blocks that we have to go through
   675  	// in order to obtain the state.
   676  	// Therefore, it's perfectly valid to specify `"futureForkBlock": 0`, to enable `futureFork`
   677  
   678  	if config != nil && config.Overrides != nil {
   679  		// Copy the config, to not screw up the main config
   680  		// Note: the Clique-part is _not_ deep copied
   681  		chainConfigCopy := new(params.ChainConfig)
   682  		*chainConfigCopy = *chainConfig
   683  		chainConfig = chainConfigCopy
   684  		if berlin := config.LogConfig.Overrides.BerlinBlock; berlin != nil {
   685  			chainConfig.BerlinBlock = berlin
   686  			canon = false
   687  		}
   688  	}
   689  	for i, tx := range block.Transactions() {
   690  		// Prepare the trasaction for un-traced execution
   691  		var (
   692  			msg, _    = tx.AsMessage(signer, block.BaseFee())
   693  			txContext = core.NewEVMTxContext(msg)
   694  			vmConf    vm.Config
   695  			dump      *os.File
   696  			writer    *bufio.Writer
   697  			err       error
   698  		)
   699  		// If the transaction needs tracing, swap out the configs
   700  		if tx.Hash() == txHash || txHash == (common.Hash{}) {
   701  			// Generate a unique temporary file to dump it into
   702  			prefix := fmt.Sprintf("block_%#x-%d-%#x-", block.Hash().Bytes()[:4], i, tx.Hash().Bytes()[:4])
   703  			if !canon {
   704  				prefix = fmt.Sprintf("%valt-", prefix)
   705  			}
   706  			dump, err = ioutil.TempFile(os.TempDir(), prefix)
   707  			if err != nil {
   708  				return nil, err
   709  			}
   710  			dumps = append(dumps, dump.Name())
   711  
   712  			// Swap out the noop logger to the standard tracer
   713  			writer = bufio.NewWriter(dump)
   714  			vmConf = vm.Config{
   715  				Debug:                   true,
   716  				Tracer:                  vm.NewJSONLogger(&logConfig, writer),
   717  				EnablePreimageRecording: true,
   718  			}
   719  		}
   720  		// Execute the transaction and flush any traces to disk
   721  		vmenv := vm.NewEVM(vmctx, txContext, statedb, chainConfig, vmConf)
   722  		statedb.Prepare(tx.Hash(), i)
   723  		_, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()))
   724  		if writer != nil {
   725  			writer.Flush()
   726  		}
   727  		if dump != nil {
   728  			dump.Close()
   729  			log.Info("Wrote standard trace", "file", dump.Name())
   730  		}
   731  		if err != nil {
   732  			return dumps, err
   733  		}
   734  		// Finalize the state so any modifications are written to the trie
   735  		// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
   736  		statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number()))
   737  
   738  		// If we've traced the transaction we were looking for, abort
   739  		if tx.Hash() == txHash {
   740  			break
   741  		}
   742  	}
   743  	return dumps, nil
   744  }
   745  
   746  // containsTx reports whether the transaction with a certain hash
   747  // is contained within the specified block.
   748  func containsTx(block *types.Block, hash common.Hash) bool {
   749  	for _, tx := range block.Transactions() {
   750  		if tx.Hash() == hash {
   751  			return true
   752  		}
   753  	}
   754  	return false
   755  }
   756  
   757  // TraceTransaction returns the structured logs created during the execution of EVM
   758  // and returns them as a JSON object.
   759  func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config *TraceConfig) (interface{}, error) {
   760  	tx, blockHash, blockNumber, index, err := api.backend.GetTransaction(ctx, hash)
   761  	if tx == nil {
   762  		// For BorTransaction, there will be no trace available
   763  		tx, _, _, _ = rawdb.ReadBorTransaction(api.backend.ChainDb(), hash)
   764  		if tx != nil {
   765  			return &ethapi.ExecutionResult{
   766  				StructLogs: make([]ethapi.StructLogRes, 0),
   767  			}, nil
   768  		}
   769  	}
   770  	if err != nil {
   771  		return nil, err
   772  	}
   773  
   774  	// It shouldn't happen in practice.
   775  	if blockNumber == 0 {
   776  		return nil, errors.New("genesis is not traceable")
   777  	}
   778  	reexec := defaultTraceReexec
   779  	if config != nil && config.Reexec != nil {
   780  		reexec = *config.Reexec
   781  	}
   782  	block, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(blockNumber), blockHash)
   783  	if err != nil {
   784  		return nil, err
   785  	}
   786  	msg, vmctx, statedb, err := api.backend.StateAtTransaction(ctx, block, int(index), reexec)
   787  	if err != nil {
   788  		return nil, err
   789  	}
   790  	txctx := &Context{
   791  		BlockHash: blockHash,
   792  		TxIndex:   int(index),
   793  		TxHash:    hash,
   794  	}
   795  	return api.traceTx(ctx, msg, txctx, vmctx, statedb, config)
   796  }
   797  
   798  // TraceCall lets you trace a given eth_call. It collects the structured logs
   799  // created during the execution of EVM if the given transaction was added on
   800  // top of the provided block and returns them as a JSON object.
   801  // You can provide -2 as a block number to trace on top of the pending block.
   802  func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, config *TraceCallConfig) (interface{}, error) {
   803  	// Try to retrieve the specified block
   804  	var (
   805  		err   error
   806  		block *types.Block
   807  	)
   808  	if hash, ok := blockNrOrHash.Hash(); ok {
   809  		block, err = api.blockByHash(ctx, hash)
   810  	} else if number, ok := blockNrOrHash.Number(); ok {
   811  		block, err = api.blockByNumber(ctx, number)
   812  	} else {
   813  		return nil, errors.New("invalid arguments; neither block nor hash specified")
   814  	}
   815  	if err != nil {
   816  		return nil, err
   817  	}
   818  	// try to recompute the state
   819  	reexec := defaultTraceReexec
   820  	if config != nil && config.Reexec != nil {
   821  		reexec = *config.Reexec
   822  	}
   823  	statedb, err := api.backend.StateAtBlock(ctx, block, reexec, nil, true)
   824  	if err != nil {
   825  		return nil, err
   826  	}
   827  	// Apply the customized state rules if required.
   828  	if config != nil {
   829  		if err := config.StateOverrides.Apply(statedb); err != nil {
   830  			return nil, err
   831  		}
   832  	}
   833  	// Execute the trace
   834  	msg, err := args.ToMessage(api.backend.RPCGasCap(), block.BaseFee())
   835  	if err != nil {
   836  		return nil, err
   837  	}
   838  	vmctx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
   839  
   840  	var traceConfig *TraceConfig
   841  	if config != nil {
   842  		traceConfig = &TraceConfig{
   843  			LogConfig: config.LogConfig,
   844  			Tracer:    config.Tracer,
   845  			Timeout:   config.Timeout,
   846  			Reexec:    config.Reexec,
   847  		}
   848  	}
   849  	return api.traceTx(ctx, msg, new(Context), vmctx, statedb, traceConfig)
   850  }
   851  
   852  // traceTx configures a new tracer according to the provided configuration, and
   853  // executes the given message in the provided environment. The return value will
   854  // be tracer dependent.
   855  func (api *API) traceTx(ctx context.Context, message core.Message, txctx *Context, vmctx vm.BlockContext, statedb *state.StateDB, config *TraceConfig) (interface{}, error) {
   856  	// Assemble the structured logger or the JavaScript tracer
   857  	var (
   858  		tracer    vm.Tracer
   859  		err       error
   860  		txContext = core.NewEVMTxContext(message)
   861  	)
   862  	switch {
   863  	case config != nil && config.Tracer != nil:
   864  		// Define a meaningful timeout of a single transaction trace
   865  		timeout := defaultTraceTimeout
   866  		if config.Timeout != nil {
   867  			if timeout, err = time.ParseDuration(*config.Timeout); err != nil {
   868  				return nil, err
   869  			}
   870  		}
   871  		// Construct the JavaScript tracer to execute with
   872  		if tracer, err = New(*config.Tracer, txctx); err != nil {
   873  			return nil, err
   874  		}
   875  		// Handle timeouts and RPC cancellations
   876  		deadlineCtx, cancel := context.WithTimeout(ctx, timeout)
   877  		go func() {
   878  			<-deadlineCtx.Done()
   879  			if deadlineCtx.Err() == context.DeadlineExceeded {
   880  				tracer.(*Tracer).Stop(errors.New("execution timeout"))
   881  			}
   882  		}()
   883  		defer cancel()
   884  
   885  	case config == nil:
   886  		tracer = vm.NewStructLogger(nil)
   887  
   888  	default:
   889  		tracer = vm.NewStructLogger(config.LogConfig)
   890  	}
   891  	// Run the transaction with tracing enabled.
   892  	vmenv := vm.NewEVM(vmctx, txContext, statedb, api.backend.ChainConfig(), vm.Config{Debug: true, Tracer: tracer, NoBaseFee: true})
   893  
   894  	// Call Prepare to clear out the statedb access list
   895  	statedb.Prepare(txctx.TxHash, txctx.TxIndex)
   896  
   897  	result, err := core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas()))
   898  	if err != nil {
   899  		return nil, fmt.Errorf("tracing failed: %w", err)
   900  	}
   901  
   902  	// Depending on the tracer type, format and return the output.
   903  	switch tracer := tracer.(type) {
   904  	case *vm.StructLogger:
   905  		// If the result contains a revert reason, return it.
   906  		returnVal := fmt.Sprintf("%x", result.Return())
   907  		if len(result.Revert()) > 0 {
   908  			returnVal = fmt.Sprintf("%x", result.Revert())
   909  		}
   910  		return &ethapi.ExecutionResult{
   911  			Gas:         result.UsedGas,
   912  			Failed:      result.Failed(),
   913  			ReturnValue: returnVal,
   914  			StructLogs:  ethapi.FormatLogs(tracer.StructLogs()),
   915  		}, nil
   916  
   917  	case *Tracer:
   918  		return tracer.GetResult()
   919  
   920  	default:
   921  		panic(fmt.Sprintf("bad tracer type %T", tracer))
   922  	}
   923  }
   924  
   925  // APIs return the collection of RPC services the tracer package offers.
   926  func APIs(backend Backend) []rpc.API {
   927  	// Append all the local APIs and return
   928  	return []rpc.API{
   929  		{
   930  			Namespace: "debug",
   931  			Version:   "1.0",
   932  			Service:   NewAPI(backend),
   933  			Public:    false,
   934  		},
   935  	}
   936  }