github.com/palisadeinc/bor@v0.0.0-20230615125219-ab7196213d15/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/hex"
    24  	"errors"
    25  	"fmt"
    26  	"io/ioutil"
    27  	"math/big"
    28  	"os"
    29  	"path/filepath"
    30  	"runtime"
    31  	"sync"
    32  	"time"
    33  
    34  	"github.com/ethereum/go-ethereum"
    35  	"github.com/ethereum/go-ethereum/common"
    36  	"github.com/ethereum/go-ethereum/common/hexutil"
    37  	"github.com/ethereum/go-ethereum/consensus"
    38  	"github.com/ethereum/go-ethereum/consensus/bor/statefull"
    39  	"github.com/ethereum/go-ethereum/core"
    40  	"github.com/ethereum/go-ethereum/core/rawdb"
    41  	"github.com/ethereum/go-ethereum/core/state"
    42  	"github.com/ethereum/go-ethereum/core/types"
    43  	"github.com/ethereum/go-ethereum/core/vm"
    44  	"github.com/ethereum/go-ethereum/eth/tracers/logger"
    45  	"github.com/ethereum/go-ethereum/ethdb"
    46  	"github.com/ethereum/go-ethereum/internal/ethapi"
    47  	"github.com/ethereum/go-ethereum/log"
    48  	"github.com/ethereum/go-ethereum/params"
    49  	"github.com/ethereum/go-ethereum/rlp"
    50  	"github.com/ethereum/go-ethereum/rpc"
    51  )
    52  
    53  const (
    54  	// defaultTraceTimeout is the amount of time a single transaction can execute
    55  	// by default before being forcefully aborted.
    56  	defaultTraceTimeout = 5 * time.Second
    57  
    58  	// defaultTraceReexec is the number of blocks the tracer is willing to go back
    59  	// and reexecute to produce missing historical state necessary to run a specific
    60  	// trace.
    61  	defaultTraceReexec = uint64(128)
    62  
    63  	// defaultTracechainMemLimit is the size of the triedb, at which traceChain
    64  	// switches over and tries to use a disk-backed database instead of building
    65  	// on top of memory.
    66  	// For non-archive nodes, this limit _will_ be overblown, as disk-backed tries
    67  	// will only be found every ~15K blocks or so.
    68  	defaultTracechainMemLimit = common.StorageSize(500 * 1024 * 1024)
    69  
    70  	defaultPath = string(".")
    71  
    72  	defaultIOFlag = false
    73  )
    74  
    75  var defaultBorTraceEnabled = newBoolPtr(false)
    76  
    77  var allowIOTracing = false // Change this to true to enable IO tracing for debugging
    78  
    79  // Backend interface provides the common API services (that are provided by
    80  // both full and light clients) with access to necessary functions.
    81  type Backend interface {
    82  	HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error)
    83  	HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error)
    84  	BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error)
    85  	BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error)
    86  	GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error)
    87  	RPCGasCap() uint64
    88  	ChainConfig() *params.ChainConfig
    89  	Engine() consensus.Engine
    90  	ChainDb() ethdb.Database
    91  	// StateAtBlock returns the state corresponding to the stateroot of the block.
    92  	// N.B: For executing transactions on block N, the required stateRoot is block N-1,
    93  	// so this method should be called with the parent.
    94  	StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, checkLive, preferDisk bool) (*state.StateDB, error)
    95  	StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, error)
    96  
    97  	// Bor related APIs
    98  	GetBorBlockTransactionWithBlockHash(ctx context.Context, txHash common.Hash, blockHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error)
    99  }
   100  
   101  // API is the collection of tracing APIs exposed over the private debugging endpoint.
   102  type API struct {
   103  	backend Backend
   104  }
   105  
   106  // NewAPI creates a new API definition for the tracing methods of the Ethereum service.
   107  func NewAPI(backend Backend) *API {
   108  	return &API{backend: backend}
   109  }
   110  
   111  type chainContext struct {
   112  	api *API
   113  	ctx context.Context
   114  }
   115  
   116  func (context *chainContext) Engine() consensus.Engine {
   117  	return context.api.backend.Engine()
   118  }
   119  
   120  func (context *chainContext) GetHeader(hash common.Hash, number uint64) *types.Header {
   121  	header, err := context.api.backend.HeaderByNumber(context.ctx, rpc.BlockNumber(number))
   122  	if err != nil {
   123  		return nil
   124  	}
   125  	if header.Hash() == hash {
   126  		return header
   127  	}
   128  	header, err = context.api.backend.HeaderByHash(context.ctx, hash)
   129  	if err != nil {
   130  		return nil
   131  	}
   132  	return header
   133  }
   134  
   135  // chainContext construts the context reader which is used by the evm for reading
   136  // the necessary chain context.
   137  func (api *API) chainContext(ctx context.Context) core.ChainContext {
   138  	return &chainContext{api: api, ctx: ctx}
   139  }
   140  
   141  // blockByNumber is the wrapper of the chain access function offered by the backend.
   142  // It will return an error if the block is not found.
   143  func (api *API) blockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) {
   144  	block, err := api.backend.BlockByNumber(ctx, number)
   145  	if err != nil {
   146  		return nil, err
   147  	}
   148  	if block == nil {
   149  		return nil, fmt.Errorf("block #%d not found", number)
   150  	}
   151  	return block, nil
   152  }
   153  
   154  // blockByHash is the wrapper of the chain access function offered by the backend.
   155  // It will return an error if the block is not found.
   156  func (api *API) blockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) {
   157  	block, err := api.backend.BlockByHash(ctx, hash)
   158  	if err != nil {
   159  		return nil, err
   160  	}
   161  	if block == nil {
   162  		return nil, fmt.Errorf("block %s not found", hash.Hex())
   163  	}
   164  	return block, nil
   165  }
   166  
   167  // blockByNumberAndHash is the wrapper of the chain access function offered by
   168  // the backend. It will return an error if the block is not found.
   169  //
   170  // Note this function is friendly for the light client which can only retrieve the
   171  // historical(before the CHT) header/block by number.
   172  func (api *API) blockByNumberAndHash(ctx context.Context, number rpc.BlockNumber, hash common.Hash) (*types.Block, error) {
   173  	block, err := api.blockByNumber(ctx, number)
   174  	if err != nil {
   175  		return nil, err
   176  	}
   177  	if block.Hash() == hash {
   178  		return block, nil
   179  	}
   180  	return api.blockByHash(ctx, hash)
   181  }
   182  
   183  // returns block transactions along with state-sync transaction if present
   184  func (api *API) getAllBlockTransactions(ctx context.Context, block *types.Block) (types.Transactions, bool) {
   185  	txs := block.Transactions()
   186  
   187  	stateSyncPresent := false
   188  
   189  	borReceipt := rawdb.ReadBorReceipt(api.backend.ChainDb(), block.Hash(), block.NumberU64(), api.backend.ChainConfig())
   190  	if borReceipt != nil {
   191  		txHash := types.GetDerivedBorTxHash(types.BorReceiptKey(block.Number().Uint64(), block.Hash()))
   192  		if txHash != (common.Hash{}) {
   193  			borTx, _, _, _, _ := api.backend.GetBorBlockTransactionWithBlockHash(ctx, txHash, block.Hash())
   194  			txs = append(txs, borTx)
   195  			stateSyncPresent = true
   196  		}
   197  	}
   198  
   199  	return txs, stateSyncPresent
   200  }
   201  
   202  // TraceConfig holds extra parameters to trace functions.
   203  type TraceConfig struct {
   204  	*logger.Config
   205  	Tracer          *string
   206  	Timeout         *string
   207  	Reexec          *uint64
   208  	Path            *string
   209  	IOFlag          *bool
   210  	BorTraceEnabled *bool
   211  	BorTx           *bool
   212  }
   213  
   214  // TraceCallConfig is the config for traceCall API. It holds one more
   215  // field to override the state for tracing.
   216  type TraceCallConfig struct {
   217  	*logger.Config
   218  	Tracer         *string
   219  	Timeout        *string
   220  	Reexec         *uint64
   221  	StateOverrides *ethapi.StateOverride
   222  }
   223  
   224  // StdTraceConfig holds extra parameters to standard-json trace functions.
   225  type StdTraceConfig struct {
   226  	logger.Config
   227  	Reexec          *uint64
   228  	TxHash          common.Hash
   229  	BorTraceEnabled *bool
   230  }
   231  
   232  // txTraceResult is the result of a single transaction trace.
   233  type txTraceResult struct {
   234  	Result interface{} `json:"result,omitempty"` // Trace results produced by the tracer
   235  	Error  string      `json:"error,omitempty"`  // Trace failure produced by the tracer
   236  }
   237  
   238  // blockTraceTask represents a single block trace task when an entire chain is
   239  // being traced.
   240  type blockTraceTask struct {
   241  	statedb *state.StateDB   // Intermediate state prepped for tracing
   242  	block   *types.Block     // Block to trace the transactions from
   243  	rootref common.Hash      // Trie root reference held for this task
   244  	results []*txTraceResult // Trace results procudes by the task
   245  }
   246  
   247  // blockTraceResult represets the results of tracing a single block when an entire
   248  // chain is being traced.
   249  type blockTraceResult struct {
   250  	Block  hexutil.Uint64   `json:"block"`  // Block number corresponding to this trace
   251  	Hash   common.Hash      `json:"hash"`   // Block hash corresponding to this trace
   252  	Traces []*txTraceResult `json:"traces"` // Trace results produced by the task
   253  }
   254  
   255  // txTraceTask represents a single transaction trace task when an entire block
   256  // is being traced.
   257  type txTraceTask struct {
   258  	statedb *state.StateDB // Intermediate state prepped for tracing
   259  	index   int            // Transaction offset in the block
   260  }
   261  
   262  // TraceChain returns the structured logs created during the execution of EVM
   263  // between two blocks (excluding start) and returns them as a JSON object.
   264  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
   265  	from, err := api.blockByNumber(ctx, start)
   266  	if err != nil {
   267  		return nil, err
   268  	}
   269  	to, err := api.blockByNumber(ctx, end)
   270  	if err != nil {
   271  		return nil, err
   272  	}
   273  	if from.Number().Cmp(to.Number()) >= 0 {
   274  		return nil, fmt.Errorf("end block (#%d) needs to come after start block (#%d)", end, start)
   275  	}
   276  	return api.traceChain(ctx, from, to, config)
   277  }
   278  
   279  // traceChain configures a new tracer according to the provided configuration, and
   280  // executes all the transactions contained within. The return value will be one item
   281  // per transaction, dependent on the requested tracer.
   282  func (api *API) traceChain(ctx context.Context, start, end *types.Block, config *TraceConfig) (*rpc.Subscription, error) {
   283  	if config == nil {
   284  		config = &TraceConfig{
   285  			BorTraceEnabled: defaultBorTraceEnabled,
   286  			BorTx:           newBoolPtr(false),
   287  		}
   288  	}
   289  
   290  	if config.BorTraceEnabled == nil {
   291  		config.BorTraceEnabled = defaultBorTraceEnabled
   292  	}
   293  	// Tracing a chain is a **long** operation, only do with subscriptions
   294  	notifier, supported := rpc.NotifierFromContext(ctx)
   295  	if !supported {
   296  		return &rpc.Subscription{}, rpc.ErrNotificationsUnsupported
   297  	}
   298  	sub := notifier.CreateSubscription()
   299  
   300  	// Prepare all the states for tracing. Note this procedure can take very
   301  	// long time. Timeout mechanism is necessary.
   302  	reexec := defaultTraceReexec
   303  	if config != nil && config.Reexec != nil {
   304  		reexec = *config.Reexec
   305  	}
   306  	blocks := int(end.NumberU64() - start.NumberU64())
   307  	threads := runtime.NumCPU()
   308  	if threads > blocks {
   309  		threads = blocks
   310  	}
   311  	var (
   312  		pend     = new(sync.WaitGroup)
   313  		tasks    = make(chan *blockTraceTask, threads)
   314  		results  = make(chan *blockTraceTask, threads)
   315  		localctx = context.Background()
   316  	)
   317  	for th := 0; th < threads; th++ {
   318  		pend.Add(1)
   319  		go func() {
   320  			defer pend.Done()
   321  
   322  			// Fetch and execute the next block trace tasks
   323  			for task := range tasks {
   324  				signer := types.MakeSigner(api.backend.ChainConfig(), task.block.Number())
   325  				blockCtx := core.NewEVMBlockContext(task.block.Header(), api.chainContext(localctx), nil)
   326  				// Trace all the transactions contained within
   327  				txs, stateSyncPresent := api.getAllBlockTransactions(ctx, task.block)
   328  				if !*config.BorTraceEnabled && stateSyncPresent {
   329  					txs = txs[:len(txs)-1]
   330  					stateSyncPresent = false
   331  				}
   332  
   333  				for i, tx := range txs {
   334  					msg, _ := tx.AsMessage(signer, task.block.BaseFee())
   335  					txctx := &Context{
   336  						BlockHash: task.block.Hash(),
   337  						TxIndex:   i,
   338  						TxHash:    tx.Hash(),
   339  					}
   340  
   341  					var res interface{}
   342  
   343  					var err error
   344  
   345  					if stateSyncPresent && i == len(txs)-1 {
   346  						if *config.BorTraceEnabled {
   347  							config.BorTx = newBoolPtr(true)
   348  							res, err = api.traceTx(localctx, msg, txctx, blockCtx, task.statedb, config)
   349  						}
   350  					} else {
   351  						res, err = api.traceTx(localctx, msg, txctx, blockCtx, task.statedb, config)
   352  					}
   353  
   354  					if err != nil {
   355  						task.results[i] = &txTraceResult{Error: err.Error()}
   356  						log.Warn("Tracing failed", "hash", tx.Hash(), "block", task.block.NumberU64(), "err", err)
   357  						break
   358  					}
   359  
   360  					// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
   361  					task.statedb.Finalise(api.backend.ChainConfig().IsEIP158(task.block.Number()))
   362  					task.results[i] = &txTraceResult{Result: res}
   363  				}
   364  				// Stream the result back to the user or abort on teardown
   365  				select {
   366  				case results <- task:
   367  				case <-notifier.Closed():
   368  					return
   369  				}
   370  			}
   371  		}()
   372  	}
   373  	// Start a goroutine to feed all the blocks into the tracers
   374  	var (
   375  		begin     = time.Now()
   376  		derefTodo []common.Hash // list of hashes to dereference from the db
   377  		derefsMu  sync.Mutex    // mutex for the derefs
   378  	)
   379  
   380  	go func() {
   381  		var (
   382  			logged  time.Time
   383  			number  uint64
   384  			traced  uint64
   385  			failed  error
   386  			parent  common.Hash
   387  			statedb *state.StateDB
   388  		)
   389  		// Ensure everything is properly cleaned up on any exit path
   390  		defer func() {
   391  			close(tasks)
   392  			pend.Wait()
   393  
   394  			switch {
   395  			case failed != nil:
   396  				log.Warn("Chain tracing failed", "start", start.NumberU64(), "end", end.NumberU64(), "transactions", traced, "elapsed", time.Since(begin), "err", failed)
   397  			case number < end.NumberU64():
   398  				log.Warn("Chain tracing aborted", "start", start.NumberU64(), "end", end.NumberU64(), "abort", number, "transactions", traced, "elapsed", time.Since(begin))
   399  			default:
   400  				log.Info("Chain tracing finished", "start", start.NumberU64(), "end", end.NumberU64(), "transactions", traced, "elapsed", time.Since(begin))
   401  			}
   402  			close(results)
   403  		}()
   404  		var preferDisk bool
   405  		// Feed all the blocks both into the tracer, as well as fast process concurrently
   406  		for number = start.NumberU64(); number < end.NumberU64(); number++ {
   407  			// Stop tracing if interruption was requested
   408  			select {
   409  			case <-notifier.Closed():
   410  				return
   411  			default:
   412  			}
   413  			// clean out any derefs
   414  			derefsMu.Lock()
   415  			for _, h := range derefTodo {
   416  				statedb.Database().TrieDB().Dereference(h)
   417  			}
   418  			derefTodo = derefTodo[:0]
   419  			derefsMu.Unlock()
   420  
   421  			// Print progress logs if long enough time elapsed
   422  			if time.Since(logged) > 8*time.Second {
   423  				logged = time.Now()
   424  				log.Info("Tracing chain segment", "start", start.NumberU64(), "end", end.NumberU64(), "current", number, "transactions", traced, "elapsed", time.Since(begin))
   425  			}
   426  			// Retrieve the parent state to trace on top
   427  			block, err := api.blockByNumber(localctx, rpc.BlockNumber(number))
   428  			if err != nil {
   429  				failed = err
   430  				break
   431  			}
   432  			// Prepare the statedb for tracing. Don't use the live database for
   433  			// tracing to avoid persisting state junks into the database.
   434  			statedb, err = api.backend.StateAtBlock(localctx, block, reexec, statedb, false, preferDisk)
   435  			if err != nil {
   436  				failed = err
   437  				break
   438  			}
   439  			if trieDb := statedb.Database().TrieDB(); trieDb != nil {
   440  				// Hold the reference for tracer, will be released at the final stage
   441  				trieDb.Reference(block.Root(), common.Hash{})
   442  
   443  				// Release the parent state because it's already held by the tracer
   444  				if parent != (common.Hash{}) {
   445  					trieDb.Dereference(parent)
   446  				}
   447  				// Prefer disk if the trie db memory grows too much
   448  				s1, s2 := trieDb.Size()
   449  				if !preferDisk && (s1+s2) > defaultTracechainMemLimit {
   450  					log.Info("Switching to prefer-disk mode for tracing", "size", s1+s2)
   451  					preferDisk = true
   452  				}
   453  			}
   454  			parent = block.Root()
   455  
   456  			next, err := api.blockByNumber(localctx, rpc.BlockNumber(number+1))
   457  			if err != nil {
   458  				failed = err
   459  				break
   460  			}
   461  			// Send the block over to the concurrent tracers (if not in the fast-forward phase)
   462  			txs := next.Transactions()
   463  			select {
   464  			case tasks <- &blockTraceTask{statedb: statedb.Copy(), block: next, rootref: block.Root(), results: make([]*txTraceResult, len(txs))}:
   465  			case <-notifier.Closed():
   466  				return
   467  			}
   468  			traced += uint64(len(txs))
   469  		}
   470  	}()
   471  
   472  	// Keep reading the trace results and stream the to the user
   473  	go func() {
   474  		var (
   475  			done = make(map[uint64]*blockTraceResult)
   476  			next = start.NumberU64() + 1
   477  		)
   478  		for res := range results {
   479  			// Queue up next received result
   480  			result := &blockTraceResult{
   481  				Block:  hexutil.Uint64(res.block.NumberU64()),
   482  				Hash:   res.block.Hash(),
   483  				Traces: res.results,
   484  			}
   485  			// Schedule any parent tries held in memory by this task for dereferencing
   486  			done[uint64(result.Block)] = result
   487  			derefsMu.Lock()
   488  			derefTodo = append(derefTodo, res.rootref)
   489  			derefsMu.Unlock()
   490  			// Stream completed traces to the user, aborting on the first error
   491  			for result, ok := done[next]; ok; result, ok = done[next] {
   492  				if len(result.Traces) > 0 || next == end.NumberU64() {
   493  					notifier.Notify(sub.ID, result)
   494  				}
   495  				delete(done, next)
   496  				next++
   497  			}
   498  		}
   499  	}()
   500  	return sub, nil
   501  }
   502  
   503  func newBoolPtr(bb bool) *bool {
   504  	b := bb
   505  	return &b
   506  }
   507  
   508  // TraceBlockByNumber returns the structured logs created during the execution of
   509  // EVM and returns them as a JSON object.
   510  func (api *API) TraceBlockByNumber(ctx context.Context, number rpc.BlockNumber, config *TraceConfig) ([]*txTraceResult, error) {
   511  	block, err := api.blockByNumber(ctx, number)
   512  	if err != nil {
   513  		return nil, err
   514  	}
   515  	return api.traceBlock(ctx, block, config)
   516  }
   517  
   518  // TraceBlockByHash returns the structured logs created during the execution of
   519  // EVM and returns them as a JSON object.
   520  func (api *API) TraceBlockByHash(ctx context.Context, hash common.Hash, config *TraceConfig) ([]*txTraceResult, error) {
   521  	block, err := api.blockByHash(ctx, hash)
   522  	if err != nil {
   523  		return nil, err
   524  	}
   525  	return api.traceBlock(ctx, block, config)
   526  }
   527  
   528  // TraceBlock returns the structured logs created during the execution of EVM
   529  // and returns them as a JSON object.
   530  func (api *API) TraceBlock(ctx context.Context, blob hexutil.Bytes, config *TraceConfig) ([]*txTraceResult, error) {
   531  	block := new(types.Block)
   532  	if err := rlp.Decode(bytes.NewReader(blob), block); err != nil {
   533  		return nil, fmt.Errorf("could not decode block: %v", err)
   534  	}
   535  	return api.traceBlock(ctx, block, config)
   536  }
   537  
   538  // TraceBlockFromFile returns the structured logs created during the execution of
   539  // EVM and returns them as a JSON object.
   540  func (api *API) TraceBlockFromFile(ctx context.Context, file string, config *TraceConfig) ([]*txTraceResult, error) {
   541  	blob, err := ioutil.ReadFile(file)
   542  	if err != nil {
   543  		return nil, fmt.Errorf("could not read file: %v", err)
   544  	}
   545  	return api.TraceBlock(ctx, blob, config)
   546  }
   547  
   548  // TraceBadBlock returns the structured logs created during the execution of
   549  // EVM against a block pulled from the pool of bad ones and returns them as a JSON
   550  // object.
   551  func (api *API) TraceBadBlock(ctx context.Context, hash common.Hash, config *TraceConfig) ([]*txTraceResult, error) {
   552  	block := rawdb.ReadBadBlock(api.backend.ChainDb(), hash)
   553  	if block == nil {
   554  		return nil, fmt.Errorf("bad block %#x not found", hash)
   555  	}
   556  	return api.traceBlock(ctx, block, config)
   557  }
   558  
   559  // StandardTraceBlockToFile dumps the structured logs created during the
   560  // execution of EVM to the local file system and returns a list of files
   561  // to the caller.
   562  func (api *API) StandardTraceBlockToFile(ctx context.Context, hash common.Hash, config *StdTraceConfig) ([]string, error) {
   563  	block, err := api.blockByHash(ctx, hash)
   564  	if err != nil {
   565  		return nil, err
   566  	}
   567  	return api.standardTraceBlockToFile(ctx, block, config)
   568  }
   569  
   570  func prepareCallMessage(msg core.Message) statefull.Callmsg {
   571  	return statefull.Callmsg{
   572  		CallMsg: ethereum.CallMsg{
   573  			From:       msg.From(),
   574  			To:         msg.To(),
   575  			Gas:        msg.Gas(),
   576  			GasPrice:   msg.GasPrice(),
   577  			GasFeeCap:  msg.GasFeeCap(),
   578  			GasTipCap:  msg.GasTipCap(),
   579  			Value:      msg.Value(),
   580  			Data:       msg.Data(),
   581  			AccessList: msg.AccessList(),
   582  		}}
   583  }
   584  
   585  // IntermediateRoots executes a block (bad- or canon- or side-), and returns a list
   586  // of intermediate roots: the stateroot after each transaction.
   587  func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config *TraceConfig) ([]common.Hash, error) {
   588  	if config == nil {
   589  		config = &TraceConfig{
   590  			BorTraceEnabled: defaultBorTraceEnabled,
   591  			BorTx:           newBoolPtr(false),
   592  		}
   593  	}
   594  
   595  	if config.BorTraceEnabled == nil {
   596  		config.BorTraceEnabled = defaultBorTraceEnabled
   597  	}
   598  
   599  	block, _ := api.blockByHash(ctx, hash)
   600  	if block == nil {
   601  		// Check in the bad blocks
   602  		block = rawdb.ReadBadBlock(api.backend.ChainDb(), hash)
   603  	}
   604  	if block == nil {
   605  		return nil, fmt.Errorf("block %#x not found", hash)
   606  	}
   607  	if block.NumberU64() == 0 {
   608  		return nil, errors.New("genesis is not traceable")
   609  	}
   610  	parent, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(block.NumberU64()-1), block.ParentHash())
   611  	if err != nil {
   612  		return nil, err
   613  	}
   614  	reexec := defaultTraceReexec
   615  	if config != nil && config.Reexec != nil {
   616  		reexec = *config.Reexec
   617  	}
   618  	statedb, err := api.backend.StateAtBlock(ctx, parent, reexec, nil, true, false)
   619  	if err != nil {
   620  		return nil, err
   621  	}
   622  	var (
   623  		roots              []common.Hash
   624  		signer             = types.MakeSigner(api.backend.ChainConfig(), block.Number())
   625  		chainConfig        = api.backend.ChainConfig()
   626  		vmctx              = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
   627  		deleteEmptyObjects = chainConfig.IsEIP158(block.Number())
   628  	)
   629  
   630  	txs, stateSyncPresent := api.getAllBlockTransactions(ctx, block)
   631  	for i, tx := range txs {
   632  		var (
   633  			msg, _    = tx.AsMessage(signer, block.BaseFee())
   634  			txContext = core.NewEVMTxContext(msg)
   635  			vmenv     = vm.NewEVM(vmctx, txContext, statedb, chainConfig, vm.Config{})
   636  		)
   637  		statedb.Prepare(tx.Hash(), i)
   638  		//nolint: nestif
   639  		if stateSyncPresent && i == len(txs)-1 {
   640  			if *config.BorTraceEnabled {
   641  				callmsg := prepareCallMessage(msg)
   642  
   643  				if _, err := statefull.ApplyMessage(ctx, callmsg, statedb, block.Header(), api.backend.ChainConfig(), api.chainContext(ctx)); err != nil {
   644  					log.Warn("Tracing intermediate roots did not complete", "txindex", i, "txhash", tx.Hash(), "err", err)
   645  					// We intentionally don't return the error here: if we do, then the RPC server will not
   646  					// return the roots. Most likely, the caller already knows that a certain transaction fails to
   647  					// be included, but still want the intermediate roots that led to that point.
   648  					// It may happen the tx_N causes an erroneous state, which in turn causes tx_N+M to not be
   649  					// executable.
   650  					// N.B: This should never happen while tracing canon blocks, only when tracing bad blocks.
   651  					return roots, nil
   652  				}
   653  			} else {
   654  				break
   655  			}
   656  		} else {
   657  			// nolint : contextcheck
   658  			if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()), context.Background()); err != nil {
   659  				log.Warn("Tracing intermediate roots did not complete", "txindex", i, "txhash", tx.Hash(), "err", err)
   660  				// We intentionally don't return the error here: if we do, then the RPC server will not
   661  				// return the roots. Most likely, the caller already knows that a certain transaction fails to
   662  				// be included, but still want the intermediate roots that led to that point.
   663  				// It may happen the tx_N causes an erroneous state, which in turn causes tx_N+M to not be
   664  				// executable.
   665  				// N.B: This should never happen while tracing canon blocks, only when tracing bad blocks.
   666  				return roots, nil
   667  			}
   668  
   669  		}
   670  
   671  		// calling IntermediateRoot will internally call Finalize on the state
   672  		// so any modifications are written to the trie
   673  		roots = append(roots, statedb.IntermediateRoot(deleteEmptyObjects))
   674  	}
   675  	return roots, nil
   676  }
   677  
   678  // StandardTraceBadBlockToFile dumps the structured logs created during the
   679  // execution of EVM against a block pulled from the pool of bad ones to the
   680  // local file system and returns a list of files to the caller.
   681  func (api *API) StandardTraceBadBlockToFile(ctx context.Context, hash common.Hash, config *StdTraceConfig) ([]string, error) {
   682  	block := rawdb.ReadBadBlock(api.backend.ChainDb(), hash)
   683  	if block == nil {
   684  		return nil, fmt.Errorf("bad block %#x not found", hash)
   685  	}
   686  	return api.standardTraceBlockToFile(ctx, block, config)
   687  }
   688  
   689  // traceBlock configures a new tracer according to the provided configuration, and
   690  // executes all the transactions contained within. The return value will be one item
   691  // per transaction, dependent on the requestd tracer.
   692  func (api *API) traceBlock(ctx context.Context, block *types.Block, config *TraceConfig) ([]*txTraceResult, error) {
   693  
   694  	if config == nil {
   695  		config = &TraceConfig{
   696  			BorTraceEnabled: defaultBorTraceEnabled,
   697  			BorTx:           newBoolPtr(false),
   698  		}
   699  	}
   700  
   701  	if config.BorTraceEnabled == nil {
   702  		config.BorTraceEnabled = defaultBorTraceEnabled
   703  	}
   704  
   705  	if block.NumberU64() == 0 {
   706  		return nil, errors.New("genesis is not traceable")
   707  	}
   708  
   709  	parent, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(block.NumberU64()-1), block.ParentHash())
   710  	if err != nil {
   711  		return nil, err
   712  	}
   713  
   714  	reexec := defaultTraceReexec
   715  	if config != nil && config.Reexec != nil {
   716  		reexec = *config.Reexec
   717  	}
   718  
   719  	path := defaultPath
   720  	if config != nil && config.Path != nil {
   721  		path = *config.Path
   722  	}
   723  
   724  	ioflag := defaultIOFlag
   725  	if allowIOTracing && config != nil && config.IOFlag != nil {
   726  		ioflag = *config.IOFlag
   727  	}
   728  
   729  	statedb, err := api.backend.StateAtBlock(ctx, parent, reexec, nil, true, false)
   730  	if err != nil {
   731  		return nil, err
   732  	}
   733  
   734  	// create and add empty mvHashMap in statedb as StateAtBlock does not have mvHashmap in it.
   735  	if ioflag {
   736  		statedb.AddEmptyMVHashMap()
   737  	}
   738  
   739  	// Execute all the transaction contained within the block concurrently
   740  	var (
   741  		signer                = types.MakeSigner(api.backend.ChainConfig(), block.Number())
   742  		txs, stateSyncPresent = api.getAllBlockTransactions(ctx, block)
   743  		results               = make([]*txTraceResult, len(txs))
   744  
   745  		pend = new(sync.WaitGroup)
   746  		jobs = make(chan *txTraceTask, len(txs))
   747  	)
   748  	threads := runtime.NumCPU()
   749  	if threads > len(txs) {
   750  		threads = len(txs)
   751  	}
   752  	blockHash := block.Hash()
   753  	for th := 0; th < threads; th++ {
   754  		pend.Add(1)
   755  		go func() {
   756  			blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
   757  			defer pend.Done()
   758  			// Fetch and execute the next transaction trace tasks
   759  			for task := range jobs {
   760  				msg, _ := txs[task.index].AsMessage(signer, block.BaseFee())
   761  				txctx := &Context{
   762  					BlockHash: blockHash,
   763  					TxIndex:   task.index,
   764  					TxHash:    txs[task.index].Hash(),
   765  				}
   766  
   767  				var res interface{}
   768  
   769  				var err error
   770  
   771  				if stateSyncPresent && task.index == len(txs)-1 {
   772  					if *config.BorTraceEnabled {
   773  						config.BorTx = newBoolPtr(true)
   774  						res, err = api.traceTx(ctx, msg, txctx, blockCtx, task.statedb, config)
   775  					} else {
   776  						break
   777  					}
   778  				} else {
   779  					res, err = api.traceTx(ctx, msg, txctx, blockCtx, task.statedb, config)
   780  				}
   781  				if err != nil {
   782  					results[task.index] = &txTraceResult{Error: err.Error()}
   783  					continue
   784  				}
   785  				results[task.index] = &txTraceResult{Result: res}
   786  			}
   787  		}()
   788  	}
   789  
   790  	var IOdump string
   791  
   792  	var RWstruct []state.DumpStruct
   793  
   794  	var london bool
   795  
   796  	if ioflag {
   797  		IOdump = "TransactionIndex, Incarnation, VersionTxIdx, VersionInc, Path, Operation\n"
   798  		RWstruct = []state.DumpStruct{}
   799  	}
   800  	// Feed the transactions into the tracers and return
   801  	var failed error
   802  	blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
   803  
   804  	if ioflag {
   805  		london = api.backend.ChainConfig().IsLondon(block.Number())
   806  	}
   807  
   808  	for i, tx := range txs {
   809  		if ioflag {
   810  			// copy of statedb
   811  			statedb = statedb.Copy()
   812  		}
   813  
   814  		// Send the trace task over for execution
   815  		jobs <- &txTraceTask{statedb: statedb.Copy(), index: i}
   816  
   817  		// Generate the next state snapshot fast without tracing
   818  		msg, _ := tx.AsMessage(signer, block.BaseFee())
   819  		statedb.Prepare(tx.Hash(), i)
   820  
   821  		vmenv := vm.NewEVM(blockCtx, core.NewEVMTxContext(msg), statedb, api.backend.ChainConfig(), vm.Config{})
   822  
   823  		// nolint: nestif
   824  		if !ioflag {
   825  			//nolint: nestif
   826  			if stateSyncPresent && i == len(txs)-1 {
   827  				if *config.BorTraceEnabled {
   828  					callmsg := prepareCallMessage(msg)
   829  					// nolint : contextcheck
   830  					if _, err := statefull.ApplyBorMessage(*vmenv, callmsg); err != nil {
   831  						failed = err
   832  						break
   833  					}
   834  				} else {
   835  					break
   836  				}
   837  			} else {
   838  				// nolint : contextcheck
   839  				if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()), context.Background()); err != nil {
   840  					failed = err
   841  					break
   842  				}
   843  				// Finalize the state so any modifications are written to the trie
   844  				// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
   845  				statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number()))
   846  			}
   847  		} else {
   848  			coinbaseBalance := statedb.GetBalance(blockCtx.Coinbase)
   849  			// nolint : contextcheck
   850  			result, err := core.ApplyMessageNoFeeBurnOrTip(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()), context.Background())
   851  
   852  			if err != nil {
   853  				failed = err
   854  				break
   855  			}
   856  
   857  			if london {
   858  				statedb.AddBalance(result.BurntContractAddress, result.FeeBurnt)
   859  			}
   860  
   861  			statedb.AddBalance(blockCtx.Coinbase, result.FeeTipped)
   862  			output1 := new(big.Int).SetBytes(result.SenderInitBalance.Bytes())
   863  			output2 := new(big.Int).SetBytes(coinbaseBalance.Bytes())
   864  
   865  			// Deprecating transfer log and will be removed in future fork. PLEASE DO NOT USE this transfer log going forward. Parameters won't get updated as expected going forward with EIP1559
   866  			// add transfer log
   867  			core.AddFeeTransferLog(
   868  				statedb,
   869  
   870  				msg.From(),
   871  				blockCtx.Coinbase,
   872  
   873  				result.FeeTipped,
   874  				result.SenderInitBalance,
   875  				coinbaseBalance,
   876  				output1.Sub(output1, result.FeeTipped),
   877  				output2.Add(output2, result.FeeTipped),
   878  			)
   879  
   880  			// Finalize the state so any modifications are written to the trie
   881  			// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
   882  			statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number()))
   883  			statedb.FlushMVWriteSet()
   884  
   885  			structRead := statedb.GetReadMapDump()
   886  			structWrite := statedb.GetWriteMapDump()
   887  
   888  			RWstruct = append(RWstruct, structRead...)
   889  			RWstruct = append(RWstruct, structWrite...)
   890  		}
   891  	}
   892  
   893  	if ioflag {
   894  		for _, val := range RWstruct {
   895  			IOdump += fmt.Sprintf("%v , %v, %v , %v, ", val.TxIdx, val.TxInc, val.VerIdx, val.VerInc) + hex.EncodeToString(val.Path) + ", " + val.Op
   896  		}
   897  
   898  		// make sure that the file exists and write IOdump
   899  		err = ioutil.WriteFile(filepath.Join(path, "data.csv"), []byte(fmt.Sprint(IOdump)), 0600)
   900  		if err != nil {
   901  			return nil, err
   902  		}
   903  	}
   904  
   905  	close(jobs)
   906  	pend.Wait()
   907  
   908  	// If execution failed in between, abort
   909  	if failed != nil {
   910  		return nil, failed
   911  	}
   912  
   913  	if !*config.BorTraceEnabled && stateSyncPresent {
   914  		return results[:len(results)-1], nil
   915  	} else {
   916  		return results, nil
   917  	}
   918  }
   919  
   920  // standardTraceBlockToFile configures a new tracer which uses standard JSON output,
   921  // and traces either a full block or an individual transaction. The return value will
   922  // be one filename per transaction traced.
   923  func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block, config *StdTraceConfig) ([]string, error) {
   924  	if config == nil {
   925  		config = &StdTraceConfig{
   926  			BorTraceEnabled: defaultBorTraceEnabled,
   927  		}
   928  	}
   929  
   930  	if config.BorTraceEnabled == nil {
   931  		config.BorTraceEnabled = defaultBorTraceEnabled
   932  	}
   933  	// If we're tracing a single transaction, make sure it's present
   934  	if config != nil && config.TxHash != (common.Hash{}) {
   935  		if !api.containsTx(ctx, block, config.TxHash) {
   936  			return nil, fmt.Errorf("transaction %#x not found in block", config.TxHash)
   937  		}
   938  	}
   939  	if block.NumberU64() == 0 {
   940  		return nil, errors.New("genesis is not traceable")
   941  	}
   942  	parent, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(block.NumberU64()-1), block.ParentHash())
   943  	if err != nil {
   944  		return nil, err
   945  	}
   946  	reexec := defaultTraceReexec
   947  	if config != nil && config.Reexec != nil {
   948  		reexec = *config.Reexec
   949  	}
   950  	statedb, err := api.backend.StateAtBlock(ctx, parent, reexec, nil, true, false)
   951  	if err != nil {
   952  		return nil, err
   953  	}
   954  	// Retrieve the tracing configurations, or use default values
   955  	var (
   956  		logConfig logger.Config
   957  		txHash    common.Hash
   958  	)
   959  	if config != nil {
   960  		logConfig = config.Config
   961  		txHash = config.TxHash
   962  	}
   963  	logConfig.Debug = true
   964  
   965  	// Execute transaction, either tracing all or just the requested one
   966  	var (
   967  		dumps       []string
   968  		signer      = types.MakeSigner(api.backend.ChainConfig(), block.Number())
   969  		chainConfig = api.backend.ChainConfig()
   970  		vmctx       = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
   971  		canon       = true
   972  	)
   973  	// Check if there are any overrides: the caller may wish to enable a future
   974  	// fork when executing this block. Note, such overrides are only applicable to the
   975  	// actual specified block, not any preceding blocks that we have to go through
   976  	// in order to obtain the state.
   977  	// Therefore, it's perfectly valid to specify `"futureForkBlock": 0`, to enable `futureFork`
   978  
   979  	if config != nil && config.Overrides != nil {
   980  		// Copy the config, to not screw up the main config
   981  		// Note: the Clique-part is _not_ deep copied
   982  		chainConfigCopy := new(params.ChainConfig)
   983  		*chainConfigCopy = *chainConfig
   984  		chainConfig = chainConfigCopy
   985  		if berlin := config.Config.Overrides.BerlinBlock; berlin != nil {
   986  			chainConfig.BerlinBlock = berlin
   987  			canon = false
   988  		}
   989  	}
   990  
   991  	txs, stateSyncPresent := api.getAllBlockTransactions(ctx, block)
   992  	if !*config.BorTraceEnabled && stateSyncPresent {
   993  		txs = txs[:len(txs)-1]
   994  		stateSyncPresent = false
   995  	}
   996  
   997  	for i, tx := range txs {
   998  		// Prepare the trasaction for un-traced execution
   999  		var (
  1000  			msg, _    = tx.AsMessage(signer, block.BaseFee())
  1001  			txContext = core.NewEVMTxContext(msg)
  1002  			vmConf    vm.Config
  1003  			dump      *os.File
  1004  			writer    *bufio.Writer
  1005  			err       error
  1006  		)
  1007  		// If the transaction needs tracing, swap out the configs
  1008  		if tx.Hash() == txHash || txHash == (common.Hash{}) {
  1009  			// Generate a unique temporary file to dump it into
  1010  			prefix := fmt.Sprintf("block_%#x-%d-%#x-", block.Hash().Bytes()[:4], i, tx.Hash().Bytes()[:4])
  1011  			if !canon {
  1012  				prefix = fmt.Sprintf("%valt-", prefix)
  1013  			}
  1014  			dump, err = ioutil.TempFile(os.TempDir(), prefix)
  1015  			if err != nil {
  1016  				return nil, err
  1017  			}
  1018  			dumps = append(dumps, dump.Name())
  1019  
  1020  			// Swap out the noop logger to the standard tracer
  1021  			writer = bufio.NewWriter(dump)
  1022  			vmConf = vm.Config{
  1023  				Debug:                   true,
  1024  				Tracer:                  logger.NewJSONLogger(&logConfig, writer),
  1025  				EnablePreimageRecording: true,
  1026  			}
  1027  		}
  1028  		// Execute the transaction and flush any traces to disk
  1029  		vmenv := vm.NewEVM(vmctx, txContext, statedb, chainConfig, vmConf)
  1030  		statedb.Prepare(tx.Hash(), i)
  1031  		//nolint: nestif
  1032  		if stateSyncPresent && i == len(txs)-1 {
  1033  			if *config.BorTraceEnabled {
  1034  				callmsg := prepareCallMessage(msg)
  1035  				_, err = statefull.ApplyBorMessage(*vmenv, callmsg)
  1036  
  1037  				if writer != nil {
  1038  					writer.Flush()
  1039  				}
  1040  			}
  1041  		} else {
  1042  			// nolint : contextcheck
  1043  			_, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()), context.Background())
  1044  			if writer != nil {
  1045  				writer.Flush()
  1046  			}
  1047  		}
  1048  
  1049  		if dump != nil {
  1050  			dump.Close()
  1051  			log.Info("Wrote standard trace", "file", dump.Name())
  1052  		}
  1053  		if err != nil {
  1054  			return dumps, err
  1055  		}
  1056  		// Finalize the state so any modifications are written to the trie
  1057  		// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
  1058  		statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number()))
  1059  
  1060  		// If we've traced the transaction we were looking for, abort
  1061  		if tx.Hash() == txHash {
  1062  			break
  1063  		}
  1064  	}
  1065  	return dumps, nil
  1066  }
  1067  
  1068  // containsTx reports whether the transaction with a certain hash
  1069  // is contained within the specified block.
  1070  func (api *API) containsTx(ctx context.Context, block *types.Block, hash common.Hash) bool {
  1071  	txs, _ := api.getAllBlockTransactions(ctx, block)
  1072  	for _, tx := range txs {
  1073  		if tx.Hash() == hash {
  1074  			return true
  1075  		}
  1076  	}
  1077  	return false
  1078  }
  1079  
  1080  // TraceTransaction returns the structured logs created during the execution of EVM
  1081  // and returns them as a JSON object.
  1082  func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config *TraceConfig) (interface{}, error) {
  1083  	if config == nil {
  1084  		config = &TraceConfig{
  1085  			BorTraceEnabled: defaultBorTraceEnabled,
  1086  			BorTx:           newBoolPtr(false),
  1087  		}
  1088  	}
  1089  
  1090  	if config.BorTraceEnabled == nil {
  1091  		config.BorTraceEnabled = defaultBorTraceEnabled
  1092  	}
  1093  
  1094  	tx, blockHash, blockNumber, index, err := api.backend.GetTransaction(ctx, hash)
  1095  	if tx == nil {
  1096  		// For BorTransaction, there will be no trace available
  1097  		tx, _, _, _ = rawdb.ReadBorTransaction(api.backend.ChainDb(), hash)
  1098  		if tx != nil {
  1099  			return &ethapi.ExecutionResult{
  1100  				StructLogs: make([]ethapi.StructLogRes, 0),
  1101  			}, nil
  1102  		}
  1103  	}
  1104  	if err != nil {
  1105  		return nil, err
  1106  	}
  1107  
  1108  	// It shouldn't happen in practice.
  1109  	if blockNumber == 0 {
  1110  		return nil, errors.New("genesis is not traceable")
  1111  	}
  1112  	reexec := defaultTraceReexec
  1113  	if config != nil && config.Reexec != nil {
  1114  		reexec = *config.Reexec
  1115  	}
  1116  	block, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(blockNumber), blockHash)
  1117  	if err != nil {
  1118  		return nil, err
  1119  	}
  1120  	msg, vmctx, statedb, err := api.backend.StateAtTransaction(ctx, block, int(index), reexec)
  1121  	if err != nil {
  1122  		return nil, err
  1123  	}
  1124  	txctx := &Context{
  1125  		BlockHash: blockHash,
  1126  		TxIndex:   int(index),
  1127  		TxHash:    hash,
  1128  	}
  1129  
  1130  	return api.traceTx(ctx, msg, txctx, vmctx, statedb, config)
  1131  }
  1132  
  1133  // TraceCall lets you trace a given eth_call. It collects the structured logs
  1134  // created during the execution of EVM if the given transaction was added on
  1135  // top of the provided block and returns them as a JSON object.
  1136  // You can provide -2 as a block number to trace on top of the pending block.
  1137  func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, config *TraceCallConfig) (interface{}, error) {
  1138  	// Try to retrieve the specified block
  1139  	var (
  1140  		err   error
  1141  		block *types.Block
  1142  	)
  1143  	if hash, ok := blockNrOrHash.Hash(); ok {
  1144  		block, err = api.blockByHash(ctx, hash)
  1145  	} else if number, ok := blockNrOrHash.Number(); ok {
  1146  		block, err = api.blockByNumber(ctx, number)
  1147  	} else {
  1148  		return nil, errors.New("invalid arguments; neither block nor hash specified")
  1149  	}
  1150  	if err != nil {
  1151  		return nil, err
  1152  	}
  1153  	// try to recompute the state
  1154  	reexec := defaultTraceReexec
  1155  	if config != nil && config.Reexec != nil {
  1156  		reexec = *config.Reexec
  1157  	}
  1158  	statedb, err := api.backend.StateAtBlock(ctx, block, reexec, nil, true, false)
  1159  	if err != nil {
  1160  		return nil, err
  1161  	}
  1162  	// Apply the customized state rules if required.
  1163  	if config != nil {
  1164  		if err := config.StateOverrides.Apply(statedb); err != nil {
  1165  			return nil, err
  1166  		}
  1167  	}
  1168  	// Execute the trace
  1169  	msg, err := args.ToMessage(api.backend.RPCGasCap(), block.BaseFee())
  1170  	if err != nil {
  1171  		return nil, err
  1172  	}
  1173  	vmctx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
  1174  
  1175  	var traceConfig *TraceConfig
  1176  	if config != nil {
  1177  		traceConfig = &TraceConfig{
  1178  			Config:  config.Config,
  1179  			Tracer:  config.Tracer,
  1180  			Timeout: config.Timeout,
  1181  			Reexec:  config.Reexec,
  1182  		}
  1183  	}
  1184  
  1185  	return api.traceTx(ctx, msg, new(Context), vmctx, statedb, traceConfig)
  1186  }
  1187  
  1188  // traceTx configures a new tracer according to the provided configuration, and
  1189  // executes the given message in the provided environment. The return value will
  1190  // be tracer dependent.
  1191  func (api *API) traceTx(ctx context.Context, message core.Message, txctx *Context, vmctx vm.BlockContext, statedb *state.StateDB, config *TraceConfig) (interface{}, error) {
  1192  
  1193  	if config == nil {
  1194  		config = &TraceConfig{
  1195  			BorTraceEnabled: defaultBorTraceEnabled,
  1196  			BorTx:           newBoolPtr(false),
  1197  		}
  1198  	}
  1199  
  1200  	if config.BorTraceEnabled == nil {
  1201  		config.BorTraceEnabled = defaultBorTraceEnabled
  1202  	}
  1203  
  1204  	// Assemble the structured logger or the JavaScript tracer
  1205  	var (
  1206  		tracer    vm.EVMLogger
  1207  		err       error
  1208  		txContext = core.NewEVMTxContext(message)
  1209  	)
  1210  	switch {
  1211  	case config == nil:
  1212  		tracer = logger.NewStructLogger(nil)
  1213  	case config.Tracer != nil:
  1214  		// Define a meaningful timeout of a single transaction trace
  1215  		timeout := defaultTraceTimeout
  1216  		if config.Timeout != nil {
  1217  			if timeout, err = time.ParseDuration(*config.Timeout); err != nil {
  1218  				return nil, err
  1219  			}
  1220  		}
  1221  		if t, err := New(*config.Tracer, txctx); err != nil {
  1222  			return nil, err
  1223  		} else {
  1224  			deadlineCtx, cancel := context.WithTimeout(ctx, timeout)
  1225  			go func() {
  1226  				<-deadlineCtx.Done()
  1227  				if errors.Is(deadlineCtx.Err(), context.DeadlineExceeded) {
  1228  					t.Stop(errors.New("execution timeout"))
  1229  				}
  1230  			}()
  1231  			defer cancel()
  1232  			tracer = t
  1233  		}
  1234  	default:
  1235  		tracer = logger.NewStructLogger(config.Config)
  1236  	}
  1237  	// Run the transaction with tracing enabled.
  1238  	vmenv := vm.NewEVM(vmctx, txContext, statedb, api.backend.ChainConfig(), vm.Config{Debug: true, Tracer: tracer, NoBaseFee: true})
  1239  
  1240  	// Call Prepare to clear out the statedb access list
  1241  	statedb.Prepare(txctx.TxHash, txctx.TxIndex)
  1242  
  1243  	var result *core.ExecutionResult
  1244  
  1245  	if config.BorTx == nil {
  1246  		config.BorTx = newBoolPtr(false)
  1247  	}
  1248  
  1249  	if *config.BorTx {
  1250  		callmsg := prepareCallMessage(message)
  1251  		if result, err = statefull.ApplyBorMessage(*vmenv, callmsg); err != nil {
  1252  			return nil, fmt.Errorf("tracing failed: %w", err)
  1253  		}
  1254  	} else {
  1255  		// nolint : contextcheck
  1256  		result, err = core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas()), context.Background())
  1257  		if err != nil {
  1258  			return nil, fmt.Errorf("tracing failed: %w", err)
  1259  		}
  1260  	}
  1261  
  1262  	// Depending on the tracer type, format and return the output.
  1263  	switch tracer := tracer.(type) {
  1264  	case *logger.StructLogger:
  1265  		// If the result contains a revert reason, return it.
  1266  		returnVal := fmt.Sprintf("%x", result.Return())
  1267  		if len(result.Revert()) > 0 {
  1268  			returnVal = fmt.Sprintf("%x", result.Revert())
  1269  		}
  1270  		return &ethapi.ExecutionResult{
  1271  			Gas:         result.UsedGas,
  1272  			Failed:      result.Failed(),
  1273  			ReturnValue: returnVal,
  1274  			StructLogs:  ethapi.FormatLogs(tracer.StructLogs()),
  1275  		}, nil
  1276  
  1277  	case Tracer:
  1278  		return tracer.GetResult()
  1279  
  1280  	default:
  1281  		panic(fmt.Sprintf("bad tracer type %T", tracer))
  1282  	}
  1283  }
  1284  
  1285  // APIs return the collection of RPC services the tracer package offers.
  1286  func APIs(backend Backend) []rpc.API {
  1287  	// Append all the local APIs and return
  1288  	return []rpc.API{
  1289  		{
  1290  			Namespace: "debug",
  1291  			Version:   "1.0",
  1292  			Service:   NewAPI(backend),
  1293  			Public:    false,
  1294  		},
  1295  	}
  1296  }