github.com/MetalBlockchain/subnet-evm@v0.4.9/eth/tracers/api.go (about)

     1  // (c) 2019-2020, Ava Labs, Inc.
     2  //
     3  // This file is a derived work, based on the go-ethereum library whose original
     4  // notices appear below.
     5  //
     6  // It is distributed under a license compatible with the licensing terms of the
     7  // original code from which it is derived.
     8  //
     9  // Much love to the original authors for their work.
    10  // **********
    11  // Copyright 2021 The go-ethereum Authors
    12  // This file is part of the go-ethereum library.
    13  //
    14  // The go-ethereum library is free software: you can redistribute it and/or modify
    15  // it under the terms of the GNU Lesser General Public License as published by
    16  // the Free Software Foundation, either version 3 of the License, or
    17  // (at your option) any later version.
    18  //
    19  // The go-ethereum library is distributed in the hope that it will be useful,
    20  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    21  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    22  // GNU Lesser General Public License for more details.
    23  //
    24  // You should have received a copy of the GNU Lesser General Public License
    25  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    26  
    27  package tracers
    28  
    29  import (
    30  	"bytes"
    31  	"context"
    32  	"encoding/json"
    33  	"errors"
    34  	"fmt"
    35  	"math/big"
    36  	"runtime"
    37  	"sync"
    38  	"time"
    39  
    40  	"github.com/MetalBlockchain/subnet-evm/consensus"
    41  	"github.com/MetalBlockchain/subnet-evm/core"
    42  	"github.com/MetalBlockchain/subnet-evm/core/state"
    43  	"github.com/MetalBlockchain/subnet-evm/core/types"
    44  	"github.com/MetalBlockchain/subnet-evm/core/vm"
    45  	"github.com/MetalBlockchain/subnet-evm/eth/tracers/logger"
    46  	"github.com/MetalBlockchain/subnet-evm/ethdb"
    47  	"github.com/MetalBlockchain/subnet-evm/internal/ethapi"
    48  	"github.com/MetalBlockchain/subnet-evm/params"
    49  	"github.com/MetalBlockchain/subnet-evm/rpc"
    50  	"github.com/ethereum/go-ethereum/common"
    51  	"github.com/ethereum/go-ethereum/common/hexutil"
    52  	"github.com/ethereum/go-ethereum/log"
    53  	"github.com/ethereum/go-ethereum/rlp"
    54  )
    55  
    56  const (
    57  	// defaultTraceTimeout is the amount of time a single transaction can execute
    58  	// by default before being forcefully aborted.
    59  	defaultTraceTimeout = 5 * time.Second
    60  
    61  	// defaultTraceReexec is the number of blocks the tracer is willing to go back
    62  	// and reexecute to produce missing historical state necessary to run a specific
    63  	// trace.
    64  	defaultTraceReexec = uint64(128)
    65  
    66  	// defaultTracechainMemLimit is the size of the triedb, at which traceChain
    67  	// switches over and tries to use a disk-backed database instead of building
    68  	// on top of memory.
    69  	// For non-archive nodes, this limit _will_ be overblown, as disk-backed tries
    70  	// will only be found every ~15K blocks or so.
    71  	defaultTracechainMemLimit = common.StorageSize(500 * 1024 * 1024)
    72  )
    73  
    74  // Backend interface provides the common API services (that are provided by
    75  // both full and light clients) with access to necessary functions.
    76  type Backend interface {
    77  	HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error)
    78  	HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error)
    79  	BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error)
    80  	BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error)
    81  	BadBlocks() ([]*types.Block, []*core.BadBlockReason)
    82  	GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error)
    83  	RPCGasCap() uint64
    84  	ChainConfig() *params.ChainConfig
    85  	Engine() consensus.Engine
    86  	ChainDb() ethdb.Database
    87  	StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, checkLive bool, preferDisk bool) (*state.StateDB, error)
    88  	StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, error)
    89  }
    90  
    91  // API is the collection of tracing APIs exposed over the private debugging endpoint.
    92  type API struct {
    93  	backend Backend
    94  }
    95  
    96  // NewAPI creates a new API definition for the tracing methods of the Ethereum service.
    97  func NewAPI(backend Backend) *API {
    98  	return &API{backend: backend}
    99  }
   100  
   101  type chainContext struct {
   102  	api *API
   103  	ctx context.Context
   104  }
   105  
   106  func (context *chainContext) Engine() consensus.Engine {
   107  	return context.api.backend.Engine()
   108  }
   109  
   110  func (context *chainContext) GetHeader(hash common.Hash, number uint64) *types.Header {
   111  	header, err := context.api.backend.HeaderByNumber(context.ctx, rpc.BlockNumber(number))
   112  	if err != nil {
   113  		return nil
   114  	}
   115  	if header.Hash() == hash {
   116  		return header
   117  	}
   118  	header, err = context.api.backend.HeaderByHash(context.ctx, hash)
   119  	if err != nil {
   120  		return nil
   121  	}
   122  	return header
   123  }
   124  
   125  // chainContext constructs the context reader which is used by the evm for reading
   126  // the necessary chain context.
   127  func (api *API) chainContext(ctx context.Context) core.ChainContext {
   128  	return &chainContext{api: api, ctx: ctx}
   129  }
   130  
   131  // blockByNumber is the wrapper of the chain access function offered by the backend.
   132  // It will return an error if the block is not found.
   133  func (api *API) blockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) {
   134  	block, err := api.backend.BlockByNumber(ctx, number)
   135  	if err != nil {
   136  		return nil, err
   137  	}
   138  	if block == nil {
   139  		return nil, fmt.Errorf("block #%d not found", number)
   140  	}
   141  	return block, nil
   142  }
   143  
   144  // blockByHash is the wrapper of the chain access function offered by the backend.
   145  // It will return an error if the block is not found.
   146  func (api *API) blockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) {
   147  	block, err := api.backend.BlockByHash(ctx, hash)
   148  	if err != nil {
   149  		return nil, err
   150  	}
   151  	if block == nil {
   152  		return nil, fmt.Errorf("block %s not found", hash.Hex())
   153  	}
   154  	return block, nil
   155  }
   156  
   157  // blockByNumberAndHash is the wrapper of the chain access function offered by
   158  // the backend. It will return an error if the block is not found.
   159  //
   160  // Note this function is friendly for the light client which can only retrieve the
   161  // historical(before the CHT) header/block by number.
   162  func (api *API) blockByNumberAndHash(ctx context.Context, number rpc.BlockNumber, hash common.Hash) (*types.Block, error) {
   163  	block, err := api.blockByNumber(ctx, number)
   164  	if err != nil {
   165  		return nil, err
   166  	}
   167  	if block.Hash() == hash {
   168  		return block, nil
   169  	}
   170  	return api.blockByHash(ctx, hash)
   171  }
   172  
   173  // TraceConfig holds extra parameters to trace functions.
   174  type TraceConfig struct {
   175  	*logger.Config
   176  	Tracer  *string
   177  	Timeout *string
   178  	Reexec  *uint64
   179  	// Config specific to given tracer. Note struct logger
   180  	// config are historically embedded in main object.
   181  	TracerConfig json.RawMessage
   182  }
   183  
   184  // TraceCallConfig is the config for traceCall API. It holds one more
   185  // field to override the state for tracing.
   186  type TraceCallConfig struct {
   187  	TraceConfig
   188  	StateOverrides *ethapi.StateOverride
   189  	BlockOverrides *ethapi.BlockOverrides
   190  }
   191  
   192  // StdTraceConfig holds extra parameters to standard-json trace functions.
   193  type StdTraceConfig struct {
   194  	logger.Config
   195  	Reexec *uint64
   196  	TxHash common.Hash
   197  }
   198  
   199  // txTraceResult is the result of a single transaction trace.
   200  type txTraceResult struct {
   201  	Result interface{} `json:"result,omitempty"` // Trace results produced by the tracer
   202  	Error  string      `json:"error,omitempty"`  // Trace failure produced by the tracer
   203  }
   204  
   205  func (t *txTraceResult) String() string {
   206  	return fmt.Sprintf("result: %s, error: %s", t.Result, t.Error)
   207  }
   208  
   209  // blockTraceTask represents a single block trace task when an entire chain is
   210  // being traced.
   211  type blockTraceTask struct {
   212  	statedb *state.StateDB   // Intermediate state prepped for tracing
   213  	block   *types.Block     // Block to trace the transactions from
   214  	rootref common.Hash      // Trie root reference held for this task
   215  	results []*txTraceResult // Trace results procudes by the task
   216  }
   217  
   218  // blockTraceResult represets the results of tracing a single block when an entire
   219  // chain is being traced.
   220  type blockTraceResult struct {
   221  	Block  hexutil.Uint64   `json:"block"`  // Block number corresponding to this trace
   222  	Hash   common.Hash      `json:"hash"`   // Block hash corresponding to this trace
   223  	Traces []*txTraceResult `json:"traces"` // Trace results produced by the task
   224  }
   225  
   226  // txTraceTask represents a single transaction trace task when an entire block
   227  // is being traced.
   228  type txTraceTask struct {
   229  	statedb *state.StateDB // Intermediate state prepped for tracing
   230  	index   int            // Transaction offset in the block
   231  }
   232  
   233  // TraceChain returns the structured logs created during the execution of EVM
   234  // between two blocks (excluding start) and returns them as a JSON object.
   235  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
   236  	from, err := api.blockByNumber(ctx, start)
   237  	if err != nil {
   238  		return nil, err
   239  	}
   240  	to, err := api.blockByNumber(ctx, end)
   241  	if err != nil {
   242  		return nil, err
   243  	}
   244  	if from.Number().Cmp(to.Number()) >= 0 {
   245  		return nil, fmt.Errorf("end block (#%d) needs to come after start block (#%d)", end, start)
   246  	}
   247  	return api.traceChain(ctx, from, to, config)
   248  }
   249  
   250  // traceChain configures a new tracer according to the provided configuration, and
   251  // executes all the transactions contained within. The return value will be one item
   252  // per transaction, dependent on the requested tracer.
   253  func (api *API) traceChain(ctx context.Context, start, end *types.Block, config *TraceConfig) (*rpc.Subscription, error) {
   254  	// Tracing a chain is a **long** operation, only do with subscriptions
   255  	notifier, supported := rpc.NotifierFromContext(ctx)
   256  	if !supported {
   257  		return &rpc.Subscription{}, rpc.ErrNotificationsUnsupported
   258  	}
   259  	sub := notifier.CreateSubscription()
   260  
   261  	// Prepare all the states for tracing. Note this procedure can take very
   262  	// long time. Timeout mechanism is necessary.
   263  	reexec := defaultTraceReexec
   264  	if config != nil && config.Reexec != nil {
   265  		reexec = *config.Reexec
   266  	}
   267  	blocks := int(end.NumberU64() - start.NumberU64())
   268  	threads := runtime.NumCPU()
   269  	if threads > blocks {
   270  		threads = blocks
   271  	}
   272  	var (
   273  		pend     = new(sync.WaitGroup)
   274  		tasks    = make(chan *blockTraceTask, threads)
   275  		results  = make(chan *blockTraceTask, threads)
   276  		localctx = context.Background()
   277  	)
   278  	for th := 0; th < threads; th++ {
   279  		pend.Add(1)
   280  		go func() {
   281  			defer pend.Done()
   282  
   283  			// Fetch and execute the next block trace tasks
   284  			for task := range tasks {
   285  				signer := types.MakeSigner(api.backend.ChainConfig(), task.block.Number(), new(big.Int).SetUint64(task.block.Time()))
   286  				blockCtx := core.NewEVMBlockContext(task.block.Header(), api.chainContext(localctx), nil)
   287  				// Trace all the transactions contained within
   288  				for i, tx := range task.block.Transactions() {
   289  					msg, _ := tx.AsMessage(signer, task.block.BaseFee())
   290  					txctx := &Context{
   291  						BlockHash: task.block.Hash(),
   292  						TxIndex:   i,
   293  						TxHash:    tx.Hash(),
   294  					}
   295  					res, err := api.traceTx(localctx, msg, txctx, blockCtx, task.statedb, config)
   296  					if err != nil {
   297  						task.results[i] = &txTraceResult{Error: err.Error()}
   298  						log.Warn("Tracing failed", "hash", tx.Hash(), "block", task.block.NumberU64(), "err", err)
   299  						break
   300  					}
   301  					// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
   302  					task.statedb.Finalise(api.backend.ChainConfig().IsEIP158(task.block.Number()))
   303  					task.results[i] = &txTraceResult{Result: res}
   304  				}
   305  				// Stream the result back to the user or abort on teardown
   306  				select {
   307  				case results <- task:
   308  				case <-notifier.Closed():
   309  					return
   310  				}
   311  			}
   312  		}()
   313  	}
   314  	// Start a goroutine to feed all the blocks into the tracers
   315  	var (
   316  		begin     = time.Now()
   317  		derefTodo []common.Hash // list of hashes to dereference from the db
   318  		derefsMu  sync.Mutex    // mutex for the derefs
   319  	)
   320  
   321  	go func() {
   322  		var (
   323  			logged  time.Time
   324  			number  uint64
   325  			traced  uint64
   326  			failed  error
   327  			parent  common.Hash
   328  			statedb *state.StateDB
   329  		)
   330  		// Ensure everything is properly cleaned up on any exit path
   331  		defer func() {
   332  			close(tasks)
   333  			pend.Wait()
   334  
   335  			switch {
   336  			case failed != nil:
   337  				log.Warn("Chain tracing failed", "start", start.NumberU64(), "end", end.NumberU64(), "transactions", traced, "elapsed", time.Since(begin), "err", failed)
   338  			case number < end.NumberU64():
   339  				log.Warn("Chain tracing aborted", "start", start.NumberU64(), "end", end.NumberU64(), "abort", number, "transactions", traced, "elapsed", time.Since(begin))
   340  			default:
   341  				log.Info("Chain tracing finished", "start", start.NumberU64(), "end", end.NumberU64(), "transactions", traced, "elapsed", time.Since(begin))
   342  			}
   343  			close(results)
   344  		}()
   345  		var preferDisk bool
   346  		// Feed all the blocks both into the tracer, as well as fast process concurrently
   347  		for number = start.NumberU64(); number < end.NumberU64(); number++ {
   348  			// Stop tracing if interruption was requested
   349  			select {
   350  			case <-notifier.Closed():
   351  				return
   352  			default:
   353  			}
   354  			// clean out any derefs
   355  			derefsMu.Lock()
   356  			for _, h := range derefTodo {
   357  				statedb.Database().TrieDB().Dereference(h)
   358  			}
   359  			derefTodo = derefTodo[:0]
   360  			derefsMu.Unlock()
   361  
   362  			// Print progress logs if long enough time elapsed
   363  			if time.Since(logged) > 8*time.Second {
   364  				logged = time.Now()
   365  				log.Info("Tracing chain segment", "start", start.NumberU64(), "end", end.NumberU64(), "current", number, "transactions", traced, "elapsed", time.Since(begin))
   366  			}
   367  			// Retrieve the parent state to trace on top
   368  			block, err := api.blockByNumber(localctx, rpc.BlockNumber(number))
   369  			if err != nil {
   370  				failed = err
   371  				break
   372  			}
   373  			// Prepare the statedb for tracing. Don't use the live database for
   374  			// tracing to avoid persisting state junks into the database.
   375  			statedb, err = api.backend.StateAtBlock(localctx, block, reexec, statedb, false, preferDisk)
   376  			if err != nil {
   377  				failed = err
   378  				break
   379  			}
   380  			if trieDb := statedb.Database().TrieDB(); trieDb != nil {
   381  				// Hold the reference for tracer, will be released at the final stage
   382  				trieDb.Reference(block.Root(), common.Hash{})
   383  
   384  				// Release the parent state because it's already held by the tracer
   385  				if parent != (common.Hash{}) {
   386  					trieDb.Dereference(parent)
   387  				}
   388  				// Prefer disk if the trie db memory grows too much
   389  				s1, s2 := trieDb.Size()
   390  				if !preferDisk && (s1+s2) > defaultTracechainMemLimit {
   391  					log.Info("Switching to prefer-disk mode for tracing", "size", s1+s2)
   392  					preferDisk = true
   393  				}
   394  			}
   395  			parent = block.Root()
   396  
   397  			next, err := api.blockByNumber(localctx, rpc.BlockNumber(number+1))
   398  			if err != nil {
   399  				failed = err
   400  				break
   401  			}
   402  			// Send the block over to the concurrent tracers (if not in the fast-forward phase)
   403  			txs := next.Transactions()
   404  			select {
   405  			case tasks <- &blockTraceTask{statedb: statedb.Copy(), block: next, rootref: block.Root(), results: make([]*txTraceResult, len(txs))}:
   406  			case <-notifier.Closed():
   407  				return
   408  			}
   409  			traced += uint64(len(txs))
   410  		}
   411  	}()
   412  
   413  	// Keep reading the trace results and stream the to the user
   414  	go func() {
   415  		var (
   416  			done = make(map[uint64]*blockTraceResult)
   417  			next = start.NumberU64() + 1
   418  		)
   419  		for res := range results {
   420  			// Queue up next received result
   421  			result := &blockTraceResult{
   422  				Block:  hexutil.Uint64(res.block.NumberU64()),
   423  				Hash:   res.block.Hash(),
   424  				Traces: res.results,
   425  			}
   426  			// Schedule any parent tries held in memory by this task for dereferencing
   427  			done[uint64(result.Block)] = result
   428  			derefsMu.Lock()
   429  			derefTodo = append(derefTodo, res.rootref)
   430  			derefsMu.Unlock()
   431  			// Stream completed traces to the user, aborting on the first error
   432  			for result, ok := done[next]; ok; result, ok = done[next] {
   433  				if len(result.Traces) > 0 || next == end.NumberU64() {
   434  					notifier.Notify(sub.ID, result)
   435  				}
   436  				delete(done, next)
   437  				next++
   438  			}
   439  		}
   440  	}()
   441  	return sub, nil
   442  }
   443  
   444  // TraceBlockByNumber returns the structured logs created during the execution of
   445  // EVM and returns them as a JSON object.
   446  func (api *API) TraceBlockByNumber(ctx context.Context, number rpc.BlockNumber, config *TraceConfig) ([]*txTraceResult, error) {
   447  	block, err := api.blockByNumber(ctx, number)
   448  	if err != nil {
   449  		return nil, err
   450  	}
   451  	return api.traceBlock(ctx, block, config)
   452  }
   453  
   454  // TraceBlockByHash returns the structured logs created during the execution of
   455  // EVM and returns them as a JSON object.
   456  func (api *API) TraceBlockByHash(ctx context.Context, hash common.Hash, config *TraceConfig) ([]*txTraceResult, error) {
   457  	block, err := api.blockByHash(ctx, hash)
   458  	if err != nil {
   459  		return nil, err
   460  	}
   461  	return api.traceBlock(ctx, block, config)
   462  }
   463  
   464  // TraceBlock returns the structured logs created during the execution of EVM
   465  // and returns them as a JSON object.
   466  func (api *API) TraceBlock(ctx context.Context, blob hexutil.Bytes, config *TraceConfig) ([]*txTraceResult, error) {
   467  	block := new(types.Block)
   468  	if err := rlp.Decode(bytes.NewReader(blob), block); err != nil {
   469  		return nil, fmt.Errorf("could not decode block: %v", err)
   470  	}
   471  	return api.traceBlock(ctx, block, config)
   472  }
   473  
   474  // TraceBadBlock returns the structured logs created during the execution of
   475  // EVM against a block pulled from the pool of bad ones and returns them as a JSON
   476  // object.
   477  func (api *API) TraceBadBlock(ctx context.Context, hash common.Hash, config *TraceConfig) ([]*txTraceResult, error) {
   478  	// Search for the bad block corresponding to [hash].
   479  	var (
   480  		badBlocks, _ = api.backend.BadBlocks()
   481  		block        *types.Block
   482  	)
   483  	for _, badBlock := range badBlocks {
   484  		if hash == block.Hash() {
   485  			block = badBlock
   486  			break
   487  		}
   488  	}
   489  	if block == nil {
   490  		return nil, fmt.Errorf("bad block %#x not found", hash)
   491  	}
   492  	return api.traceBlock(ctx, block, config)
   493  }
   494  
   495  // IntermediateRoots executes a block (bad- or canon- or side-), and returns a list
   496  // of intermediate roots: the stateroot after each transaction.
   497  func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config *TraceConfig) ([]common.Hash, error) {
   498  	block, _ := api.blockByHash(ctx, hash)
   499  	if block == nil {
   500  		return nil, fmt.Errorf("block %#x not found", hash)
   501  	}
   502  	if block.NumberU64() == 0 {
   503  		return nil, errors.New("genesis is not traceable")
   504  	}
   505  	parent, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(block.NumberU64()-1), block.ParentHash())
   506  	if err != nil {
   507  		return nil, err
   508  	}
   509  	reexec := defaultTraceReexec
   510  	if config != nil && config.Reexec != nil {
   511  		reexec = *config.Reexec
   512  	}
   513  	statedb, err := api.backend.StateAtBlock(ctx, parent, reexec, nil, true, false)
   514  	if err != nil {
   515  		return nil, err
   516  	}
   517  	var (
   518  		roots              []common.Hash
   519  		signer             = types.MakeSigner(api.backend.ChainConfig(), block.Number(), new(big.Int).SetUint64(block.Time()))
   520  		chainConfig        = api.backend.ChainConfig()
   521  		vmctx              = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
   522  		deleteEmptyObjects = chainConfig.IsEIP158(block.Number())
   523  	)
   524  	for i, tx := range block.Transactions() {
   525  		var (
   526  			msg, _    = tx.AsMessage(signer, block.BaseFee())
   527  			txContext = core.NewEVMTxContext(msg)
   528  			vmenv     = vm.NewEVM(vmctx, txContext, statedb, chainConfig, vm.Config{})
   529  		)
   530  		statedb.Prepare(tx.Hash(), i)
   531  		if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil {
   532  			log.Warn("Tracing intermediate roots did not complete", "txindex", i, "txhash", tx.Hash(), "err", err)
   533  			// We intentionally don't return the error here: if we do, then the RPC server will not
   534  			// return the roots. Most likely, the caller already knows that a certain transaction fails to
   535  			// be included, but still want the intermediate roots that led to that point.
   536  			// It may happen the tx_N causes an erroneous state, which in turn causes tx_N+M to not be
   537  			// executable.
   538  			// N.B: This should never happen while tracing canon blocks, only when tracing bad blocks.
   539  			return roots, nil
   540  		}
   541  		// calling IntermediateRoot will internally call Finalize on the state
   542  		// so any modifications are written to the trie
   543  		roots = append(roots, statedb.IntermediateRoot(deleteEmptyObjects))
   544  	}
   545  	return roots, nil
   546  }
   547  
   548  // traceBlock configures a new tracer according to the provided configuration, and
   549  // executes all the transactions contained within. The return value will be one item
   550  // per transaction, dependent on the requested tracer.
   551  func (api *API) traceBlock(ctx context.Context, block *types.Block, config *TraceConfig) ([]*txTraceResult, error) {
   552  	if block.NumberU64() == 0 {
   553  		return nil, errors.New("genesis is not traceable")
   554  	}
   555  	parent, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(block.NumberU64()-1), block.ParentHash())
   556  	if err != nil {
   557  		return nil, err
   558  	}
   559  	reexec := defaultTraceReexec
   560  	if config != nil && config.Reexec != nil {
   561  		reexec = *config.Reexec
   562  	}
   563  	statedb, err := api.backend.StateAtBlock(ctx, parent, reexec, nil, true, false)
   564  	if err != nil {
   565  		return nil, err
   566  	}
   567  	// Execute all the transaction contained within the block concurrently
   568  	var (
   569  		signer  = types.MakeSigner(api.backend.ChainConfig(), block.Number(), new(big.Int).SetUint64(block.Time()))
   570  		txs     = block.Transactions()
   571  		results = make([]*txTraceResult, len(txs))
   572  
   573  		pend = new(sync.WaitGroup)
   574  		jobs = make(chan *txTraceTask, len(txs))
   575  	)
   576  	threads := runtime.NumCPU()
   577  	if threads > len(txs) {
   578  		threads = len(txs)
   579  	}
   580  	blockHash := block.Hash()
   581  	for th := 0; th < threads; th++ {
   582  		pend.Add(1)
   583  		go func() {
   584  			defer pend.Done()
   585  
   586  			blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
   587  			// Fetch and execute the next transaction trace tasks
   588  			for task := range jobs {
   589  				msg, _ := txs[task.index].AsMessage(signer, block.BaseFee())
   590  				txctx := &Context{
   591  					BlockHash: blockHash,
   592  					TxIndex:   task.index,
   593  					TxHash:    txs[task.index].Hash(),
   594  				}
   595  				res, err := api.traceTx(ctx, msg, txctx, blockCtx, task.statedb, config)
   596  				if err != nil {
   597  					results[task.index] = &txTraceResult{Error: err.Error()}
   598  					continue
   599  				}
   600  				results[task.index] = &txTraceResult{Result: res}
   601  			}
   602  		}()
   603  	}
   604  	// Feed the transactions into the tracers and return
   605  	var failed error
   606  	blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
   607  	for i, tx := range txs {
   608  		// Send the trace task over for execution
   609  		jobs <- &txTraceTask{statedb: statedb.Copy(), index: i}
   610  
   611  		// Generate the next state snapshot fast without tracing
   612  		msg, _ := tx.AsMessage(signer, block.BaseFee())
   613  		statedb.Prepare(tx.Hash(), i)
   614  		vmenv := vm.NewEVM(blockCtx, core.NewEVMTxContext(msg), statedb, api.backend.ChainConfig(), vm.Config{})
   615  		if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil {
   616  			failed = err
   617  			break
   618  		}
   619  		// Finalize the state so any modifications are written to the trie
   620  		// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
   621  		statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number()))
   622  	}
   623  	close(jobs)
   624  	pend.Wait()
   625  
   626  	// If execution failed in between, abort
   627  	if failed != nil {
   628  		return nil, failed
   629  	}
   630  	return results, nil
   631  }
   632  
   633  // TraceTransaction returns the structured logs created during the execution of EVM
   634  // and returns them as a JSON object.
   635  func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config *TraceConfig) (interface{}, error) {
   636  	_, blockHash, blockNumber, index, err := api.backend.GetTransaction(ctx, hash)
   637  	if err != nil {
   638  		return nil, err
   639  	}
   640  	// It shouldn't happen in practice.
   641  	if blockNumber == 0 {
   642  		return nil, errors.New("genesis is not traceable")
   643  	}
   644  	reexec := defaultTraceReexec
   645  	if config != nil && config.Reexec != nil {
   646  		reexec = *config.Reexec
   647  	}
   648  	block, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(blockNumber), blockHash)
   649  	if err != nil {
   650  		return nil, err
   651  	}
   652  	msg, vmctx, statedb, err := api.backend.StateAtTransaction(ctx, block, int(index), reexec)
   653  	if err != nil {
   654  		return nil, err
   655  	}
   656  	txctx := &Context{
   657  		BlockHash: blockHash,
   658  		TxIndex:   int(index),
   659  		TxHash:    hash,
   660  	}
   661  	return api.traceTx(ctx, msg, txctx, vmctx, statedb, config)
   662  }
   663  
   664  // TraceCall lets you trace a given eth_call. It collects the structured logs
   665  // created during the execution of EVM if the given transaction was added on
   666  // top of the provided block and returns them as a JSON object.
   667  func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, config *TraceCallConfig) (interface{}, error) {
   668  	// Try to retrieve the specified block
   669  	var (
   670  		err   error
   671  		block *types.Block
   672  	)
   673  	if hash, ok := blockNrOrHash.Hash(); ok {
   674  		block, err = api.blockByHash(ctx, hash)
   675  	} else if number, ok := blockNrOrHash.Number(); ok {
   676  		if number == rpc.PendingBlockNumber {
   677  			// We don't have access to the miner here. For tracing 'future' transactions,
   678  			// it can be done with block- and state-overrides instead, which offers
   679  			// more flexibility and stability than trying to trace on 'pending', since
   680  			// the contents of 'pending' is unstable and probably not a true representation
   681  			// of what the next actual block is likely to contain.
   682  			return nil, errors.New("tracing on top of pending is not supported")
   683  		}
   684  		block, err = api.blockByNumber(ctx, number)
   685  	} else {
   686  		return nil, errors.New("invalid arguments; neither block nor hash specified")
   687  	}
   688  	if err != nil {
   689  		return nil, err
   690  	}
   691  	// try to recompute the state
   692  	reexec := defaultTraceReexec
   693  	if config != nil && config.Reexec != nil {
   694  		reexec = *config.Reexec
   695  	}
   696  	statedb, err := api.backend.StateAtBlock(ctx, block, reexec, nil, true, false)
   697  	if err != nil {
   698  		return nil, err
   699  	}
   700  	vmctx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
   701  	// Apply the customization rules if required.
   702  	if config != nil {
   703  		if err := config.StateOverrides.Apply(statedb); err != nil {
   704  			return nil, err
   705  		}
   706  		config.BlockOverrides.Apply(&vmctx)
   707  	}
   708  	// Execute the trace
   709  	msg, err := args.ToMessage(api.backend.RPCGasCap(), block.BaseFee())
   710  	if err != nil {
   711  		return nil, err
   712  	}
   713  
   714  	var traceConfig *TraceConfig
   715  	if config != nil {
   716  		traceConfig = &TraceConfig{
   717  			Config:  config.Config,
   718  			Tracer:  config.Tracer,
   719  			Timeout: config.Timeout,
   720  			Reexec:  config.Reexec,
   721  		}
   722  	}
   723  	return api.traceTx(ctx, msg, new(Context), vmctx, statedb, traceConfig)
   724  }
   725  
   726  // traceTx configures a new tracer according to the provided configuration, and
   727  // executes the given message in the provided environment. The return value will
   728  // be tracer dependent.
   729  func (api *API) traceTx(ctx context.Context, message core.Message, txctx *Context, vmctx vm.BlockContext, statedb *state.StateDB, config *TraceConfig) (interface{}, error) {
   730  	var (
   731  		tracer    Tracer
   732  		err       error
   733  		timeout   = defaultTraceTimeout
   734  		txContext = core.NewEVMTxContext(message)
   735  	)
   736  	if config == nil {
   737  		config = &TraceConfig{}
   738  	}
   739  	// Default tracer is the struct logger
   740  	tracer = logger.NewStructLogger(config.Config)
   741  	if config.Tracer != nil {
   742  		tracer, err = New(*config.Tracer, txctx, config.TracerConfig)
   743  		if err != nil {
   744  			return nil, err
   745  		}
   746  	}
   747  	// Define a meaningful timeout of a single transaction trace
   748  	if config.Timeout != nil {
   749  		if timeout, err = time.ParseDuration(*config.Timeout); err != nil {
   750  			return nil, err
   751  		}
   752  	}
   753  	deadlineCtx, cancel := context.WithTimeout(ctx, timeout)
   754  	go func() {
   755  		<-deadlineCtx.Done()
   756  		if errors.Is(deadlineCtx.Err(), context.DeadlineExceeded) {
   757  			tracer.Stop(errors.New("execution timeout"))
   758  		}
   759  	}()
   760  	defer cancel()
   761  
   762  	// Run the transaction with tracing enabled.
   763  	vmenv := vm.NewEVM(vmctx, txContext, statedb, api.backend.ChainConfig(), vm.Config{Debug: true, Tracer: tracer, NoBaseFee: true})
   764  	// Call Prepare to clear out the statedb access list
   765  	statedb.Prepare(txctx.TxHash, txctx.TxIndex)
   766  	if _, err = core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas())); err != nil {
   767  		return nil, fmt.Errorf("tracing failed: %w", err)
   768  	}
   769  	return tracer.GetResult()
   770  }
   771  
   772  // APIs return the collection of RPC services the tracer package offers.
   773  func APIs(backend Backend) []rpc.API {
   774  	// Append all the local APIs and return
   775  	return []rpc.API{
   776  		{
   777  			Namespace: "debug",
   778  			Service:   NewAPI(backend),
   779  			Name:      "debug-tracer",
   780  		},
   781  	}
   782  }