github.com/ethereum-optimism/optimism/l2geth@v0.0.0-20230612200230-50b04ade19e3/eth/api_tracer.go (about)

     1  // Copyright 2017 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 eth
    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/ethereum-optimism/optimism/l2geth/common"
    32  	"github.com/ethereum-optimism/optimism/l2geth/common/hexutil"
    33  	"github.com/ethereum-optimism/optimism/l2geth/core"
    34  	"github.com/ethereum-optimism/optimism/l2geth/core/rawdb"
    35  	"github.com/ethereum-optimism/optimism/l2geth/core/state"
    36  	"github.com/ethereum-optimism/optimism/l2geth/core/types"
    37  	"github.com/ethereum-optimism/optimism/l2geth/core/vm"
    38  	"github.com/ethereum-optimism/optimism/l2geth/eth/tracers"
    39  	"github.com/ethereum-optimism/optimism/l2geth/internal/ethapi"
    40  	"github.com/ethereum-optimism/optimism/l2geth/log"
    41  	"github.com/ethereum-optimism/optimism/l2geth/params"
    42  	"github.com/ethereum-optimism/optimism/l2geth/rlp"
    43  	"github.com/ethereum-optimism/optimism/l2geth/rpc"
    44  	"github.com/ethereum-optimism/optimism/l2geth/trie"
    45  )
    46  
    47  const (
    48  	// defaultTraceTimeout is the amount of time a single transaction can execute
    49  	// by default before being forcefully aborted.
    50  	defaultTraceTimeout = 5 * time.Second
    51  
    52  	// defaultTraceReexec is the number of blocks the tracer is willing to go back
    53  	// and reexecute to produce missing historical state necessary to run a specific
    54  	// trace.
    55  	defaultTraceReexec = uint64(128)
    56  )
    57  
    58  // TraceConfig holds extra parameters to trace functions.
    59  type TraceConfig struct {
    60  	*vm.LogConfig
    61  	Tracer  *string
    62  	Timeout *string
    63  	Reexec  *uint64
    64  }
    65  
    66  // StdTraceConfig holds extra parameters to standard-json trace functions.
    67  type StdTraceConfig struct {
    68  	vm.LogConfig
    69  	Reexec *uint64
    70  	TxHash common.Hash
    71  }
    72  
    73  // txTraceResult is the result of a single transaction trace.
    74  type txTraceResult struct {
    75  	Result interface{} `json:"result,omitempty"` // Trace results produced by the tracer
    76  	Error  string      `json:"error,omitempty"`  // Trace failure produced by the tracer
    77  }
    78  
    79  // blockTraceTask represents a single block trace task when an entire chain is
    80  // being traced.
    81  type blockTraceTask struct {
    82  	statedb *state.StateDB   // Intermediate state prepped for tracing
    83  	block   *types.Block     // Block to trace the transactions from
    84  	rootref common.Hash      // Trie root reference held for this task
    85  	results []*txTraceResult // Trace results procudes by the task
    86  }
    87  
    88  // blockTraceResult represets the results of tracing a single block when an entire
    89  // chain is being traced.
    90  type blockTraceResult struct {
    91  	Block  hexutil.Uint64   `json:"block"`  // Block number corresponding to this trace
    92  	Hash   common.Hash      `json:"hash"`   // Block hash corresponding to this trace
    93  	Traces []*txTraceResult `json:"traces"` // Trace results produced by the task
    94  }
    95  
    96  // txTraceTask represents a single transaction trace task when an entire block
    97  // is being traced.
    98  type txTraceTask struct {
    99  	statedb *state.StateDB // Intermediate state prepped for tracing
   100  	index   int            // Transaction offset in the block
   101  }
   102  
   103  // TraceChain returns the structured logs created during the execution of EVM
   104  // between two blocks (excluding start) and returns them as a JSON object.
   105  func (api *PrivateDebugAPI) TraceChain(ctx context.Context, start, end rpc.BlockNumber, config *TraceConfig) (*rpc.Subscription, error) {
   106  	// Fetch the block interval that we want to trace
   107  	var from, to *types.Block
   108  
   109  	switch start {
   110  	case rpc.LatestBlockNumber:
   111  	case rpc.PendingBlockNumber:
   112  		from = api.eth.blockchain.CurrentBlock()
   113  	default:
   114  		from = api.eth.blockchain.GetBlockByNumber(uint64(start))
   115  	}
   116  	switch end {
   117  	case rpc.LatestBlockNumber:
   118  	case rpc.PendingBlockNumber:
   119  		to = api.eth.blockchain.CurrentBlock()
   120  	default:
   121  		to = api.eth.blockchain.GetBlockByNumber(uint64(end))
   122  	}
   123  	// Trace the chain if we've found all our blocks
   124  	if from == nil {
   125  		return nil, fmt.Errorf("starting block #%d not found", start)
   126  	}
   127  	if to == nil {
   128  		return nil, fmt.Errorf("end block #%d not found", end)
   129  	}
   130  	if from.Number().Cmp(to.Number()) >= 0 {
   131  		return nil, fmt.Errorf("end block (#%d) needs to come after start block (#%d)", end, start)
   132  	}
   133  	return api.traceChain(ctx, from, to, config)
   134  }
   135  
   136  // traceChain configures a new tracer according to the provided configuration, and
   137  // executes all the transactions contained within. The return value will be one item
   138  // per transaction, dependent on the requested tracer.
   139  func (api *PrivateDebugAPI) traceChain(ctx context.Context, start, end *types.Block, config *TraceConfig) (*rpc.Subscription, error) {
   140  	// Tracing a chain is a **long** operation, only do with subscriptions
   141  	notifier, supported := rpc.NotifierFromContext(ctx)
   142  	if !supported {
   143  		return &rpc.Subscription{}, rpc.ErrNotificationsUnsupported
   144  	}
   145  	sub := notifier.CreateSubscription()
   146  
   147  	// Ensure we have a valid starting state before doing any work
   148  	origin := start.NumberU64()
   149  	database := state.NewDatabaseWithCache(api.eth.ChainDb(), 16) // Chain tracing will probably start at genesis
   150  
   151  	if number := start.NumberU64(); number > 0 {
   152  		start = api.eth.blockchain.GetBlock(start.ParentHash(), start.NumberU64()-1)
   153  		if start == nil {
   154  			return nil, fmt.Errorf("parent block #%d not found", number-1)
   155  		}
   156  	}
   157  	statedb, err := state.New(start.Root(), database)
   158  	if err != nil {
   159  		// If the starting state is missing, allow some number of blocks to be reexecuted
   160  		reexec := defaultTraceReexec
   161  		if config != nil && config.Reexec != nil {
   162  			reexec = *config.Reexec
   163  		}
   164  		// Find the most recent block that has the state available
   165  		for i := uint64(0); i < reexec; i++ {
   166  			start = api.eth.blockchain.GetBlock(start.ParentHash(), start.NumberU64()-1)
   167  			if start == nil {
   168  				break
   169  			}
   170  			if statedb, err = state.New(start.Root(), database); err == nil {
   171  				break
   172  			}
   173  		}
   174  		// If we still don't have the state available, bail out
   175  		if err != nil {
   176  			switch err.(type) {
   177  			case *trie.MissingNodeError:
   178  				return nil, errors.New("required historical state unavailable")
   179  			default:
   180  				return nil, err
   181  			}
   182  		}
   183  	}
   184  	// Execute all the transaction contained within the chain concurrently for each block
   185  	blocks := int(end.NumberU64() - origin)
   186  
   187  	threads := runtime.NumCPU()
   188  	if threads > blocks {
   189  		threads = blocks
   190  	}
   191  	var (
   192  		pend    = new(sync.WaitGroup)
   193  		tasks   = make(chan *blockTraceTask, threads)
   194  		results = make(chan *blockTraceTask, threads)
   195  	)
   196  	for th := 0; th < threads; th++ {
   197  		pend.Add(1)
   198  		go func() {
   199  			defer pend.Done()
   200  
   201  			// Fetch and execute the next block trace tasks
   202  			for task := range tasks {
   203  				signer := types.MakeSigner(api.eth.blockchain.Config(), task.block.Number())
   204  
   205  				// Trace all the transactions contained within
   206  				for i, tx := range task.block.Transactions() {
   207  					msg, _ := tx.AsMessage(signer)
   208  					vmctx := core.NewEVMContext(msg, task.block.Header(), api.eth.blockchain, nil)
   209  
   210  					res, err := api.traceTx(ctx, msg, vmctx, task.statedb, config)
   211  					if err != nil {
   212  						task.results[i] = &txTraceResult{Error: err.Error()}
   213  						log.Warn("Tracing failed", "hash", tx.Hash(), "block", task.block.NumberU64(), "err", err)
   214  						break
   215  					}
   216  					// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
   217  					task.statedb.Finalise(api.eth.blockchain.Config().IsEIP158(task.block.Number()))
   218  					task.results[i] = &txTraceResult{Result: res}
   219  				}
   220  				// Stream the result back to the user or abort on teardown
   221  				select {
   222  				case results <- task:
   223  				case <-notifier.Closed():
   224  					return
   225  				}
   226  			}
   227  		}()
   228  	}
   229  	// Start a goroutine to feed all the blocks into the tracers
   230  	begin := time.Now()
   231  
   232  	go func() {
   233  		var (
   234  			logged time.Time
   235  			number uint64
   236  			traced uint64
   237  			failed error
   238  			proot  common.Hash
   239  		)
   240  		// Ensure everything is properly cleaned up on any exit path
   241  		defer func() {
   242  			close(tasks)
   243  			pend.Wait()
   244  
   245  			switch {
   246  			case failed != nil:
   247  				log.Warn("Chain tracing failed", "start", start.NumberU64(), "end", end.NumberU64(), "transactions", traced, "elapsed", time.Since(begin), "err", failed)
   248  			case number < end.NumberU64():
   249  				log.Warn("Chain tracing aborted", "start", start.NumberU64(), "end", end.NumberU64(), "abort", number, "transactions", traced, "elapsed", time.Since(begin))
   250  			default:
   251  				log.Info("Chain tracing finished", "start", start.NumberU64(), "end", end.NumberU64(), "transactions", traced, "elapsed", time.Since(begin))
   252  			}
   253  			close(results)
   254  		}()
   255  		// Feed all the blocks both into the tracer, as well as fast process concurrently
   256  		for number = start.NumberU64() + 1; number <= end.NumberU64(); number++ {
   257  			// Stop tracing if interruption was requested
   258  			select {
   259  			case <-notifier.Closed():
   260  				return
   261  			default:
   262  			}
   263  			// Print progress logs if long enough time elapsed
   264  			if time.Since(logged) > 8*time.Second {
   265  				if number > origin {
   266  					nodes, imgs := database.TrieDB().Size()
   267  					log.Info("Tracing chain segment", "start", origin, "end", end.NumberU64(), "current", number, "transactions", traced, "elapsed", time.Since(begin), "memory", nodes+imgs)
   268  				} else {
   269  					log.Info("Preparing state for chain trace", "block", number, "start", origin, "elapsed", time.Since(begin))
   270  				}
   271  				logged = time.Now()
   272  			}
   273  			// Retrieve the next block to trace
   274  			block := api.eth.blockchain.GetBlockByNumber(number)
   275  			if block == nil {
   276  				failed = fmt.Errorf("block #%d not found", number)
   277  				break
   278  			}
   279  			// Send the block over to the concurrent tracers (if not in the fast-forward phase)
   280  			if number > origin {
   281  				txs := block.Transactions()
   282  
   283  				select {
   284  				case tasks <- &blockTraceTask{statedb: statedb.Copy(), block: block, rootref: proot, results: make([]*txTraceResult, len(txs))}:
   285  				case <-notifier.Closed():
   286  					return
   287  				}
   288  				traced += uint64(len(txs))
   289  			}
   290  			// Generate the next state snapshot fast without tracing
   291  			_, _, _, err := api.eth.blockchain.Processor().Process(block, statedb, vm.Config{})
   292  			if err != nil {
   293  				failed = err
   294  				break
   295  			}
   296  			// Finalize the state so any modifications are written to the trie
   297  			root, err := statedb.Commit(api.eth.blockchain.Config().IsEIP158(block.Number()))
   298  			if err != nil {
   299  				failed = err
   300  				break
   301  			}
   302  			if err := statedb.Reset(root); err != nil {
   303  				failed = err
   304  				break
   305  			}
   306  			// Reference the trie twice, once for us, once for the tracer
   307  			database.TrieDB().Reference(root, common.Hash{})
   308  			if number >= origin {
   309  				database.TrieDB().Reference(root, common.Hash{})
   310  			}
   311  			// Dereference all past tries we ourselves are done working with
   312  			if proot != (common.Hash{}) {
   313  				database.TrieDB().Dereference(proot)
   314  			}
   315  			proot = root
   316  
   317  			// TODO(karalabe): Do we need the preimages? Won't they accumulate too much?
   318  		}
   319  	}()
   320  
   321  	// Keep reading the trace results and stream the to the user
   322  	go func() {
   323  		var (
   324  			done = make(map[uint64]*blockTraceResult)
   325  			next = origin + 1
   326  		)
   327  		for res := range results {
   328  			// Queue up next received result
   329  			result := &blockTraceResult{
   330  				Block:  hexutil.Uint64(res.block.NumberU64()),
   331  				Hash:   res.block.Hash(),
   332  				Traces: res.results,
   333  			}
   334  			done[uint64(result.Block)] = result
   335  
   336  			// Dereference any paret tries held in memory by this task
   337  			database.TrieDB().Dereference(res.rootref)
   338  
   339  			// Stream completed traces to the user, aborting on the first error
   340  			for result, ok := done[next]; ok; result, ok = done[next] {
   341  				if len(result.Traces) > 0 || next == end.NumberU64() {
   342  					notifier.Notify(sub.ID, result)
   343  				}
   344  				delete(done, next)
   345  				next++
   346  			}
   347  		}
   348  	}()
   349  	return sub, nil
   350  }
   351  
   352  // TraceBlockByNumber returns the structured logs created during the execution of
   353  // EVM and returns them as a JSON object.
   354  func (api *PrivateDebugAPI) TraceBlockByNumber(ctx context.Context, number rpc.BlockNumber, config *TraceConfig) ([]*txTraceResult, error) {
   355  	// Fetch the block that we want to trace
   356  	var block *types.Block
   357  
   358  	switch number {
   359  	case rpc.LatestBlockNumber:
   360  	case rpc.PendingBlockNumber:
   361  		block = api.eth.blockchain.CurrentBlock()
   362  	default:
   363  		block = api.eth.blockchain.GetBlockByNumber(uint64(number))
   364  	}
   365  	// Trace the block if it was found
   366  	if block == nil {
   367  		return nil, fmt.Errorf("block #%d not found", number)
   368  	}
   369  	return api.traceBlock(ctx, block, config)
   370  }
   371  
   372  // TraceBlockByHash returns the structured logs created during the execution of
   373  // EVM and returns them as a JSON object.
   374  func (api *PrivateDebugAPI) TraceBlockByHash(ctx context.Context, hash common.Hash, config *TraceConfig) ([]*txTraceResult, error) {
   375  	block := api.eth.blockchain.GetBlockByHash(hash)
   376  	if block == nil {
   377  		return nil, fmt.Errorf("block %#x not found", hash)
   378  	}
   379  	return api.traceBlock(ctx, block, config)
   380  }
   381  
   382  // TraceBlock returns the structured logs created during the execution of EVM
   383  // and returns them as a JSON object.
   384  func (api *PrivateDebugAPI) TraceBlock(ctx context.Context, blob []byte, config *TraceConfig) ([]*txTraceResult, error) {
   385  	block := new(types.Block)
   386  	if err := rlp.Decode(bytes.NewReader(blob), block); err != nil {
   387  		return nil, fmt.Errorf("could not decode block: %v", err)
   388  	}
   389  	return api.traceBlock(ctx, block, config)
   390  }
   391  
   392  // TraceBlockFromFile returns the structured logs created during the execution of
   393  // EVM and returns them as a JSON object.
   394  func (api *PrivateDebugAPI) TraceBlockFromFile(ctx context.Context, file string, config *TraceConfig) ([]*txTraceResult, error) {
   395  	blob, err := ioutil.ReadFile(file)
   396  	if err != nil {
   397  		return nil, fmt.Errorf("could not read file: %v", err)
   398  	}
   399  	return api.TraceBlock(ctx, blob, config)
   400  }
   401  
   402  // TraceBadBlockByHash returns the structured logs created during the execution of
   403  // EVM against a block pulled from the pool of bad ones and returns them as a JSON
   404  // object.
   405  func (api *PrivateDebugAPI) TraceBadBlock(ctx context.Context, hash common.Hash, config *TraceConfig) ([]*txTraceResult, error) {
   406  	blocks := api.eth.blockchain.BadBlocks()
   407  	for _, block := range blocks {
   408  		if block.Hash() == hash {
   409  			return api.traceBlock(ctx, block, config)
   410  		}
   411  	}
   412  	return nil, fmt.Errorf("bad block %#x not found", hash)
   413  }
   414  
   415  // StandardTraceBlockToFile dumps the structured logs created during the
   416  // execution of EVM to the local file system and returns a list of files
   417  // to the caller.
   418  func (api *PrivateDebugAPI) StandardTraceBlockToFile(ctx context.Context, hash common.Hash, config *StdTraceConfig) ([]string, error) {
   419  	block := api.eth.blockchain.GetBlockByHash(hash)
   420  	if block == nil {
   421  		return nil, fmt.Errorf("block %#x not found", hash)
   422  	}
   423  	return api.standardTraceBlockToFile(ctx, block, config)
   424  }
   425  
   426  // StandardTraceBadBlockToFile dumps the structured logs created during the
   427  // execution of EVM against a block pulled from the pool of bad ones to the
   428  // local file system and returns a list of files to the caller.
   429  func (api *PrivateDebugAPI) StandardTraceBadBlockToFile(ctx context.Context, hash common.Hash, config *StdTraceConfig) ([]string, error) {
   430  	blocks := api.eth.blockchain.BadBlocks()
   431  	for _, block := range blocks {
   432  		if block.Hash() == hash {
   433  			return api.standardTraceBlockToFile(ctx, block, config)
   434  		}
   435  	}
   436  	return nil, fmt.Errorf("bad block %#x not found", hash)
   437  }
   438  
   439  // traceBlock configures a new tracer according to the provided configuration, and
   440  // executes all the transactions contained within. The return value will be one item
   441  // per transaction, dependent on the requestd tracer.
   442  func (api *PrivateDebugAPI) traceBlock(ctx context.Context, block *types.Block, config *TraceConfig) ([]*txTraceResult, error) {
   443  	// Create the parent state database
   444  	if err := api.eth.engine.VerifyHeader(api.eth.blockchain, block.Header(), true); err != nil {
   445  		return nil, err
   446  	}
   447  	parent := api.eth.blockchain.GetBlock(block.ParentHash(), block.NumberU64()-1)
   448  	if parent == nil {
   449  		return nil, fmt.Errorf("parent %#x not found", block.ParentHash())
   450  	}
   451  	reexec := defaultTraceReexec
   452  	if config != nil && config.Reexec != nil {
   453  		reexec = *config.Reexec
   454  	}
   455  	statedb, err := api.computeStateDB(parent, reexec)
   456  	if err != nil {
   457  		return nil, err
   458  	}
   459  	// Execute all the transaction contained within the block concurrently
   460  	var (
   461  		signer = types.MakeSigner(api.eth.blockchain.Config(), block.Number())
   462  
   463  		txs     = block.Transactions()
   464  		results = make([]*txTraceResult, len(txs))
   465  
   466  		pend = new(sync.WaitGroup)
   467  		jobs = make(chan *txTraceTask, len(txs))
   468  	)
   469  	threads := runtime.NumCPU()
   470  	if threads > len(txs) {
   471  		threads = len(txs)
   472  	}
   473  	for th := 0; th < threads; th++ {
   474  		pend.Add(1)
   475  		go func() {
   476  			defer pend.Done()
   477  
   478  			// Fetch and execute the next transaction trace tasks
   479  			for task := range jobs {
   480  				msg, _ := txs[task.index].AsMessage(signer)
   481  				vmctx := core.NewEVMContext(msg, block.Header(), api.eth.blockchain, nil)
   482  
   483  				res, err := api.traceTx(ctx, msg, vmctx, task.statedb, config)
   484  				if err != nil {
   485  					results[task.index] = &txTraceResult{Error: err.Error()}
   486  					continue
   487  				}
   488  				results[task.index] = &txTraceResult{Result: res}
   489  			}
   490  		}()
   491  	}
   492  	// Feed the transactions into the tracers and return
   493  	var failed error
   494  	for i, tx := range txs {
   495  		// Send the trace task over for execution
   496  		jobs <- &txTraceTask{statedb: statedb.Copy(), index: i}
   497  
   498  		// Generate the next state snapshot fast without tracing
   499  		msg, _ := tx.AsMessage(signer)
   500  		vmctx := core.NewEVMContext(msg, block.Header(), api.eth.blockchain, nil)
   501  
   502  		vmenv := vm.NewEVM(vmctx, statedb, api.eth.blockchain.Config(), vm.Config{})
   503  		if _, _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil {
   504  			failed = err
   505  			break
   506  		}
   507  		// Finalize the state so any modifications are written to the trie
   508  		// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
   509  		statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number()))
   510  	}
   511  	close(jobs)
   512  	pend.Wait()
   513  
   514  	// If execution failed in between, abort
   515  	if failed != nil {
   516  		return nil, failed
   517  	}
   518  	return results, nil
   519  }
   520  
   521  // standardTraceBlockToFile configures a new tracer which uses standard JSON output,
   522  // and traces either a full block or an individual transaction. The return value will
   523  // be one filename per transaction traced.
   524  func (api *PrivateDebugAPI) standardTraceBlockToFile(ctx context.Context, block *types.Block, config *StdTraceConfig) ([]string, error) {
   525  	// If we're tracing a single transaction, make sure it's present
   526  	if config != nil && config.TxHash != (common.Hash{}) {
   527  		if !containsTx(block, config.TxHash) {
   528  			return nil, fmt.Errorf("transaction %#x not found in block", config.TxHash)
   529  		}
   530  	}
   531  	// Create the parent state database
   532  	if err := api.eth.engine.VerifyHeader(api.eth.blockchain, block.Header(), true); err != nil {
   533  		return nil, err
   534  	}
   535  	parent := api.eth.blockchain.GetBlock(block.ParentHash(), block.NumberU64()-1)
   536  	if parent == nil {
   537  		return nil, fmt.Errorf("parent %#x not found", block.ParentHash())
   538  	}
   539  	reexec := defaultTraceReexec
   540  	if config != nil && config.Reexec != nil {
   541  		reexec = *config.Reexec
   542  	}
   543  	statedb, err := api.computeStateDB(parent, reexec)
   544  	if err != nil {
   545  		return nil, err
   546  	}
   547  	// Retrieve the tracing configurations, or use default values
   548  	var (
   549  		logConfig vm.LogConfig
   550  		txHash    common.Hash
   551  	)
   552  	if config != nil {
   553  		logConfig = config.LogConfig
   554  		txHash = config.TxHash
   555  	}
   556  	logConfig.Debug = true
   557  
   558  	// Execute transaction, either tracing all or just the requested one
   559  	var (
   560  		dumps       []string
   561  		signer      = types.MakeSigner(api.eth.blockchain.Config(), block.Number())
   562  		chainConfig = api.eth.blockchain.Config()
   563  		canon       = true
   564  	)
   565  
   566  	// Check if there are any overrides: the caller may wish to enable a future
   567  	// fork when executing this block. Note, such overrides are only applicable to the
   568  	// actual specified block, not any preceding blocks that we have to go through
   569  	// in order to obtain the state.
   570  	// Therefore, it's perfectly valid to specify `"futureForkBlock": 0`, to enable `futureFork`
   571  
   572  	if config != nil && config.Overrides != nil {
   573  		// Copy the config, to not screw up the main config
   574  		// Note: the Clique-part is _not_ deep copied
   575  		chainConfigCopy := new(params.ChainConfig)
   576  		*chainConfigCopy = *chainConfig
   577  		chainConfig = chainConfigCopy
   578  		if berlin := config.LogConfig.Overrides.BerlinBlock; berlin != nil {
   579  			chainConfig.BerlinBlock = berlin
   580  			canon = false
   581  		}
   582  	}
   583  
   584  	for i, tx := range block.Transactions() {
   585  		// Prepare the trasaction for un-traced execution
   586  		var (
   587  			msg, _ = tx.AsMessage(signer)
   588  			vmctx  = core.NewEVMContext(msg, block.Header(), api.eth.blockchain, nil)
   589  
   590  			vmConf vm.Config
   591  			dump   *os.File
   592  			writer *bufio.Writer
   593  			err    error
   594  		)
   595  		// If the transaction needs tracing, swap out the configs
   596  		if tx.Hash() == txHash || txHash == (common.Hash{}) {
   597  			// Generate a unique temporary file to dump it into
   598  			prefix := fmt.Sprintf("block_%#x-%d-%#x-", block.Hash().Bytes()[:4], i, tx.Hash().Bytes()[:4])
   599  			if !canon {
   600  				prefix = fmt.Sprintf("%valt-", prefix)
   601  			}
   602  			dump, err = ioutil.TempFile(os.TempDir(), prefix)
   603  			if err != nil {
   604  				return nil, err
   605  			}
   606  			dumps = append(dumps, dump.Name())
   607  
   608  			// Swap out the noop logger to the standard tracer
   609  			writer = bufio.NewWriter(dump)
   610  			vmConf = vm.Config{
   611  				Debug:                   true,
   612  				Tracer:                  vm.NewJSONLogger(&logConfig, writer),
   613  				EnablePreimageRecording: true,
   614  			}
   615  		}
   616  		// Execute the transaction and flush any traces to disk
   617  		vmenv := vm.NewEVM(vmctx, statedb, chainConfig, vmConf)
   618  		_, _, _, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()))
   619  		if writer != nil {
   620  			writer.Flush()
   621  		}
   622  		if dump != nil {
   623  			dump.Close()
   624  			log.Info("Wrote standard trace", "file", dump.Name())
   625  		}
   626  		if err != nil {
   627  			return dumps, err
   628  		}
   629  		// Finalize the state so any modifications are written to the trie
   630  		// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
   631  		statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number()))
   632  
   633  		// If we've traced the transaction we were looking for, abort
   634  		if tx.Hash() == txHash {
   635  			break
   636  		}
   637  	}
   638  	return dumps, nil
   639  }
   640  
   641  // containsTx reports whether the transaction with a certain hash
   642  // is contained within the specified block.
   643  func containsTx(block *types.Block, hash common.Hash) bool {
   644  	for _, tx := range block.Transactions() {
   645  		if tx.Hash() == hash {
   646  			return true
   647  		}
   648  	}
   649  	return false
   650  }
   651  
   652  // computeStateDB retrieves the state database associated with a certain block.
   653  // If no state is locally available for the given block, a number of blocks are
   654  // attempted to be reexecuted to generate the desired state.
   655  func (api *PrivateDebugAPI) computeStateDB(block *types.Block, reexec uint64) (*state.StateDB, error) {
   656  	// If we have the state fully available, use that
   657  	statedb, err := api.eth.blockchain.StateAt(block.Root())
   658  	if err == nil {
   659  		return statedb, nil
   660  	}
   661  	// Otherwise try to reexec blocks until we find a state or reach our limit
   662  	origin := block.NumberU64()
   663  	database := state.NewDatabaseWithCache(api.eth.ChainDb(), 16)
   664  
   665  	for i := uint64(0); i < reexec; i++ {
   666  		block = api.eth.blockchain.GetBlock(block.ParentHash(), block.NumberU64()-1)
   667  		if block == nil {
   668  			break
   669  		}
   670  		if statedb, err = state.New(block.Root(), database); err == nil {
   671  			break
   672  		}
   673  	}
   674  	if err != nil {
   675  		switch err.(type) {
   676  		case *trie.MissingNodeError:
   677  			return nil, fmt.Errorf("required historical state unavailable (reexec=%d)", reexec)
   678  		default:
   679  			return nil, err
   680  		}
   681  	}
   682  	// State was available at historical point, regenerate
   683  	var (
   684  		start  = time.Now()
   685  		logged time.Time
   686  		proot  common.Hash
   687  	)
   688  	for block.NumberU64() < origin {
   689  		// Print progress logs if long enough time elapsed
   690  		if time.Since(logged) > 8*time.Second {
   691  			log.Info("Regenerating historical state", "block", block.NumberU64()+1, "target", origin, "remaining", origin-block.NumberU64()-1, "elapsed", time.Since(start))
   692  			logged = time.Now()
   693  		}
   694  		// Retrieve the next block to regenerate and process it
   695  		if block = api.eth.blockchain.GetBlockByNumber(block.NumberU64() + 1); block == nil {
   696  			return nil, fmt.Errorf("block #%d not found", block.NumberU64()+1)
   697  		}
   698  		_, _, _, err := api.eth.blockchain.Processor().Process(block, statedb, vm.Config{})
   699  		if err != nil {
   700  			return nil, fmt.Errorf("processing block %d failed: %v", block.NumberU64(), err)
   701  		}
   702  		// Finalize the state so any modifications are written to the trie
   703  		root, err := statedb.Commit(api.eth.blockchain.Config().IsEIP158(block.Number()))
   704  		if err != nil {
   705  			return nil, err
   706  		}
   707  		if err := statedb.Reset(root); err != nil {
   708  			return nil, fmt.Errorf("state reset after block %d failed: %v", block.NumberU64(), err)
   709  		}
   710  		database.TrieDB().Reference(root, common.Hash{})
   711  		if proot != (common.Hash{}) {
   712  			database.TrieDB().Dereference(proot)
   713  		}
   714  		proot = root
   715  	}
   716  	nodes, imgs := database.TrieDB().Size()
   717  	log.Info("Historical state regenerated", "block", block.NumberU64(), "elapsed", time.Since(start), "nodes", nodes, "preimages", imgs)
   718  	return statedb, nil
   719  }
   720  
   721  // TraceTransaction returns the structured logs created during the execution of EVM
   722  // and returns them as a JSON object.
   723  func (api *PrivateDebugAPI) TraceTransaction(ctx context.Context, hash common.Hash, config *TraceConfig) (interface{}, error) {
   724  	// Retrieve the transaction and assemble its EVM context
   725  	tx, blockHash, _, index := rawdb.ReadTransaction(api.eth.ChainDb(), hash)
   726  	if tx == nil {
   727  		return nil, fmt.Errorf("transaction %#x not found", hash)
   728  	}
   729  	reexec := defaultTraceReexec
   730  	if config != nil && config.Reexec != nil {
   731  		reexec = *config.Reexec
   732  	}
   733  	msg, vmctx, statedb, err := api.computeTxEnv(blockHash, int(index), reexec)
   734  	if err != nil {
   735  		return nil, err
   736  	}
   737  	// Trace the transaction and return
   738  	return api.traceTx(ctx, msg, vmctx, statedb, config)
   739  }
   740  
   741  // traceTx configures a new tracer according to the provided configuration, and
   742  // executes the given message in the provided environment. The return value will
   743  // be tracer dependent.
   744  func (api *PrivateDebugAPI) traceTx(ctx context.Context, message core.Message, vmctx vm.Context, statedb *state.StateDB, config *TraceConfig) (interface{}, error) {
   745  	// Assemble the structured logger or the JavaScript tracer
   746  	var (
   747  		tracer vm.Tracer
   748  		err    error
   749  	)
   750  	switch {
   751  	case config != nil && config.Tracer != nil:
   752  		// Define a meaningful timeout of a single transaction trace
   753  		timeout := defaultTraceTimeout
   754  		if config.Timeout != nil {
   755  			if timeout, err = time.ParseDuration(*config.Timeout); err != nil {
   756  				return nil, err
   757  			}
   758  		}
   759  		// Constuct the JavaScript tracer to execute with
   760  		if tracer, err = tracers.New(*config.Tracer); err != nil {
   761  			return nil, err
   762  		}
   763  		// Handle timeouts and RPC cancellations
   764  		deadlineCtx, cancel := context.WithTimeout(ctx, timeout)
   765  		go func() {
   766  			<-deadlineCtx.Done()
   767  			tracer.(*tracers.Tracer).Stop(errors.New("execution timeout"))
   768  		}()
   769  		defer cancel()
   770  
   771  	case config == nil:
   772  		tracer = vm.NewStructLogger(nil)
   773  
   774  	default:
   775  		tracer = vm.NewStructLogger(config.LogConfig)
   776  	}
   777  
   778  	chainConfig := api.eth.blockchain.Config()
   779  	if config != nil && config.LogConfig != nil && config.LogConfig.Overrides != nil {
   780  		chainConfigCopy := new(params.ChainConfig)
   781  		*chainConfigCopy = *chainConfig
   782  		chainConfig = chainConfigCopy
   783  		if berlin := config.LogConfig.Overrides.BerlinBlock; berlin != nil {
   784  			chainConfig.BerlinBlock = berlin
   785  		}
   786  	}
   787  
   788  	// Run the transaction with tracing enabled.
   789  	vmenv := vm.NewEVM(vmctx, statedb, chainConfig, vm.Config{Debug: true, Tracer: tracer})
   790  
   791  	ret, gas, failed, err := core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas()))
   792  	if err != nil {
   793  		return nil, fmt.Errorf("tracing failed: %v", err)
   794  	}
   795  	// Depending on the tracer type, format and return the output
   796  	switch tracer := tracer.(type) {
   797  	case *vm.StructLogger:
   798  		return &ethapi.ExecutionResult{
   799  			Gas:         gas,
   800  			Failed:      failed,
   801  			ReturnValue: fmt.Sprintf("%x", ret),
   802  			StructLogs:  ethapi.FormatLogs(tracer.StructLogs()),
   803  		}, nil
   804  
   805  	case *tracers.Tracer:
   806  		return tracer.GetResult()
   807  
   808  	default:
   809  		panic(fmt.Sprintf("bad tracer type %T", tracer))
   810  	}
   811  }
   812  
   813  // computeTxEnv returns the execution environment of a certain transaction.
   814  func (api *PrivateDebugAPI) computeTxEnv(blockHash common.Hash, txIndex int, reexec uint64) (core.Message, vm.Context, *state.StateDB, error) {
   815  	// Create the parent state database
   816  	block := api.eth.blockchain.GetBlockByHash(blockHash)
   817  	if block == nil {
   818  		return nil, vm.Context{}, nil, fmt.Errorf("block %#x not found", blockHash)
   819  	}
   820  	parent := api.eth.blockchain.GetBlock(block.ParentHash(), block.NumberU64()-1)
   821  	if parent == nil {
   822  		return nil, vm.Context{}, nil, fmt.Errorf("parent %#x not found", block.ParentHash())
   823  	}
   824  	statedb, err := api.computeStateDB(parent, reexec)
   825  	if err != nil {
   826  		return nil, vm.Context{}, nil, err
   827  	}
   828  
   829  	if txIndex == 0 && len(block.Transactions()) == 0 {
   830  		return nil, vm.Context{}, statedb, nil
   831  	}
   832  
   833  	// Recompute transactions up to the target index.
   834  	signer := types.MakeSigner(api.eth.blockchain.Config(), block.Number())
   835  
   836  	for idx, tx := range block.Transactions() {
   837  		// Assemble the transaction call message and return if the requested offset
   838  		msg, _ := tx.AsMessage(signer)
   839  		context := core.NewEVMContext(msg, block.Header(), api.eth.blockchain, nil)
   840  		if idx == txIndex {
   841  			return msg, context, statedb, nil
   842  		}
   843  		// Not yet the searched for transaction, execute on top of the current state
   844  		vmenv := vm.NewEVM(context, statedb, api.eth.blockchain.Config(), vm.Config{})
   845  		if _, _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil {
   846  			return nil, vm.Context{}, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err)
   847  		}
   848  		// Ensure any modifications are committed to the state
   849  		// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
   850  		statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number()))
   851  	}
   852  	return nil, vm.Context{}, nil, fmt.Errorf("transaction index %d out of range for block %#x", txIndex, blockHash)
   853  }