github.com/LampardNguyen234/go-ethereum@v1.10.16-0.20220117140830-b6a3b0260724/eth/tracers/api.go (about)

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