github.com/cryptotooltop/go-ethereum@v0.0.0-20231103184714-151d1922f3e5/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  	"math/big"
    27  	"os"
    28  	"runtime"
    29  	"sync"
    30  	"time"
    31  
    32  	"github.com/scroll-tech/go-ethereum/common"
    33  	"github.com/scroll-tech/go-ethereum/common/hexutil"
    34  	"github.com/scroll-tech/go-ethereum/consensus"
    35  	"github.com/scroll-tech/go-ethereum/core"
    36  	"github.com/scroll-tech/go-ethereum/core/rawdb"
    37  	"github.com/scroll-tech/go-ethereum/core/state"
    38  	"github.com/scroll-tech/go-ethereum/core/types"
    39  	"github.com/scroll-tech/go-ethereum/core/vm"
    40  	"github.com/scroll-tech/go-ethereum/ethdb"
    41  	"github.com/scroll-tech/go-ethereum/internal/ethapi"
    42  	"github.com/scroll-tech/go-ethereum/log"
    43  	"github.com/scroll-tech/go-ethereum/params"
    44  	"github.com/scroll-tech/go-ethereum/rlp"
    45  	"github.com/scroll-tech/go-ethereum/rollup/fees"
    46  	"github.com/scroll-tech/go-ethereum/rpc"
    47  )
    48  
    49  const (
    50  	// defaultTraceTimeout is the amount of time a single transaction can execute
    51  	// by default before being forcefully aborted.
    52  	defaultTraceTimeout = 5 * time.Second
    53  
    54  	// defaultTraceReexec is the number of blocks the tracer is willing to go back
    55  	// and reexecute to produce missing historical state necessary to run a specific
    56  	// trace.
    57  	defaultTraceReexec = uint64(128)
    58  
    59  	// defaultTracechainMemLimit is the size of the triedb, at which traceChain
    60  	// switches over and tries to use a disk-backed database instead of building
    61  	// on top of memory.
    62  	// For non-archive nodes, this limit _will_ be overblown, as disk-backed tries
    63  	// will only be found every ~15K blocks or so.
    64  	defaultTracechainMemLimit = common.StorageSize(500 * 1024 * 1024)
    65  )
    66  
    67  // Backend interface provides the common API services (that are provided by
    68  // both full and light clients) with access to necessary functions.
    69  type Backend interface {
    70  	HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error)
    71  	HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error)
    72  	BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error)
    73  	BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error)
    74  	GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error)
    75  	RPCGasCap() uint64
    76  	ChainConfig() *params.ChainConfig
    77  	CacheConfig() *core.CacheConfig
    78  	Engine() consensus.Engine
    79  	ChainDb() ethdb.Database
    80  	// StateAtBlock returns the state corresponding to the stateroot of the block.
    81  	// N.B: For executing transactions on block N, the required stateRoot is block N-1,
    82  	// so this method should be called with the parent.
    83  	StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, checkLive, preferDisk bool) (*state.StateDB, error)
    84  	StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, error)
    85  }
    86  
    87  // API is the collection of tracing APIs exposed over the private debugging endpoint.
    88  type API struct {
    89  	backend Backend
    90  }
    91  
    92  // NewAPI creates a new API definition for the tracing methods of the Ethereum service.
    93  func NewAPI(backend Backend) *API {
    94  	return &API{backend: backend}
    95  }
    96  
    97  type chainContext struct {
    98  	api *API
    99  	ctx context.Context
   100  }
   101  
   102  func (context *chainContext) Engine() consensus.Engine {
   103  	return context.api.backend.Engine()
   104  }
   105  
   106  func (context *chainContext) GetHeader(hash common.Hash, number uint64) *types.Header {
   107  	header, err := context.api.backend.HeaderByNumber(context.ctx, rpc.BlockNumber(number))
   108  	if err != nil {
   109  		return nil
   110  	}
   111  	if header.Hash() == hash {
   112  		return header
   113  	}
   114  	header, err = context.api.backend.HeaderByHash(context.ctx, hash)
   115  	if err != nil {
   116  		return nil
   117  	}
   118  	return header
   119  }
   120  
   121  // chainContext construts the context reader which is used by the evm for reading
   122  // the necessary chain context.
   123  func (api *API) chainContext(ctx context.Context) core.ChainContext {
   124  	return &chainContext{api: api, ctx: ctx}
   125  }
   126  
   127  // blockByNumber 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) blockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) {
   130  	block, err := api.backend.BlockByNumber(ctx, number)
   131  	if err != nil {
   132  		return nil, err
   133  	}
   134  	if block == nil {
   135  		return nil, fmt.Errorf("block #%d not found", number)
   136  	}
   137  	return block, nil
   138  }
   139  
   140  // blockByHash is the wrapper of the chain access function offered by the backend.
   141  // It will return an error if the block is not found.
   142  func (api *API) blockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) {
   143  	block, err := api.backend.BlockByHash(ctx, hash)
   144  	if err != nil {
   145  		return nil, err
   146  	}
   147  	if block == nil {
   148  		return nil, fmt.Errorf("block %s not found", hash.Hex())
   149  	}
   150  	return block, nil
   151  }
   152  
   153  // blockByNumberAndHash is the wrapper of the chain access function offered by
   154  // the backend. It will return an error if the block is not found.
   155  //
   156  // Note this function is friendly for the light client which can only retrieve the
   157  // historical(before the CHT) header/block by number.
   158  func (api *API) blockByNumberAndHash(ctx context.Context, number rpc.BlockNumber, hash common.Hash) (*types.Block, error) {
   159  	block, err := api.blockByNumber(ctx, number)
   160  	if err != nil {
   161  		return nil, err
   162  	}
   163  	if block.Hash() == hash {
   164  		return block, nil
   165  	}
   166  	return api.blockByHash(ctx, hash)
   167  }
   168  
   169  // TraceConfig holds extra parameters to trace functions.
   170  type TraceConfig struct {
   171  	*vm.LogConfig
   172  	Tracer  *string
   173  	Timeout *string
   174  	Reexec  *uint64
   175  }
   176  
   177  // TraceCallConfig is the config for traceCall API. It holds one more
   178  // field to override the state for tracing.
   179  type TraceCallConfig struct {
   180  	*vm.LogConfig
   181  	Tracer         *string
   182  	Timeout        *string
   183  	Reexec         *uint64
   184  	StateOverrides *ethapi.StateOverride
   185  }
   186  
   187  // StdTraceConfig holds extra parameters to standard-json trace functions.
   188  type StdTraceConfig struct {
   189  	vm.LogConfig
   190  	Reexec *uint64
   191  	TxHash common.Hash
   192  }
   193  
   194  // txTraceResult is the result of a single transaction trace.
   195  type txTraceResult struct {
   196  	Result interface{} `json:"result,omitempty"` // Trace results produced by the tracer
   197  	Error  string      `json:"error,omitempty"`  // Trace failure produced by the tracer
   198  }
   199  
   200  // blockTraceTask represents a single block trace task when an entire chain is
   201  // being traced.
   202  type blockTraceTask struct {
   203  	statedb *state.StateDB   // Intermediate state prepped for tracing
   204  	block   *types.Block     // Block to trace the transactions from
   205  	rootref common.Hash      // Trie root reference held for this task
   206  	results []*txTraceResult // Trace results procudes by the task
   207  }
   208  
   209  // blockTraceResult represets the results of tracing a single block when an entire
   210  // chain is being traced.
   211  type blockTraceResult struct {
   212  	Block  hexutil.Uint64   `json:"block"`  // Block number corresponding to this trace
   213  	Hash   common.Hash      `json:"hash"`   // Block hash corresponding to this trace
   214  	Traces []*txTraceResult `json:"traces"` // Trace results produced by the task
   215  }
   216  
   217  // txTraceTask represents a single transaction trace task when an entire block
   218  // is being traced.
   219  type txTraceTask struct {
   220  	statedb *state.StateDB // Intermediate state prepped for tracing
   221  	index   int            // Transaction offset in the block
   222  }
   223  
   224  // TraceChain returns the structured logs created during the execution of EVM
   225  // between two blocks (excluding start) and returns them as a JSON object.
   226  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
   227  	from, err := api.blockByNumber(ctx, start)
   228  	if err != nil {
   229  		return nil, err
   230  	}
   231  	to, err := api.blockByNumber(ctx, end)
   232  	if err != nil {
   233  		return nil, err
   234  	}
   235  	if from.Number().Cmp(to.Number()) >= 0 {
   236  		return nil, fmt.Errorf("end block (#%d) needs to come after start block (#%d)", end, start)
   237  	}
   238  	return api.traceChain(ctx, from, to, config)
   239  }
   240  
   241  // traceChain configures a new tracer according to the provided configuration, and
   242  // executes all the transactions contained within. The return value will be one item
   243  // per transaction, dependent on the requested tracer.
   244  func (api *API) traceChain(ctx context.Context, start, end *types.Block, config *TraceConfig) (*rpc.Subscription, error) {
   245  	// Tracing a chain is a **long** operation, only do with subscriptions
   246  	notifier, supported := rpc.NotifierFromContext(ctx)
   247  	if !supported {
   248  		return &rpc.Subscription{}, rpc.ErrNotificationsUnsupported
   249  	}
   250  	sub := notifier.CreateSubscription()
   251  
   252  	// Prepare all the states for tracing. Note this procedure can take very
   253  	// long time. Timeout mechanism is necessary.
   254  	reexec := defaultTraceReexec
   255  	if config != nil && config.Reexec != nil {
   256  		reexec = *config.Reexec
   257  	}
   258  	blocks := int(end.NumberU64() - start.NumberU64())
   259  	threads := runtime.NumCPU()
   260  	if threads > blocks {
   261  		threads = blocks
   262  	}
   263  	var (
   264  		pend     = new(sync.WaitGroup)
   265  		tasks    = make(chan *blockTraceTask, threads)
   266  		results  = make(chan *blockTraceTask, threads)
   267  		localctx = context.Background()
   268  	)
   269  	for th := 0; th < threads; th++ {
   270  		pend.Add(1)
   271  		go func() {
   272  			defer pend.Done()
   273  
   274  			// Fetch and execute the next block trace tasks
   275  			for task := range tasks {
   276  				signer := types.MakeSigner(api.backend.ChainConfig(), task.block.Number())
   277  				blockCtx := core.NewEVMBlockContext(task.block.Header(), api.chainContext(localctx), api.backend.ChainConfig(), nil)
   278  				// Trace all the transactions contained within
   279  				for i, tx := range task.block.Transactions() {
   280  					msg, _ := tx.AsMessage(signer, task.block.BaseFee())
   281  					txctx := &Context{
   282  						BlockHash: task.block.Hash(),
   283  						TxIndex:   i,
   284  						TxHash:    tx.Hash(),
   285  					}
   286  
   287  					l1DataFee, err := fees.CalculateL1DataFee(tx, task.statedb)
   288  					if err != nil {
   289  						// though it's not a "tracing error", we still need to put it here
   290  						task.results[i] = &txTraceResult{Error: err.Error()}
   291  						log.Warn("CalculateL1DataFee failed", "hash", tx.Hash(), "block", task.block.NumberU64(), "err", err)
   292  						break
   293  					}
   294  
   295  					res, err := api.traceTx(localctx, msg, txctx, blockCtx, task.statedb, config, l1DataFee)
   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 []byte, 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  // TraceBlockFromFile returns the structured logs created during the execution of
   475  // EVM and returns them as a JSON object.
   476  func (api *API) TraceBlockFromFile(ctx context.Context, file string, config *TraceConfig) ([]*txTraceResult, error) {
   477  	blob, err := ioutil.ReadFile(file)
   478  	if err != nil {
   479  		return nil, fmt.Errorf("could not read file: %v", err)
   480  	}
   481  	return api.TraceBlock(ctx, blob, config)
   482  }
   483  
   484  // TraceBadBlock returns the structured logs created during the execution of
   485  // EVM against a block pulled from the pool of bad ones and returns them as a JSON
   486  // object.
   487  func (api *API) TraceBadBlock(ctx context.Context, hash common.Hash, config *TraceConfig) ([]*txTraceResult, error) {
   488  	block := rawdb.ReadBadBlock(api.backend.ChainDb(), hash)
   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  // StandardTraceBlockToFile dumps the structured logs created during the
   496  // execution of EVM to the local file system and returns a list of files
   497  // to the caller.
   498  func (api *API) StandardTraceBlockToFile(ctx context.Context, hash common.Hash, config *StdTraceConfig) ([]string, error) {
   499  	block, err := api.blockByHash(ctx, hash)
   500  	if err != nil {
   501  		return nil, err
   502  	}
   503  	return api.standardTraceBlockToFile(ctx, block, config)
   504  }
   505  
   506  // IntermediateRoots executes a block (bad- or canon- or side-), and returns a list
   507  // of intermediate roots: the stateroot after each transaction.
   508  func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config *TraceConfig) ([]common.Hash, error) {
   509  	block, _ := api.blockByHash(ctx, hash)
   510  	if block == nil {
   511  		// Check in the bad blocks
   512  		block = rawdb.ReadBadBlock(api.backend.ChainDb(), hash)
   513  	}
   514  	if block == nil {
   515  		return nil, fmt.Errorf("block %#x not found", hash)
   516  	}
   517  	if block.NumberU64() == 0 {
   518  		return nil, errors.New("genesis is not traceable")
   519  	}
   520  	parent, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(block.NumberU64()-1), block.ParentHash())
   521  	if err != nil {
   522  		return nil, err
   523  	}
   524  	reexec := defaultTraceReexec
   525  	if config != nil && config.Reexec != nil {
   526  		reexec = *config.Reexec
   527  	}
   528  	statedb, err := api.backend.StateAtBlock(ctx, parent, reexec, nil, true, false)
   529  	if err != nil {
   530  		return nil, err
   531  	}
   532  	var (
   533  		roots              []common.Hash
   534  		signer             = types.MakeSigner(api.backend.ChainConfig(), block.Number())
   535  		chainConfig        = api.backend.ChainConfig()
   536  		vmctx              = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), api.backend.ChainConfig(), nil)
   537  		deleteEmptyObjects = chainConfig.IsEIP158(block.Number())
   538  	)
   539  	for i, tx := range block.Transactions() {
   540  		var (
   541  			msg, _    = tx.AsMessage(signer, block.BaseFee())
   542  			txContext = core.NewEVMTxContext(msg)
   543  			vmenv     = vm.NewEVM(vmctx, txContext, statedb, chainConfig, vm.Config{})
   544  		)
   545  		statedb.Prepare(tx.Hash(), i)
   546  
   547  		l1DataFee, err := fees.CalculateL1DataFee(tx, statedb)
   548  		if err != nil {
   549  			log.Warn("Tracing intermediate roots did not complete due to fees.CalculateL1DataFee", "txindex", i, "txhash", tx.Hash(), "err", err)
   550  			return nil, err
   551  		}
   552  
   553  		if _, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()), l1DataFee); err != nil {
   554  			log.Warn("Tracing intermediate roots did not complete", "txindex", i, "txhash", tx.Hash(), "err", err)
   555  			// We intentionally don't return the error here: if we do, then the RPC server will not
   556  			// return the roots. Most likely, the caller already knows that a certain transaction fails to
   557  			// be included, but still want the intermediate roots that led to that point.
   558  			// It may happen the tx_N causes an erroneous state, which in turn causes tx_N+M to not be
   559  			// executable.
   560  			// N.B: This should never happen while tracing canon blocks, only when tracing bad blocks.
   561  			return roots, nil
   562  		}
   563  		// calling IntermediateRoot will internally call Finalize on the state
   564  		// so any modifications are written to the trie
   565  		roots = append(roots, statedb.IntermediateRoot(deleteEmptyObjects))
   566  	}
   567  	return roots, nil
   568  }
   569  
   570  // StandardTraceBadBlockToFile dumps the structured logs created during the
   571  // execution of EVM against a block pulled from the pool of bad ones to the
   572  // local file system and returns a list of files to the caller.
   573  func (api *API) StandardTraceBadBlockToFile(ctx context.Context, hash common.Hash, config *StdTraceConfig) ([]string, error) {
   574  	block := rawdb.ReadBadBlock(api.backend.ChainDb(), hash)
   575  	if block == nil {
   576  		return nil, fmt.Errorf("bad block %#x not found", hash)
   577  	}
   578  	return api.standardTraceBlockToFile(ctx, block, config)
   579  }
   580  
   581  // traceBlock configures a new tracer according to the provided configuration, and
   582  // executes all the transactions contained within. The return value will be one item
   583  // per transaction, dependent on the requestd tracer.
   584  func (api *API) traceBlock(ctx context.Context, block *types.Block, config *TraceConfig) ([]*txTraceResult, error) {
   585  	if block.NumberU64() == 0 {
   586  		return nil, errors.New("genesis is not traceable")
   587  	}
   588  	parent, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(block.NumberU64()-1), block.ParentHash())
   589  	if err != nil {
   590  		return nil, err
   591  	}
   592  	reexec := defaultTraceReexec
   593  	if config != nil && config.Reexec != nil {
   594  		reexec = *config.Reexec
   595  	}
   596  	statedb, err := api.backend.StateAtBlock(ctx, parent, reexec, nil, true, false)
   597  	if err != nil {
   598  		return nil, err
   599  	}
   600  	// Execute all the transaction contained within the block concurrently
   601  	var (
   602  		signer  = types.MakeSigner(api.backend.ChainConfig(), block.Number())
   603  		txs     = block.Transactions()
   604  		results = make([]*txTraceResult, len(txs))
   605  
   606  		pend = new(sync.WaitGroup)
   607  		jobs = make(chan *txTraceTask, len(txs))
   608  	)
   609  	threads := runtime.NumCPU()
   610  	if threads > len(txs) {
   611  		threads = len(txs)
   612  	}
   613  	blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), api.backend.ChainConfig(), nil)
   614  	blockHash := block.Hash()
   615  	for th := 0; th < threads; th++ {
   616  		pend.Add(1)
   617  		go func() {
   618  			defer pend.Done()
   619  			// Fetch and execute the next transaction trace tasks
   620  			for task := range jobs {
   621  				msg, _ := txs[task.index].AsMessage(signer, block.BaseFee())
   622  				txctx := &Context{
   623  					BlockHash: blockHash,
   624  					TxIndex:   task.index,
   625  					TxHash:    txs[task.index].Hash(),
   626  				}
   627  
   628  				l1DataFee, err := fees.CalculateL1DataFee(txs[task.index], task.statedb)
   629  				if err != nil {
   630  					// though it's not a "tracing error", we still need to put it here
   631  					results[task.index] = &txTraceResult{Error: err.Error()}
   632  					continue
   633  				}
   634  				res, err := api.traceTx(ctx, msg, txctx, blockCtx, task.statedb, config, l1DataFee)
   635  				if err != nil {
   636  					results[task.index] = &txTraceResult{Error: err.Error()}
   637  					continue
   638  				}
   639  				results[task.index] = &txTraceResult{Result: res}
   640  			}
   641  		}()
   642  	}
   643  	// Feed the transactions into the tracers and return
   644  	var failed error
   645  	for i, tx := range txs {
   646  		// Send the trace task over for execution
   647  		jobs <- &txTraceTask{statedb: statedb.Copy(), index: i}
   648  
   649  		// Generate the next state snapshot fast without tracing
   650  		msg, _ := tx.AsMessage(signer, block.BaseFee())
   651  		statedb.Prepare(tx.Hash(), i)
   652  		vmenv := vm.NewEVM(blockCtx, core.NewEVMTxContext(msg), statedb, api.backend.ChainConfig(), vm.Config{})
   653  		l1DataFee, err := fees.CalculateL1DataFee(tx, statedb)
   654  		if err != nil {
   655  			failed = err
   656  			break
   657  		}
   658  		if _, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()), l1DataFee); err != nil {
   659  			failed = err
   660  			break
   661  		}
   662  		// Finalize the state so any modifications are written to the trie
   663  		// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
   664  		statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number()))
   665  	}
   666  	close(jobs)
   667  	pend.Wait()
   668  
   669  	// If execution failed in between, abort
   670  	if failed != nil {
   671  		return nil, failed
   672  	}
   673  	return results, nil
   674  }
   675  
   676  // standardTraceBlockToFile configures a new tracer which uses standard JSON output,
   677  // and traces either a full block or an individual transaction. The return value will
   678  // be one filename per transaction traced.
   679  func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block, config *StdTraceConfig) ([]string, error) {
   680  	// If we're tracing a single transaction, make sure it's present
   681  	if config != nil && config.TxHash != (common.Hash{}) {
   682  		if !containsTx(block, config.TxHash) {
   683  			return nil, fmt.Errorf("transaction %#x not found in block", config.TxHash)
   684  		}
   685  	}
   686  	if block.NumberU64() == 0 {
   687  		return nil, errors.New("genesis is not traceable")
   688  	}
   689  	parent, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(block.NumberU64()-1), block.ParentHash())
   690  	if err != nil {
   691  		return nil, err
   692  	}
   693  	reexec := defaultTraceReexec
   694  	if config != nil && config.Reexec != nil {
   695  		reexec = *config.Reexec
   696  	}
   697  	statedb, err := api.backend.StateAtBlock(ctx, parent, reexec, nil, true, false)
   698  	if err != nil {
   699  		return nil, err
   700  	}
   701  	// Retrieve the tracing configurations, or use default values
   702  	var (
   703  		logConfig vm.LogConfig
   704  		txHash    common.Hash
   705  	)
   706  	if config != nil {
   707  		logConfig = config.LogConfig
   708  		txHash = config.TxHash
   709  	}
   710  	logConfig.Debug = true
   711  
   712  	// Execute transaction, either tracing all or just the requested one
   713  	var (
   714  		dumps       []string
   715  		signer      = types.MakeSigner(api.backend.ChainConfig(), block.Number())
   716  		chainConfig = api.backend.ChainConfig()
   717  		vmctx       = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), api.backend.ChainConfig(), nil)
   718  		canon       = true
   719  	)
   720  	// Check if there are any overrides: the caller may wish to enable a future
   721  	// fork when executing this block. Note, such overrides are only applicable to the
   722  	// actual specified block, not any preceding blocks that we have to go through
   723  	// in order to obtain the state.
   724  	// Therefore, it's perfectly valid to specify `"futureForkBlock": 0`, to enable `futureFork`
   725  
   726  	if config != nil && config.Overrides != nil {
   727  		// Copy the config, to not screw up the main config
   728  		// Note: the Clique-part is _not_ deep copied
   729  		chainConfigCopy := new(params.ChainConfig)
   730  		*chainConfigCopy = *chainConfig
   731  		chainConfig = chainConfigCopy
   732  		if berlin := config.LogConfig.Overrides.BerlinBlock; berlin != nil {
   733  			chainConfig.BerlinBlock = berlin
   734  			canon = false
   735  		}
   736  	}
   737  	for i, tx := range block.Transactions() {
   738  		// Prepare the trasaction for un-traced execution
   739  		var (
   740  			msg, _    = tx.AsMessage(signer, block.BaseFee())
   741  			txContext = core.NewEVMTxContext(msg)
   742  			vmConf    vm.Config
   743  			dump      *os.File
   744  			writer    *bufio.Writer
   745  			err       error
   746  		)
   747  		// If the transaction needs tracing, swap out the configs
   748  		if tx.Hash() == txHash || txHash == (common.Hash{}) {
   749  			// Generate a unique temporary file to dump it into
   750  			prefix := fmt.Sprintf("block_%#x-%d-%#x-", block.Hash().Bytes()[:4], i, tx.Hash().Bytes()[:4])
   751  			if !canon {
   752  				prefix = fmt.Sprintf("%valt-", prefix)
   753  			}
   754  			dump, err = ioutil.TempFile(os.TempDir(), prefix)
   755  			if err != nil {
   756  				return nil, err
   757  			}
   758  			dumps = append(dumps, dump.Name())
   759  
   760  			// Swap out the noop logger to the standard tracer
   761  			writer = bufio.NewWriter(dump)
   762  			vmConf = vm.Config{
   763  				Debug:                   true,
   764  				Tracer:                  vm.NewJSONLogger(&logConfig, writer),
   765  				EnablePreimageRecording: true,
   766  			}
   767  		}
   768  		// Execute the transaction and flush any traces to disk
   769  		vmenv := vm.NewEVM(vmctx, txContext, statedb, chainConfig, vmConf)
   770  		statedb.Prepare(tx.Hash(), i)
   771  		l1DataFee, err := fees.CalculateL1DataFee(tx, statedb)
   772  		if err == nil {
   773  			_, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()), l1DataFee)
   774  		}
   775  		if writer != nil {
   776  			writer.Flush()
   777  		}
   778  		if dump != nil {
   779  			dump.Close()
   780  			log.Info("Wrote standard trace", "file", dump.Name())
   781  		}
   782  		if err != nil {
   783  			return dumps, err
   784  		}
   785  		// Finalize the state so any modifications are written to the trie
   786  		// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
   787  		statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number()))
   788  
   789  		// If we've traced the transaction we were looking for, abort
   790  		if tx.Hash() == txHash {
   791  			break
   792  		}
   793  	}
   794  	return dumps, nil
   795  }
   796  
   797  // containsTx reports whether the transaction with a certain hash
   798  // is contained within the specified block.
   799  func containsTx(block *types.Block, hash common.Hash) bool {
   800  	for _, tx := range block.Transactions() {
   801  		if tx.Hash() == hash {
   802  			return true
   803  		}
   804  	}
   805  	return false
   806  }
   807  
   808  // TraceTransaction returns the structured logs created during the execution of EVM
   809  // and returns them as a JSON object.
   810  func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config *TraceConfig) (interface{}, error) {
   811  	tx, blockHash, blockNumber, index, err := api.backend.GetTransaction(ctx, hash)
   812  	if err != nil {
   813  		return nil, err
   814  	}
   815  	// It shouldn't happen in practice.
   816  	if blockNumber == 0 {
   817  		return nil, errors.New("genesis is not traceable")
   818  	}
   819  	reexec := defaultTraceReexec
   820  	if config != nil && config.Reexec != nil {
   821  		reexec = *config.Reexec
   822  	}
   823  	block, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(blockNumber), blockHash)
   824  	if err != nil {
   825  		return nil, err
   826  	}
   827  	msg, vmctx, statedb, err := api.backend.StateAtTransaction(ctx, block, int(index), reexec)
   828  	if err != nil {
   829  		return nil, err
   830  	}
   831  	txctx := &Context{
   832  		BlockHash: blockHash,
   833  		TxIndex:   int(index),
   834  		TxHash:    hash,
   835  	}
   836  	l1DataFee, err := fees.CalculateL1DataFee(tx, statedb)
   837  	if err != nil {
   838  		return nil, err
   839  	}
   840  	return api.traceTx(ctx, msg, txctx, vmctx, statedb, config, l1DataFee)
   841  }
   842  
   843  // TraceCall lets you trace a given eth_call. It collects the structured logs
   844  // created during the execution of EVM if the given transaction was added on
   845  // top of the provided block and returns them as a JSON object.
   846  // You can provide -2 as a block number to trace on top of the pending block.
   847  func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, config *TraceCallConfig) (interface{}, error) {
   848  	// Try to retrieve the specified block
   849  	var (
   850  		err   error
   851  		block *types.Block
   852  	)
   853  	if hash, ok := blockNrOrHash.Hash(); ok {
   854  		block, err = api.blockByHash(ctx, hash)
   855  	} else if number, ok := blockNrOrHash.Number(); ok {
   856  		block, err = api.blockByNumber(ctx, number)
   857  	} else {
   858  		return nil, errors.New("invalid arguments; neither block nor hash specified")
   859  	}
   860  	if err != nil {
   861  		return nil, err
   862  	}
   863  	// try to recompute the state
   864  	reexec := defaultTraceReexec
   865  	if config != nil && config.Reexec != nil {
   866  		reexec = *config.Reexec
   867  	}
   868  	statedb, err := api.backend.StateAtBlock(ctx, block, reexec, nil, true, false)
   869  	if err != nil {
   870  		return nil, err
   871  	}
   872  	// Apply the customized state rules if required.
   873  	if config != nil {
   874  		if err := config.StateOverrides.Apply(statedb); err != nil {
   875  			return nil, err
   876  		}
   877  	}
   878  	// Execute the trace
   879  	msg, err := args.ToMessage(api.backend.RPCGasCap(), block.BaseFee())
   880  	if err != nil {
   881  		return nil, err
   882  	}
   883  	vmctx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), api.backend.ChainConfig(), nil)
   884  
   885  	var traceConfig *TraceConfig
   886  	if config != nil {
   887  		traceConfig = &TraceConfig{
   888  			LogConfig: config.LogConfig,
   889  			Tracer:    config.Tracer,
   890  			Timeout:   config.Timeout,
   891  			Reexec:    config.Reexec,
   892  		}
   893  	}
   894  
   895  	signer := types.MakeSigner(api.backend.ChainConfig(), block.Number())
   896  	l1DataFee, err := fees.EstimateL1DataFeeForMessage(msg, block.BaseFee(), api.backend.ChainConfig().ChainID, signer, statedb)
   897  	if err != nil {
   898  		return nil, err
   899  	}
   900  
   901  	return api.traceTx(ctx, msg, new(Context), vmctx, statedb, traceConfig, l1DataFee)
   902  }
   903  
   904  // traceTx configures a new tracer according to the provided configuration, and
   905  // executes the given message in the provided environment. The return value will
   906  // be tracer dependent.
   907  func (api *API) traceTx(ctx context.Context, message core.Message, txctx *Context, vmctx vm.BlockContext, statedb *state.StateDB, config *TraceConfig, l1DataFee *big.Int) (interface{}, error) {
   908  	// Assemble the structured logger or the JavaScript tracer
   909  	var (
   910  		tracer    vm.EVMLogger
   911  		err       error
   912  		txContext = core.NewEVMTxContext(message)
   913  	)
   914  	switch {
   915  	case config == nil:
   916  		tracer = vm.NewStructLogger(nil)
   917  	case config.Tracer != nil:
   918  		// Define a meaningful timeout of a single transaction trace
   919  		timeout := defaultTraceTimeout
   920  		if config.Timeout != nil {
   921  			if timeout, err = time.ParseDuration(*config.Timeout); err != nil {
   922  				return nil, err
   923  			}
   924  		}
   925  		if t, err := New(*config.Tracer, txctx); err != nil {
   926  			return nil, err
   927  		} else {
   928  			deadlineCtx, cancel := context.WithTimeout(ctx, timeout)
   929  			go func() {
   930  				<-deadlineCtx.Done()
   931  				if errors.Is(deadlineCtx.Err(), context.DeadlineExceeded) {
   932  					t.Stop(errors.New("execution timeout"))
   933  				}
   934  			}()
   935  			defer cancel()
   936  			tracer = t
   937  		}
   938  	default:
   939  		tracer = vm.NewStructLogger(config.LogConfig)
   940  	}
   941  	// Run the transaction with tracing enabled.
   942  	vmenv := vm.NewEVM(vmctx, txContext, statedb, api.backend.ChainConfig(), vm.Config{Debug: true, Tracer: tracer, NoBaseFee: true})
   943  
   944  	// If gasPrice is 0, make sure that the account has sufficient balance to cover `l1DataFee`.
   945  	if message.GasPrice().Cmp(big.NewInt(0)) == 0 {
   946  		statedb.AddBalance(message.From(), l1DataFee)
   947  	}
   948  
   949  	// Call Prepare to clear out the statedb access list
   950  	statedb.Prepare(txctx.TxHash, txctx.TxIndex)
   951  
   952  	result, err := core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas()), l1DataFee)
   953  	if err != nil {
   954  		return nil, fmt.Errorf("tracing failed: %w", err)
   955  	}
   956  
   957  	// Depending on the tracer type, format and return the output.
   958  	switch tracer := tracer.(type) {
   959  	case *vm.StructLogger:
   960  		// If the result contains a revert reason, return it.
   961  		returnVal := fmt.Sprintf("%x", result.Return())
   962  		if len(result.Revert()) > 0 {
   963  			returnVal = fmt.Sprintf("%x", result.Revert())
   964  		}
   965  		return &types.ExecutionResult{
   966  			Gas:         result.UsedGas,
   967  			Failed:      result.Failed(),
   968  			ReturnValue: returnVal,
   969  			StructLogs:  vm.FormatLogs(tracer.StructLogs()),
   970  			L1DataFee:   (*hexutil.Big)(result.L1DataFee),
   971  		}, nil
   972  
   973  	case Tracer:
   974  		return tracer.GetResult()
   975  
   976  	default:
   977  		panic(fmt.Sprintf("bad tracer type %T", tracer))
   978  	}
   979  }
   980  
   981  // APIs return the collection of RPC services the tracer package offers.
   982  func APIs(backend Backend) []rpc.API {
   983  	// Append all the local APIs and return
   984  	return []rpc.API{
   985  		{
   986  			Namespace: "debug",
   987  			Version:   "1.0",
   988  			Service:   NewAPI(backend),
   989  			Public:    false,
   990  		},
   991  		{
   992  			Namespace: "scroll",
   993  			Version:   "1.0",
   994  			Service:   TraceBlock(NewAPI(backend)),
   995  			Public:    true,
   996  		},
   997  	}
   998  }