github.com/calmw/ethereum@v0.1.1/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  	"encoding/json"
    24  	"errors"
    25  	"fmt"
    26  	"os"
    27  	"runtime"
    28  	"sync"
    29  	"time"
    30  
    31  	"github.com/calmw/ethereum/common"
    32  	"github.com/calmw/ethereum/common/hexutil"
    33  	"github.com/calmw/ethereum/consensus"
    34  	"github.com/calmw/ethereum/core"
    35  	"github.com/calmw/ethereum/core/rawdb"
    36  	"github.com/calmw/ethereum/core/state"
    37  	"github.com/calmw/ethereum/core/types"
    38  	"github.com/calmw/ethereum/core/vm"
    39  	"github.com/calmw/ethereum/eth/tracers/logger"
    40  	"github.com/calmw/ethereum/ethdb"
    41  	"github.com/calmw/ethereum/internal/ethapi"
    42  	"github.com/calmw/ethereum/log"
    43  	"github.com/calmw/ethereum/params"
    44  	"github.com/calmw/ethereum/rlp"
    45  	"github.com/calmw/ethereum/rpc"
    46  )
    47  
    48  const (
    49  	// defaultTraceTimeout is the amount of time a single transaction can execute
    50  	// by default before being forcefully aborted.
    51  	defaultTraceTimeout = 5 * time.Second
    52  
    53  	// defaultTraceReexec is the number of blocks the tracer is willing to go back
    54  	// and reexecute to produce missing historical state necessary to run a specific
    55  	// trace.
    56  	defaultTraceReexec = uint64(128)
    57  
    58  	// defaultTracechainMemLimit is the size of the triedb, at which traceChain
    59  	// switches over and tries to use a disk-backed database instead of building
    60  	// on top of memory.
    61  	// For non-archive nodes, this limit _will_ be overblown, as disk-backed tries
    62  	// will only be found every ~15K blocks or so.
    63  	defaultTracechainMemLimit = common.StorageSize(500 * 1024 * 1024)
    64  
    65  	// maximumPendingTraceStates is the maximum number of states allowed waiting
    66  	// for tracing. The creation of trace state will be paused if the unused
    67  	// trace states exceed this limit.
    68  	maximumPendingTraceStates = 128
    69  )
    70  
    71  var errTxNotFound = errors.New("transaction not found")
    72  
    73  // StateReleaseFunc is used to deallocate resources held by constructing a
    74  // historical state for tracing purposes.
    75  type StateReleaseFunc func()
    76  
    77  // Backend interface provides the common API services (that are provided by
    78  // both full and light clients) with access to necessary functions.
    79  type Backend interface {
    80  	HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error)
    81  	HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error)
    82  	BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error)
    83  	BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error)
    84  	GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error)
    85  	RPCGasCap() uint64
    86  	ChainConfig() *params.ChainConfig
    87  	Engine() consensus.Engine
    88  	ChainDb() ethdb.Database
    89  	StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (*state.StateDB, StateReleaseFunc, error)
    90  	StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, StateReleaseFunc, error)
    91  }
    92  
    93  // API is the collection of tracing APIs exposed over the private debugging endpoint.
    94  type API struct {
    95  	backend Backend
    96  }
    97  
    98  // NewAPI creates a new API definition for the tracing methods of the Ethereum service.
    99  func NewAPI(backend Backend) *API {
   100  	return &API{backend: backend}
   101  }
   102  
   103  // chainContext constructs the context reader which is used by the evm for reading
   104  // the necessary chain context.
   105  func (api *API) chainContext(ctx context.Context) core.ChainContext {
   106  	return ethapi.NewChainContext(ctx, api.backend)
   107  }
   108  
   109  // blockByNumber is the wrapper of the chain access function offered by the backend.
   110  // It will return an error if the block is not found.
   111  func (api *API) blockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) {
   112  	block, err := api.backend.BlockByNumber(ctx, number)
   113  	if err != nil {
   114  		return nil, err
   115  	}
   116  	if block == nil {
   117  		return nil, fmt.Errorf("block #%d not found", number)
   118  	}
   119  	return block, nil
   120  }
   121  
   122  // blockByHash is the wrapper of the chain access function offered by the backend.
   123  // It will return an error if the block is not found.
   124  func (api *API) blockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) {
   125  	block, err := api.backend.BlockByHash(ctx, hash)
   126  	if err != nil {
   127  		return nil, err
   128  	}
   129  	if block == nil {
   130  		return nil, fmt.Errorf("block %s not found", hash.Hex())
   131  	}
   132  	return block, nil
   133  }
   134  
   135  // blockByNumberAndHash is the wrapper of the chain access function offered by
   136  // the backend. It will return an error if the block is not found.
   137  //
   138  // Note this function is friendly for the light client which can only retrieve the
   139  // historical(before the CHT) header/block by number.
   140  func (api *API) blockByNumberAndHash(ctx context.Context, number rpc.BlockNumber, hash common.Hash) (*types.Block, error) {
   141  	block, err := api.blockByNumber(ctx, number)
   142  	if err != nil {
   143  		return nil, err
   144  	}
   145  	if block.Hash() == hash {
   146  		return block, nil
   147  	}
   148  	return api.blockByHash(ctx, hash)
   149  }
   150  
   151  // TraceConfig holds extra parameters to trace functions.
   152  type TraceConfig struct {
   153  	*logger.Config
   154  	Tracer  *string
   155  	Timeout *string
   156  	Reexec  *uint64
   157  	// Config specific to given tracer. Note struct logger
   158  	// config are historically embedded in main object.
   159  	TracerConfig json.RawMessage
   160  }
   161  
   162  // TraceCallConfig is the config for traceCall API. It holds one more
   163  // field to override the state for tracing.
   164  type TraceCallConfig struct {
   165  	TraceConfig
   166  	StateOverrides *ethapi.StateOverride
   167  	BlockOverrides *ethapi.BlockOverrides
   168  }
   169  
   170  // StdTraceConfig holds extra parameters to standard-json trace functions.
   171  type StdTraceConfig struct {
   172  	logger.Config
   173  	Reexec *uint64
   174  	TxHash common.Hash
   175  }
   176  
   177  // txTraceResult is the result of a single transaction trace.
   178  type txTraceResult struct {
   179  	TxHash common.Hash `json:"txHash"`           // transaction hash
   180  	Result interface{} `json:"result,omitempty"` // Trace results produced by the tracer
   181  	Error  string      `json:"error,omitempty"`  // Trace failure produced by the tracer
   182  }
   183  
   184  // blockTraceTask represents a single block trace task when an entire chain is
   185  // being traced.
   186  type blockTraceTask struct {
   187  	statedb *state.StateDB   // Intermediate state prepped for tracing
   188  	block   *types.Block     // Block to trace the transactions from
   189  	release StateReleaseFunc // The function to release the held resource for this task
   190  	results []*txTraceResult // Trace results produced by the task
   191  }
   192  
   193  // blockTraceResult represents the results of tracing a single block when an entire
   194  // chain is being traced.
   195  type blockTraceResult struct {
   196  	Block  hexutil.Uint64   `json:"block"`  // Block number corresponding to this trace
   197  	Hash   common.Hash      `json:"hash"`   // Block hash corresponding to this trace
   198  	Traces []*txTraceResult `json:"traces"` // Trace results produced by the task
   199  }
   200  
   201  // txTraceTask represents a single transaction trace task when an entire block
   202  // is being traced.
   203  type txTraceTask struct {
   204  	statedb *state.StateDB // Intermediate state prepped for tracing
   205  	index   int            // Transaction offset in the block
   206  }
   207  
   208  // TraceChain returns the structured logs created during the execution of EVM
   209  // between two blocks (excluding start) and returns them as a JSON object.
   210  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
   211  	from, err := api.blockByNumber(ctx, start)
   212  	if err != nil {
   213  		return nil, err
   214  	}
   215  	to, err := api.blockByNumber(ctx, end)
   216  	if err != nil {
   217  		return nil, err
   218  	}
   219  	if from.Number().Cmp(to.Number()) >= 0 {
   220  		return nil, fmt.Errorf("end block (#%d) needs to come after start block (#%d)", end, start)
   221  	}
   222  	// Tracing a chain is a **long** operation, only do with subscriptions
   223  	notifier, supported := rpc.NotifierFromContext(ctx)
   224  	if !supported {
   225  		return &rpc.Subscription{}, rpc.ErrNotificationsUnsupported
   226  	}
   227  	sub := notifier.CreateSubscription()
   228  
   229  	resCh := api.traceChain(from, to, config, notifier.Closed())
   230  	go func() {
   231  		for result := range resCh {
   232  			notifier.Notify(sub.ID, result)
   233  		}
   234  	}()
   235  	return sub, nil
   236  }
   237  
   238  // traceChain configures a new tracer according to the provided configuration, and
   239  // executes all the transactions contained within. The tracing chain range includes
   240  // the end block but excludes the start one. The return value will be one item per
   241  // transaction, dependent on the requested tracer.
   242  // The tracing procedure should be aborted in case the closed signal is received.
   243  func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed <-chan interface{}) chan *blockTraceResult {
   244  	reexec := defaultTraceReexec
   245  	if config != nil && config.Reexec != nil {
   246  		reexec = *config.Reexec
   247  	}
   248  	blocks := int(end.NumberU64() - start.NumberU64())
   249  	threads := runtime.NumCPU()
   250  	if threads > blocks {
   251  		threads = blocks
   252  	}
   253  	var (
   254  		pend    = new(sync.WaitGroup)
   255  		ctx     = context.Background()
   256  		taskCh  = make(chan *blockTraceTask, threads)
   257  		resCh   = make(chan *blockTraceTask, threads)
   258  		tracker = newStateTracker(maximumPendingTraceStates, start.NumberU64())
   259  	)
   260  	for th := 0; th < threads; th++ {
   261  		pend.Add(1)
   262  		go func() {
   263  			defer pend.Done()
   264  
   265  			// Fetch and execute the block trace taskCh
   266  			for task := range taskCh {
   267  				var (
   268  					signer   = types.MakeSigner(api.backend.ChainConfig(), task.block.Number(), task.block.Time())
   269  					blockCtx = core.NewEVMBlockContext(task.block.Header(), api.chainContext(ctx), nil)
   270  				)
   271  				// Trace all the transactions contained within
   272  				for i, tx := range task.block.Transactions() {
   273  					msg, _ := core.TransactionToMessage(tx, signer, task.block.BaseFee())
   274  					txctx := &Context{
   275  						BlockHash:   task.block.Hash(),
   276  						BlockNumber: task.block.Number(),
   277  						TxIndex:     i,
   278  						TxHash:      tx.Hash(),
   279  					}
   280  					res, err := api.traceTx(ctx, msg, txctx, blockCtx, task.statedb, config)
   281  					if err != nil {
   282  						task.results[i] = &txTraceResult{TxHash: tx.Hash(), Error: err.Error()}
   283  						log.Warn("Tracing failed", "hash", tx.Hash(), "block", task.block.NumberU64(), "err", err)
   284  						break
   285  					}
   286  					// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
   287  					task.statedb.Finalise(api.backend.ChainConfig().IsEIP158(task.block.Number()))
   288  					task.results[i] = &txTraceResult{TxHash: tx.Hash(), Result: res}
   289  				}
   290  				// Tracing state is used up, queue it for de-referencing. Note the
   291  				// state is the parent state of trace block, use block.number-1 as
   292  				// the state number.
   293  				tracker.releaseState(task.block.NumberU64()-1, task.release)
   294  
   295  				// Stream the result back to the result catcher or abort on teardown
   296  				select {
   297  				case resCh <- task:
   298  				case <-closed:
   299  					return
   300  				}
   301  			}
   302  		}()
   303  	}
   304  	// Start a goroutine to feed all the blocks into the tracers
   305  	go func() {
   306  		var (
   307  			logged  time.Time
   308  			begin   = time.Now()
   309  			number  uint64
   310  			traced  uint64
   311  			failed  error
   312  			statedb *state.StateDB
   313  			release StateReleaseFunc
   314  		)
   315  		// Ensure everything is properly cleaned up on any exit path
   316  		defer func() {
   317  			close(taskCh)
   318  			pend.Wait()
   319  
   320  			// Clean out any pending release functions of trace states.
   321  			tracker.callReleases()
   322  
   323  			// Log the chain result
   324  			switch {
   325  			case failed != nil:
   326  				log.Warn("Chain tracing failed", "start", start.NumberU64(), "end", end.NumberU64(), "transactions", traced, "elapsed", time.Since(begin), "err", failed)
   327  			case number < end.NumberU64():
   328  				log.Warn("Chain tracing aborted", "start", start.NumberU64(), "end", end.NumberU64(), "abort", number, "transactions", traced, "elapsed", time.Since(begin))
   329  			default:
   330  				log.Info("Chain tracing finished", "start", start.NumberU64(), "end", end.NumberU64(), "transactions", traced, "elapsed", time.Since(begin))
   331  			}
   332  			close(resCh)
   333  		}()
   334  		// Feed all the blocks both into the tracer, as well as fast process concurrently
   335  		for number = start.NumberU64(); number < end.NumberU64(); number++ {
   336  			// Stop tracing if interruption was requested
   337  			select {
   338  			case <-closed:
   339  				return
   340  			default:
   341  			}
   342  			// Print progress logs if long enough time elapsed
   343  			if time.Since(logged) > 8*time.Second {
   344  				logged = time.Now()
   345  				log.Info("Tracing chain segment", "start", start.NumberU64(), "end", end.NumberU64(), "current", number, "transactions", traced, "elapsed", time.Since(begin))
   346  			}
   347  			// Retrieve the parent block and target block for tracing.
   348  			block, err := api.blockByNumber(ctx, rpc.BlockNumber(number))
   349  			if err != nil {
   350  				failed = err
   351  				break
   352  			}
   353  			next, err := api.blockByNumber(ctx, rpc.BlockNumber(number+1))
   354  			if err != nil {
   355  				failed = err
   356  				break
   357  			}
   358  			// Make sure the state creator doesn't go too far. Too many unprocessed
   359  			// trace state may cause the oldest state to become stale(e.g. in
   360  			// path-based scheme).
   361  			if err = tracker.wait(number); err != nil {
   362  				failed = err
   363  				break
   364  			}
   365  			// Prepare the statedb for tracing. Don't use the live database for
   366  			// tracing to avoid persisting state junks into the database. Switch
   367  			// over to `preferDisk` mode only if the memory usage exceeds the
   368  			// limit, the trie database will be reconstructed from scratch only
   369  			// if the relevant state is available in disk.
   370  			var preferDisk bool
   371  			if statedb != nil {
   372  				s1, s2 := statedb.Database().TrieDB().Size()
   373  				preferDisk = s1+s2 > defaultTracechainMemLimit
   374  			}
   375  			statedb, release, err = api.backend.StateAtBlock(ctx, block, reexec, statedb, false, preferDisk)
   376  			if err != nil {
   377  				failed = err
   378  				break
   379  			}
   380  			// Clean out any pending release functions of trace state. Note this
   381  			// step must be done after constructing tracing state, because the
   382  			// tracing state of block next depends on the parent state and construction
   383  			// may fail if we release too early.
   384  			tracker.callReleases()
   385  
   386  			// Send the block over to the concurrent tracers (if not in the fast-forward phase)
   387  			txs := next.Transactions()
   388  			select {
   389  			case taskCh <- &blockTraceTask{statedb: statedb.Copy(), block: next, release: release, results: make([]*txTraceResult, len(txs))}:
   390  			case <-closed:
   391  				tracker.releaseState(number, release)
   392  				return
   393  			}
   394  			traced += uint64(len(txs))
   395  		}
   396  	}()
   397  
   398  	// Keep reading the trace results and stream them to result channel.
   399  	retCh := make(chan *blockTraceResult)
   400  	go func() {
   401  		defer close(retCh)
   402  		var (
   403  			next = start.NumberU64() + 1
   404  			done = make(map[uint64]*blockTraceResult)
   405  		)
   406  		for res := range resCh {
   407  			// Queue up next received result
   408  			result := &blockTraceResult{
   409  				Block:  hexutil.Uint64(res.block.NumberU64()),
   410  				Hash:   res.block.Hash(),
   411  				Traces: res.results,
   412  			}
   413  			done[uint64(result.Block)] = result
   414  
   415  			// Stream completed traces to the result channel
   416  			for result, ok := done[next]; ok; result, ok = done[next] {
   417  				if len(result.Traces) > 0 || next == end.NumberU64() {
   418  					// It will be blocked in case the channel consumer doesn't take the
   419  					// tracing result in time(e.g. the websocket connect is not stable)
   420  					// which will eventually block the entire chain tracer. It's the
   421  					// expected behavior to not waste node resources for a non-active user.
   422  					retCh <- result
   423  				}
   424  				delete(done, next)
   425  				next++
   426  			}
   427  		}
   428  	}()
   429  	return retCh
   430  }
   431  
   432  // TraceBlockByNumber returns the structured logs created during the execution of
   433  // EVM and returns them as a JSON object.
   434  func (api *API) TraceBlockByNumber(ctx context.Context, number rpc.BlockNumber, config *TraceConfig) ([]*txTraceResult, error) {
   435  	block, err := api.blockByNumber(ctx, number)
   436  	if err != nil {
   437  		return nil, err
   438  	}
   439  	return api.traceBlock(ctx, block, config)
   440  }
   441  
   442  // TraceBlockByHash returns the structured logs created during the execution of
   443  // EVM and returns them as a JSON object.
   444  func (api *API) TraceBlockByHash(ctx context.Context, hash common.Hash, config *TraceConfig) ([]*txTraceResult, error) {
   445  	block, err := api.blockByHash(ctx, hash)
   446  	if err != nil {
   447  		return nil, err
   448  	}
   449  	return api.traceBlock(ctx, block, config)
   450  }
   451  
   452  // TraceBlock returns the structured logs created during the execution of EVM
   453  // and returns them as a JSON object.
   454  func (api *API) TraceBlock(ctx context.Context, blob hexutil.Bytes, config *TraceConfig) ([]*txTraceResult, error) {
   455  	block := new(types.Block)
   456  	if err := rlp.Decode(bytes.NewReader(blob), block); err != nil {
   457  		return nil, fmt.Errorf("could not decode block: %v", err)
   458  	}
   459  	return api.traceBlock(ctx, block, config)
   460  }
   461  
   462  // TraceBlockFromFile returns the structured logs created during the execution of
   463  // EVM and returns them as a JSON object.
   464  func (api *API) TraceBlockFromFile(ctx context.Context, file string, config *TraceConfig) ([]*txTraceResult, error) {
   465  	blob, err := os.ReadFile(file)
   466  	if err != nil {
   467  		return nil, fmt.Errorf("could not read file: %v", err)
   468  	}
   469  	return api.TraceBlock(ctx, blob, config)
   470  }
   471  
   472  // TraceBadBlock returns the structured logs created during the execution of
   473  // EVM against a block pulled from the pool of bad ones and returns them as a JSON
   474  // object.
   475  func (api *API) TraceBadBlock(ctx context.Context, hash common.Hash, config *TraceConfig) ([]*txTraceResult, error) {
   476  	block := rawdb.ReadBadBlock(api.backend.ChainDb(), hash)
   477  	if block == nil {
   478  		return nil, fmt.Errorf("bad block %#x not found", hash)
   479  	}
   480  	return api.traceBlock(ctx, block, config)
   481  }
   482  
   483  // StandardTraceBlockToFile dumps the structured logs created during the
   484  // execution of EVM to the local file system and returns a list of files
   485  // to the caller.
   486  func (api *API) StandardTraceBlockToFile(ctx context.Context, hash common.Hash, config *StdTraceConfig) ([]string, error) {
   487  	block, err := api.blockByHash(ctx, hash)
   488  	if err != nil {
   489  		return nil, err
   490  	}
   491  	return api.standardTraceBlockToFile(ctx, block, config)
   492  }
   493  
   494  // IntermediateRoots executes a block (bad- or canon- or side-), and returns a list
   495  // of intermediate roots: the stateroot after each transaction.
   496  func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config *TraceConfig) ([]common.Hash, error) {
   497  	block, _ := api.blockByHash(ctx, hash)
   498  	if block == nil {
   499  		// Check in the bad blocks
   500  		block = rawdb.ReadBadBlock(api.backend.ChainDb(), hash)
   501  	}
   502  	if block == nil {
   503  		return nil, fmt.Errorf("block %#x not found", hash)
   504  	}
   505  	if block.NumberU64() == 0 {
   506  		return nil, errors.New("genesis is not traceable")
   507  	}
   508  	parent, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(block.NumberU64()-1), block.ParentHash())
   509  	if err != nil {
   510  		return nil, err
   511  	}
   512  	reexec := defaultTraceReexec
   513  	if config != nil && config.Reexec != nil {
   514  		reexec = *config.Reexec
   515  	}
   516  	statedb, release, err := api.backend.StateAtBlock(ctx, parent, reexec, nil, true, false)
   517  	if err != nil {
   518  		return nil, err
   519  	}
   520  	defer release()
   521  
   522  	var (
   523  		roots              []common.Hash
   524  		signer             = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time())
   525  		chainConfig        = api.backend.ChainConfig()
   526  		vmctx              = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
   527  		deleteEmptyObjects = chainConfig.IsEIP158(block.Number())
   528  	)
   529  	for i, tx := range block.Transactions() {
   530  		if err := ctx.Err(); err != nil {
   531  			return nil, err
   532  		}
   533  		var (
   534  			msg, _    = core.TransactionToMessage(tx, signer, block.BaseFee())
   535  			txContext = core.NewEVMTxContext(msg)
   536  			vmenv     = vm.NewEVM(vmctx, txContext, statedb, chainConfig, vm.Config{})
   537  		)
   538  		statedb.SetTxContext(tx.Hash(), i)
   539  		if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit)); err != nil {
   540  			log.Warn("Tracing intermediate roots did not complete", "txindex", i, "txhash", tx.Hash(), "err", err)
   541  			// We intentionally don't return the error here: if we do, then the RPC server will not
   542  			// return the roots. Most likely, the caller already knows that a certain transaction fails to
   543  			// be included, but still want the intermediate roots that led to that point.
   544  			// It may happen the tx_N causes an erroneous state, which in turn causes tx_N+M to not be
   545  			// executable.
   546  			// N.B: This should never happen while tracing canon blocks, only when tracing bad blocks.
   547  			return roots, nil
   548  		}
   549  		// calling IntermediateRoot will internally call Finalize on the state
   550  		// so any modifications are written to the trie
   551  		roots = append(roots, statedb.IntermediateRoot(deleteEmptyObjects))
   552  	}
   553  	return roots, nil
   554  }
   555  
   556  // StandardTraceBadBlockToFile dumps the structured logs created during the
   557  // execution of EVM against a block pulled from the pool of bad ones to the
   558  // local file system and returns a list of files to the caller.
   559  func (api *API) StandardTraceBadBlockToFile(ctx context.Context, hash common.Hash, config *StdTraceConfig) ([]string, error) {
   560  	block := rawdb.ReadBadBlock(api.backend.ChainDb(), hash)
   561  	if block == nil {
   562  		return nil, fmt.Errorf("bad block %#x not found", hash)
   563  	}
   564  	return api.standardTraceBlockToFile(ctx, block, config)
   565  }
   566  
   567  // traceBlock configures a new tracer according to the provided configuration, and
   568  // executes all the transactions contained within. The return value will be one item
   569  // per transaction, dependent on the requested tracer.
   570  func (api *API) traceBlock(ctx context.Context, block *types.Block, config *TraceConfig) ([]*txTraceResult, error) {
   571  	if block.NumberU64() == 0 {
   572  		return nil, errors.New("genesis is not traceable")
   573  	}
   574  	// Prepare base state
   575  	parent, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(block.NumberU64()-1), block.ParentHash())
   576  	if err != nil {
   577  		return nil, err
   578  	}
   579  	reexec := defaultTraceReexec
   580  	if config != nil && config.Reexec != nil {
   581  		reexec = *config.Reexec
   582  	}
   583  	statedb, release, err := api.backend.StateAtBlock(ctx, parent, reexec, nil, true, false)
   584  	if err != nil {
   585  		return nil, err
   586  	}
   587  	defer release()
   588  
   589  	// JS tracers have high overhead. In this case run a parallel
   590  	// process that generates states in one thread and traces txes
   591  	// in separate worker threads.
   592  	if config != nil && config.Tracer != nil && *config.Tracer != "" {
   593  		if isJS := DefaultDirectory.IsJS(*config.Tracer); isJS {
   594  			return api.traceBlockParallel(ctx, block, statedb, config)
   595  		}
   596  	}
   597  	// Native tracers have low overhead
   598  	var (
   599  		txs       = block.Transactions()
   600  		blockHash = block.Hash()
   601  		is158     = api.backend.ChainConfig().IsEIP158(block.Number())
   602  		blockCtx  = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
   603  		signer    = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time())
   604  		results   = make([]*txTraceResult, len(txs))
   605  	)
   606  	for i, tx := range txs {
   607  		// Generate the next state snapshot fast without tracing
   608  		msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
   609  		txctx := &Context{
   610  			BlockHash:   blockHash,
   611  			BlockNumber: block.Number(),
   612  			TxIndex:     i,
   613  			TxHash:      tx.Hash(),
   614  		}
   615  		res, err := api.traceTx(ctx, msg, txctx, blockCtx, statedb, config)
   616  		if err != nil {
   617  			return nil, err
   618  		}
   619  		results[i] = &txTraceResult{TxHash: tx.Hash(), Result: res}
   620  		// Finalize the state so any modifications are written to the trie
   621  		// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
   622  		statedb.Finalise(is158)
   623  	}
   624  	return results, nil
   625  }
   626  
   627  // traceBlockParallel is for tracers that have a high overhead (read JS tracers). One thread
   628  // runs along and executes txes without tracing enabled to generate their prestate.
   629  // Worker threads take the tasks and the prestate and trace them.
   630  func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, statedb *state.StateDB, config *TraceConfig) ([]*txTraceResult, error) {
   631  	// Execute all the transaction contained within the block concurrently
   632  	var (
   633  		txs       = block.Transactions()
   634  		blockHash = block.Hash()
   635  		blockCtx  = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
   636  		signer    = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time())
   637  		results   = make([]*txTraceResult, len(txs))
   638  		pend      sync.WaitGroup
   639  	)
   640  	threads := runtime.NumCPU()
   641  	if threads > len(txs) {
   642  		threads = len(txs)
   643  	}
   644  	jobs := make(chan *txTraceTask, threads)
   645  	for th := 0; th < threads; th++ {
   646  		pend.Add(1)
   647  		go func() {
   648  			defer pend.Done()
   649  			// Fetch and execute the next transaction trace tasks
   650  			for task := range jobs {
   651  				msg, _ := core.TransactionToMessage(txs[task.index], signer, block.BaseFee())
   652  				txctx := &Context{
   653  					BlockHash:   blockHash,
   654  					BlockNumber: block.Number(),
   655  					TxIndex:     task.index,
   656  					TxHash:      txs[task.index].Hash(),
   657  				}
   658  				res, err := api.traceTx(ctx, msg, txctx, blockCtx, task.statedb, config)
   659  				if err != nil {
   660  					results[task.index] = &txTraceResult{TxHash: txs[task.index].Hash(), Error: err.Error()}
   661  					continue
   662  				}
   663  				results[task.index] = &txTraceResult{TxHash: txs[task.index].Hash(), Result: res}
   664  			}
   665  		}()
   666  	}
   667  
   668  	// Feed the transactions into the tracers and return
   669  	var failed error
   670  txloop:
   671  	for i, tx := range txs {
   672  		// Send the trace task over for execution
   673  		task := &txTraceTask{statedb: statedb.Copy(), index: i}
   674  		select {
   675  		case <-ctx.Done():
   676  			failed = ctx.Err()
   677  			break txloop
   678  		case jobs <- task:
   679  		}
   680  
   681  		// Generate the next state snapshot fast without tracing
   682  		msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
   683  		statedb.SetTxContext(tx.Hash(), i)
   684  		vmenv := vm.NewEVM(blockCtx, core.NewEVMTxContext(msg), statedb, api.backend.ChainConfig(), vm.Config{})
   685  		if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit)); err != nil {
   686  			failed = err
   687  			break txloop
   688  		}
   689  		// Finalize the state so any modifications are written to the trie
   690  		// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
   691  		statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number()))
   692  	}
   693  
   694  	close(jobs)
   695  	pend.Wait()
   696  
   697  	// If execution failed in between, abort
   698  	if failed != nil {
   699  		return nil, failed
   700  	}
   701  	return results, nil
   702  }
   703  
   704  // standardTraceBlockToFile configures a new tracer which uses standard JSON output,
   705  // and traces either a full block or an individual transaction. The return value will
   706  // be one filename per transaction traced.
   707  func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block, config *StdTraceConfig) ([]string, error) {
   708  	// If we're tracing a single transaction, make sure it's present
   709  	if config != nil && config.TxHash != (common.Hash{}) {
   710  		if !containsTx(block, config.TxHash) {
   711  			return nil, fmt.Errorf("transaction %#x not found in block", config.TxHash)
   712  		}
   713  	}
   714  	if block.NumberU64() == 0 {
   715  		return nil, errors.New("genesis is not traceable")
   716  	}
   717  	parent, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(block.NumberU64()-1), block.ParentHash())
   718  	if err != nil {
   719  		return nil, err
   720  	}
   721  	reexec := defaultTraceReexec
   722  	if config != nil && config.Reexec != nil {
   723  		reexec = *config.Reexec
   724  	}
   725  	statedb, release, err := api.backend.StateAtBlock(ctx, parent, reexec, nil, true, false)
   726  	if err != nil {
   727  		return nil, err
   728  	}
   729  	defer release()
   730  
   731  	// Retrieve the tracing configurations, or use default values
   732  	var (
   733  		logConfig logger.Config
   734  		txHash    common.Hash
   735  	)
   736  	if config != nil {
   737  		logConfig = config.Config
   738  		txHash = config.TxHash
   739  	}
   740  	logConfig.Debug = true
   741  
   742  	// Execute transaction, either tracing all or just the requested one
   743  	var (
   744  		dumps       []string
   745  		signer      = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time())
   746  		chainConfig = api.backend.ChainConfig()
   747  		vmctx       = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
   748  		canon       = true
   749  	)
   750  	// Check if there are any overrides: the caller may wish to enable a future
   751  	// fork when executing this block. Note, such overrides are only applicable to the
   752  	// actual specified block, not any preceding blocks that we have to go through
   753  	// in order to obtain the state.
   754  	// Therefore, it's perfectly valid to specify `"futureForkBlock": 0`, to enable `futureFork`
   755  	if config != nil && config.Overrides != nil {
   756  		// Note: This copies the config, to not screw up the main config
   757  		chainConfig, canon = overrideConfig(chainConfig, config.Overrides)
   758  	}
   759  	for i, tx := range block.Transactions() {
   760  		// Prepare the transaction for un-traced execution
   761  		var (
   762  			msg, _    = core.TransactionToMessage(tx, signer, block.BaseFee())
   763  			txContext = core.NewEVMTxContext(msg)
   764  			vmConf    vm.Config
   765  			dump      *os.File
   766  			writer    *bufio.Writer
   767  			err       error
   768  		)
   769  		// If the transaction needs tracing, swap out the configs
   770  		if tx.Hash() == txHash || txHash == (common.Hash{}) {
   771  			// Generate a unique temporary file to dump it into
   772  			prefix := fmt.Sprintf("block_%#x-%d-%#x-", block.Hash().Bytes()[:4], i, tx.Hash().Bytes()[:4])
   773  			if !canon {
   774  				prefix = fmt.Sprintf("%valt-", prefix)
   775  			}
   776  			dump, err = os.CreateTemp(os.TempDir(), prefix)
   777  			if err != nil {
   778  				return nil, err
   779  			}
   780  			dumps = append(dumps, dump.Name())
   781  
   782  			// Swap out the noop logger to the standard tracer
   783  			writer = bufio.NewWriter(dump)
   784  			vmConf = vm.Config{
   785  				Tracer:                  logger.NewJSONLogger(&logConfig, writer),
   786  				EnablePreimageRecording: true,
   787  			}
   788  		}
   789  		// Execute the transaction and flush any traces to disk
   790  		vmenv := vm.NewEVM(vmctx, txContext, statedb, chainConfig, vmConf)
   791  		statedb.SetTxContext(tx.Hash(), i)
   792  		_, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit))
   793  		if writer != nil {
   794  			writer.Flush()
   795  		}
   796  		if dump != nil {
   797  			dump.Close()
   798  			log.Info("Wrote standard trace", "file", dump.Name())
   799  		}
   800  		if err != nil {
   801  			return dumps, err
   802  		}
   803  		// Finalize the state so any modifications are written to the trie
   804  		// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
   805  		statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number()))
   806  
   807  		// If we've traced the transaction we were looking for, abort
   808  		if tx.Hash() == txHash {
   809  			break
   810  		}
   811  	}
   812  	return dumps, nil
   813  }
   814  
   815  // containsTx reports whether the transaction with a certain hash
   816  // is contained within the specified block.
   817  func containsTx(block *types.Block, hash common.Hash) bool {
   818  	for _, tx := range block.Transactions() {
   819  		if tx.Hash() == hash {
   820  			return true
   821  		}
   822  	}
   823  	return false
   824  }
   825  
   826  // TraceTransaction returns the structured logs created during the execution of EVM
   827  // and returns them as a JSON object.
   828  func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config *TraceConfig) (interface{}, error) {
   829  	tx, blockHash, blockNumber, index, err := api.backend.GetTransaction(ctx, hash)
   830  	if err != nil {
   831  		return nil, err
   832  	}
   833  	// Only mined txes are supported
   834  	if tx == nil {
   835  		return nil, errTxNotFound
   836  	}
   837  	// It shouldn't happen in practice.
   838  	if blockNumber == 0 {
   839  		return nil, errors.New("genesis is not traceable")
   840  	}
   841  	reexec := defaultTraceReexec
   842  	if config != nil && config.Reexec != nil {
   843  		reexec = *config.Reexec
   844  	}
   845  	block, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(blockNumber), blockHash)
   846  	if err != nil {
   847  		return nil, err
   848  	}
   849  	msg, vmctx, statedb, release, err := api.backend.StateAtTransaction(ctx, block, int(index), reexec)
   850  	if err != nil {
   851  		return nil, err
   852  	}
   853  	defer release()
   854  
   855  	txctx := &Context{
   856  		BlockHash:   blockHash,
   857  		BlockNumber: block.Number(),
   858  		TxIndex:     int(index),
   859  		TxHash:      hash,
   860  	}
   861  	return api.traceTx(ctx, msg, txctx, vmctx, statedb, config)
   862  }
   863  
   864  // TraceCall lets you trace a given eth_call. It collects the structured logs
   865  // created during the execution of EVM if the given transaction was added on
   866  // top of the provided block and returns them as a JSON object.
   867  func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, config *TraceCallConfig) (interface{}, error) {
   868  	// Try to retrieve the specified block
   869  	var (
   870  		err   error
   871  		block *types.Block
   872  	)
   873  	if hash, ok := blockNrOrHash.Hash(); ok {
   874  		block, err = api.blockByHash(ctx, hash)
   875  	} else if number, ok := blockNrOrHash.Number(); ok {
   876  		if number == rpc.PendingBlockNumber {
   877  			// We don't have access to the miner here. For tracing 'future' transactions,
   878  			// it can be done with block- and state-overrides instead, which offers
   879  			// more flexibility and stability than trying to trace on 'pending', since
   880  			// the contents of 'pending' is unstable and probably not a true representation
   881  			// of what the next actual block is likely to contain.
   882  			return nil, errors.New("tracing on top of pending is not supported")
   883  		}
   884  		block, err = api.blockByNumber(ctx, number)
   885  	} else {
   886  		return nil, errors.New("invalid arguments; neither block nor hash specified")
   887  	}
   888  	if err != nil {
   889  		return nil, err
   890  	}
   891  	// try to recompute the state
   892  	reexec := defaultTraceReexec
   893  	if config != nil && config.Reexec != nil {
   894  		reexec = *config.Reexec
   895  	}
   896  	statedb, release, err := api.backend.StateAtBlock(ctx, block, reexec, nil, true, false)
   897  	if err != nil {
   898  		return nil, err
   899  	}
   900  	defer release()
   901  
   902  	vmctx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
   903  	// Apply the customization rules if required.
   904  	if config != nil {
   905  		if err := config.StateOverrides.Apply(statedb); err != nil {
   906  			return nil, err
   907  		}
   908  		config.BlockOverrides.Apply(&vmctx)
   909  	}
   910  	// Execute the trace
   911  	msg, err := args.ToMessage(api.backend.RPCGasCap(), block.BaseFee())
   912  	if err != nil {
   913  		return nil, err
   914  	}
   915  
   916  	var traceConfig *TraceConfig
   917  	if config != nil {
   918  		traceConfig = &config.TraceConfig
   919  	}
   920  	return api.traceTx(ctx, msg, new(Context), vmctx, statedb, traceConfig)
   921  }
   922  
   923  // traceTx configures a new tracer according to the provided configuration, and
   924  // executes the given message in the provided environment. The return value will
   925  // be tracer dependent.
   926  func (api *API) traceTx(ctx context.Context, message *core.Message, txctx *Context, vmctx vm.BlockContext, statedb *state.StateDB, config *TraceConfig) (interface{}, error) {
   927  	var (
   928  		tracer    Tracer
   929  		err       error
   930  		timeout   = defaultTraceTimeout
   931  		txContext = core.NewEVMTxContext(message)
   932  	)
   933  	if config == nil {
   934  		config = &TraceConfig{}
   935  	}
   936  	// Default tracer is the struct logger
   937  	tracer = logger.NewStructLogger(config.Config)
   938  	if config.Tracer != nil {
   939  		tracer, err = DefaultDirectory.New(*config.Tracer, txctx, config.TracerConfig)
   940  		if err != nil {
   941  			return nil, err
   942  		}
   943  	}
   944  	vmenv := vm.NewEVM(vmctx, txContext, statedb, api.backend.ChainConfig(), vm.Config{Tracer: tracer, NoBaseFee: true})
   945  
   946  	// Define a meaningful timeout of a single transaction trace
   947  	if config.Timeout != nil {
   948  		if timeout, err = time.ParseDuration(*config.Timeout); err != nil {
   949  			return nil, err
   950  		}
   951  	}
   952  	deadlineCtx, cancel := context.WithTimeout(ctx, timeout)
   953  	go func() {
   954  		<-deadlineCtx.Done()
   955  		if errors.Is(deadlineCtx.Err(), context.DeadlineExceeded) {
   956  			tracer.Stop(errors.New("execution timeout"))
   957  			// Stop evm execution. Note cancellation is not necessarily immediate.
   958  			vmenv.Cancel()
   959  		}
   960  	}()
   961  	defer cancel()
   962  
   963  	// Call Prepare to clear out the statedb access list
   964  	statedb.SetTxContext(txctx.TxHash, txctx.TxIndex)
   965  	if _, err = core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.GasLimit)); err != nil {
   966  		return nil, fmt.Errorf("tracing failed: %w", err)
   967  	}
   968  	return tracer.GetResult()
   969  }
   970  
   971  // APIs return the collection of RPC services the tracer package offers.
   972  func APIs(backend Backend) []rpc.API {
   973  	// Append all the local APIs and return
   974  	return []rpc.API{
   975  		{
   976  			Namespace: "debug",
   977  			Service:   NewAPI(backend),
   978  		},
   979  	}
   980  }
   981  
   982  // overrideConfig returns a copy of original with forks enabled by override enabled,
   983  // along with a boolean that indicates whether the copy is canonical (equivalent to the original).
   984  // Note: the Clique-part is _not_ deep copied
   985  func overrideConfig(original *params.ChainConfig, override *params.ChainConfig) (*params.ChainConfig, bool) {
   986  	copy := new(params.ChainConfig)
   987  	*copy = *original
   988  	canon := true
   989  
   990  	// Apply forks (after Berlin) to the copy.
   991  	if block := override.BerlinBlock; block != nil {
   992  		copy.BerlinBlock = block
   993  		canon = false
   994  	}
   995  	if block := override.LondonBlock; block != nil {
   996  		copy.LondonBlock = block
   997  		canon = false
   998  	}
   999  	if block := override.ArrowGlacierBlock; block != nil {
  1000  		copy.ArrowGlacierBlock = block
  1001  		canon = false
  1002  	}
  1003  	if block := override.GrayGlacierBlock; block != nil {
  1004  		copy.GrayGlacierBlock = block
  1005  		canon = false
  1006  	}
  1007  	if block := override.MergeNetsplitBlock; block != nil {
  1008  		copy.MergeNetsplitBlock = block
  1009  		canon = false
  1010  	}
  1011  	if timestamp := override.ShanghaiTime; timestamp != nil {
  1012  		copy.ShanghaiTime = timestamp
  1013  		canon = false
  1014  	}
  1015  	if timestamp := override.CancunTime; timestamp != nil {
  1016  		copy.CancunTime = timestamp
  1017  		canon = false
  1018  	}
  1019  	if timestamp := override.PragueTime; timestamp != nil {
  1020  		copy.PragueTime = timestamp
  1021  		canon = false
  1022  	}
  1023  
  1024  	return copy, canon
  1025  }