github.com/juliankolbe/go-ethereum@v1.9.992/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/juliankolbe/go-ethereum/common"
    32  	"github.com/juliankolbe/go-ethereum/common/hexutil"
    33  	"github.com/juliankolbe/go-ethereum/consensus"
    34  	"github.com/juliankolbe/go-ethereum/core"
    35  	"github.com/juliankolbe/go-ethereum/core/rawdb"
    36  	"github.com/juliankolbe/go-ethereum/core/state"
    37  	"github.com/juliankolbe/go-ethereum/core/types"
    38  	"github.com/juliankolbe/go-ethereum/core/vm"
    39  	"github.com/juliankolbe/go-ethereum/ethdb"
    40  	"github.com/juliankolbe/go-ethereum/internal/ethapi"
    41  	"github.com/juliankolbe/go-ethereum/log"
    42  	"github.com/juliankolbe/go-ethereum/params"
    43  	"github.com/juliankolbe/go-ethereum/rlp"
    44  	"github.com/juliankolbe/go-ethereum/rpc"
    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  // Backend interface provides the common API services (that are provided by
    59  // both full and light clients) with access to necessary functions.
    60  type Backend interface {
    61  	HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error)
    62  	HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error)
    63  	BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error)
    64  	BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error)
    65  	GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error)
    66  	RPCGasCap() uint64
    67  	ChainConfig() *params.ChainConfig
    68  	Engine() consensus.Engine
    69  	ChainDb() ethdb.Database
    70  	StateAtBlock(ctx context.Context, block *types.Block, reexec uint64) (*state.StateDB, func(), error)
    71  	StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, func(), error)
    72  	StatesInRange(ctx context.Context, fromBlock *types.Block, toBlock *types.Block, reexec uint64) ([]*state.StateDB, func(), error)
    73  }
    74  
    75  // API is the collection of tracing APIs exposed over the private debugging endpoint.
    76  type API struct {
    77  	backend Backend
    78  }
    79  
    80  // NewAPI creates a new API definition for the tracing methods of the Ethereum service.
    81  func NewAPI(backend Backend) *API {
    82  	return &API{backend: backend}
    83  }
    84  
    85  type chainContext struct {
    86  	api *API
    87  	ctx context.Context
    88  }
    89  
    90  func (context *chainContext) Engine() consensus.Engine {
    91  	return context.api.backend.Engine()
    92  }
    93  
    94  func (context *chainContext) GetHeader(hash common.Hash, number uint64) *types.Header {
    95  	header, err := context.api.backend.HeaderByNumber(context.ctx, rpc.BlockNumber(number))
    96  	if err != nil {
    97  		return nil
    98  	}
    99  	if header.Hash() == hash {
   100  		return header
   101  	}
   102  	header, err = context.api.backend.HeaderByHash(context.ctx, hash)
   103  	if err != nil {
   104  		return nil
   105  	}
   106  	return header
   107  }
   108  
   109  // chainContext construts the context reader which is used by the evm for reading
   110  // the necessary chain context.
   111  func (api *API) chainContext(ctx context.Context) core.ChainContext {
   112  	return &chainContext{api: api, ctx: ctx}
   113  }
   114  
   115  // blockByNumber is the wrapper of the chain access function offered by the backend.
   116  // It will return an error if the block is not found.
   117  func (api *API) blockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) {
   118  	block, err := api.backend.BlockByNumber(ctx, number)
   119  	if err != nil {
   120  		return nil, err
   121  	}
   122  	if block == nil {
   123  		return nil, fmt.Errorf("block #%d not found", number)
   124  	}
   125  	return block, nil
   126  }
   127  
   128  // blockByHash is the wrapper of the chain access function offered by the backend.
   129  // It will return an error if the block is not found.
   130  func (api *API) blockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) {
   131  	block, err := api.backend.BlockByHash(ctx, hash)
   132  	if err != nil {
   133  		return nil, err
   134  	}
   135  	if block == nil {
   136  		return nil, fmt.Errorf("block %s not found", hash.Hex())
   137  	}
   138  	return block, nil
   139  }
   140  
   141  // blockByNumberAndHash is the wrapper of the chain access function offered by
   142  // the backend. It will return an error if the block is not found.
   143  //
   144  // Note this function is friendly for the light client which can only retrieve the
   145  // historical(before the CHT) header/block by number.
   146  func (api *API) blockByNumberAndHash(ctx context.Context, number rpc.BlockNumber, hash common.Hash) (*types.Block, error) {
   147  	block, err := api.blockByNumber(ctx, number)
   148  	if err != nil {
   149  		return nil, err
   150  	}
   151  	if block.Hash() == hash {
   152  		return block, nil
   153  	}
   154  	return api.blockByHash(ctx, hash)
   155  }
   156  
   157  // TraceConfig holds extra parameters to trace functions.
   158  type TraceConfig struct {
   159  	*vm.LogConfig
   160  	Tracer  *string
   161  	Timeout *string
   162  	Reexec  *uint64
   163  }
   164  
   165  // StdTraceConfig holds extra parameters to standard-json trace functions.
   166  type StdTraceConfig struct {
   167  	vm.LogConfig
   168  	Reexec *uint64
   169  	TxHash common.Hash
   170  }
   171  
   172  // txTraceResult is the result of a single transaction trace.
   173  type txTraceResult struct {
   174  	Result interface{} `json:"result,omitempty"` // Trace results produced by the tracer
   175  	Error  string      `json:"error,omitempty"`  // Trace failure produced by the tracer
   176  }
   177  
   178  // blockTraceTask represents a single block trace task when an entire chain is
   179  // being traced.
   180  type blockTraceTask struct {
   181  	statedb *state.StateDB   // Intermediate state prepped for tracing
   182  	block   *types.Block     // Block to trace the transactions from
   183  	results []*txTraceResult // Trace results procudes by the task
   184  }
   185  
   186  // blockTraceResult represets the results of tracing a single block when an entire
   187  // chain is being traced.
   188  type blockTraceResult struct {
   189  	Block  hexutil.Uint64   `json:"block"`  // Block number corresponding to this trace
   190  	Hash   common.Hash      `json:"hash"`   // Block hash corresponding to this trace
   191  	Traces []*txTraceResult `json:"traces"` // Trace results produced by the task
   192  }
   193  
   194  // txTraceTask represents a single transaction trace task when an entire block
   195  // is being traced.
   196  type txTraceTask struct {
   197  	statedb *state.StateDB // Intermediate state prepped for tracing
   198  	index   int            // Transaction offset in the block
   199  }
   200  
   201  // TraceChain returns the structured logs created during the execution of EVM
   202  // between two blocks (excluding start) and returns them as a JSON object.
   203  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
   204  	from, err := api.blockByNumber(ctx, start)
   205  	if err != nil {
   206  		return nil, err
   207  	}
   208  	to, err := api.blockByNumber(ctx, end)
   209  	if err != nil {
   210  		return nil, err
   211  	}
   212  	if from.Number().Cmp(to.Number()) >= 0 {
   213  		return nil, fmt.Errorf("end block (#%d) needs to come after start block (#%d)", end, start)
   214  	}
   215  	return api.traceChain(ctx, from, to, config)
   216  }
   217  
   218  // traceChain configures a new tracer according to the provided configuration, and
   219  // executes all the transactions contained within. The return value will be one item
   220  // per transaction, dependent on the requested tracer.
   221  func (api *API) traceChain(ctx context.Context, start, end *types.Block, config *TraceConfig) (*rpc.Subscription, error) {
   222  	// Tracing a chain is a **long** operation, only do with subscriptions
   223  	notifier, supported := rpc.NotifierFromContext(ctx)
   224  	if !supported {
   225  		return &rpc.Subscription{}, rpc.ErrNotificationsUnsupported
   226  	}
   227  	sub := notifier.CreateSubscription()
   228  
   229  	// Shift the border to a block ahead in order to get the states
   230  	// before these blocks.
   231  	endBlock, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(end.NumberU64()-1), end.ParentHash())
   232  	if err != nil {
   233  		return nil, err
   234  	}
   235  	// Prepare all the states for tracing. Note this procedure can take very
   236  	// long time. Timeout mechanism is necessary.
   237  	reexec := defaultTraceReexec
   238  	if config != nil && config.Reexec != nil {
   239  		reexec = *config.Reexec
   240  	}
   241  	states, release, err := api.backend.StatesInRange(ctx, start, endBlock, reexec)
   242  	if err != nil {
   243  		return nil, err
   244  	}
   245  	defer release() // Release all the resources in the last step.
   246  
   247  	blocks := int(end.NumberU64() - start.NumberU64())
   248  	threads := runtime.NumCPU()
   249  	if threads > blocks {
   250  		threads = blocks
   251  	}
   252  	var (
   253  		pend    = new(sync.WaitGroup)
   254  		tasks   = make(chan *blockTraceTask, threads)
   255  		results = make(chan *blockTraceTask, threads)
   256  	)
   257  	for th := 0; th < threads; th++ {
   258  		pend.Add(1)
   259  		go func() {
   260  			defer pend.Done()
   261  
   262  			// Fetch and execute the next block trace tasks
   263  			for task := range tasks {
   264  				signer := types.MakeSigner(api.backend.ChainConfig(), task.block.Number())
   265  				blockCtx := core.NewEVMBlockContext(task.block.Header(), api.chainContext(ctx), nil)
   266  				// Trace all the transactions contained within
   267  				for i, tx := range task.block.Transactions() {
   268  					msg, _ := tx.AsMessage(signer)
   269  					res, err := api.traceTx(ctx, msg, blockCtx, task.statedb, config)
   270  					if err != nil {
   271  						task.results[i] = &txTraceResult{Error: err.Error()}
   272  						log.Warn("Tracing failed", "hash", tx.Hash(), "block", task.block.NumberU64(), "err", err)
   273  						break
   274  					}
   275  					// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
   276  					task.statedb.Finalise(api.backend.ChainConfig().IsEIP158(task.block.Number()))
   277  					task.results[i] = &txTraceResult{Result: res}
   278  				}
   279  				// Stream the result back to the user or abort on teardown
   280  				select {
   281  				case results <- task:
   282  				case <-notifier.Closed():
   283  					return
   284  				}
   285  			}
   286  		}()
   287  	}
   288  	// Start a goroutine to feed all the blocks into the tracers
   289  	begin := time.Now()
   290  
   291  	go func() {
   292  		var (
   293  			logged time.Time
   294  			number uint64
   295  			traced uint64
   296  			failed error
   297  		)
   298  		// Ensure everything is properly cleaned up on any exit path
   299  		defer func() {
   300  			close(tasks)
   301  			pend.Wait()
   302  
   303  			switch {
   304  			case failed != nil:
   305  				log.Warn("Chain tracing failed", "start", start.NumberU64(), "end", end.NumberU64(), "transactions", traced, "elapsed", time.Since(begin), "err", failed)
   306  			case number < end.NumberU64():
   307  				log.Warn("Chain tracing aborted", "start", start.NumberU64(), "end", end.NumberU64(), "abort", number, "transactions", traced, "elapsed", time.Since(begin))
   308  			default:
   309  				log.Info("Chain tracing finished", "start", start.NumberU64(), "end", end.NumberU64(), "transactions", traced, "elapsed", time.Since(begin))
   310  			}
   311  			close(results)
   312  		}()
   313  		// Feed all the blocks both into the tracer, as well as fast process concurrently
   314  		for number = start.NumberU64() + 1; number <= end.NumberU64(); number++ {
   315  			// Stop tracing if interruption was requested
   316  			select {
   317  			case <-notifier.Closed():
   318  				return
   319  			default:
   320  			}
   321  			// Print progress logs if long enough time elapsed
   322  			if time.Since(logged) > 8*time.Second {
   323  				logged = time.Now()
   324  				log.Info("Tracing chain segment", "start", start.NumberU64(), "end", end.NumberU64(), "current", number, "transactions", traced, "elapsed", time.Since(begin))
   325  			}
   326  			// Retrieve the next block to trace
   327  			block, err := api.blockByNumber(ctx, rpc.BlockNumber(number))
   328  			if err != nil {
   329  				failed = err
   330  				break
   331  			}
   332  			// Send the block over to the concurrent tracers (if not in the fast-forward phase)
   333  			txs := block.Transactions()
   334  			select {
   335  			case tasks <- &blockTraceTask{statedb: states[int(number-start.NumberU64()-1)], block: block, results: make([]*txTraceResult, len(txs))}:
   336  			case <-notifier.Closed():
   337  				return
   338  			}
   339  			traced += uint64(len(txs))
   340  		}
   341  	}()
   342  
   343  	// Keep reading the trace results and stream the to the user
   344  	go func() {
   345  		var (
   346  			done = make(map[uint64]*blockTraceResult)
   347  			next = start.NumberU64() + 1
   348  		)
   349  		for res := range results {
   350  			// Queue up next received result
   351  			result := &blockTraceResult{
   352  				Block:  hexutil.Uint64(res.block.NumberU64()),
   353  				Hash:   res.block.Hash(),
   354  				Traces: res.results,
   355  			}
   356  			done[uint64(result.Block)] = result
   357  
   358  			// Stream completed traces to the user, aborting on the first error
   359  			for result, ok := done[next]; ok; result, ok = done[next] {
   360  				if len(result.Traces) > 0 || next == end.NumberU64() {
   361  					notifier.Notify(sub.ID, result)
   362  				}
   363  				delete(done, next)
   364  				next++
   365  			}
   366  		}
   367  	}()
   368  	return sub, nil
   369  }
   370  
   371  // TraceBlockByNumber returns the structured logs created during the execution of
   372  // EVM and returns them as a JSON object.
   373  func (api *API) TraceBlockByNumber(ctx context.Context, number rpc.BlockNumber, config *TraceConfig) ([]*txTraceResult, error) {
   374  	block, err := api.blockByNumber(ctx, number)
   375  	if err != nil {
   376  		return nil, err
   377  	}
   378  	return api.traceBlock(ctx, block, config)
   379  }
   380  
   381  // TraceBlockByHash returns the structured logs created during the execution of
   382  // EVM and returns them as a JSON object.
   383  func (api *API) TraceBlockByHash(ctx context.Context, hash common.Hash, config *TraceConfig) ([]*txTraceResult, error) {
   384  	block, err := api.blockByHash(ctx, hash)
   385  	if err != nil {
   386  		return nil, err
   387  	}
   388  	return api.traceBlock(ctx, block, config)
   389  }
   390  
   391  // TraceBlock returns the structured logs created during the execution of EVM
   392  // and returns them as a JSON object.
   393  func (api *API) TraceBlock(ctx context.Context, blob []byte, config *TraceConfig) ([]*txTraceResult, error) {
   394  	block := new(types.Block)
   395  	if err := rlp.Decode(bytes.NewReader(blob), block); err != nil {
   396  		return nil, fmt.Errorf("could not decode block: %v", err)
   397  	}
   398  	return api.traceBlock(ctx, block, config)
   399  }
   400  
   401  // TraceBlockFromFile returns the structured logs created during the execution of
   402  // EVM and returns them as a JSON object.
   403  func (api *API) TraceBlockFromFile(ctx context.Context, file string, config *TraceConfig) ([]*txTraceResult, error) {
   404  	blob, err := ioutil.ReadFile(file)
   405  	if err != nil {
   406  		return nil, fmt.Errorf("could not read file: %v", err)
   407  	}
   408  	return api.TraceBlock(ctx, blob, config)
   409  }
   410  
   411  // TraceBadBlock returns the structured logs created during the execution of
   412  // EVM against a block pulled from the pool of bad ones and returns them as a JSON
   413  // object.
   414  func (api *API) TraceBadBlock(ctx context.Context, hash common.Hash, config *TraceConfig) ([]*txTraceResult, error) {
   415  	for _, block := range rawdb.ReadAllBadBlocks(api.backend.ChainDb()) {
   416  		if block.Hash() == hash {
   417  			return api.traceBlock(ctx, block, config)
   418  		}
   419  	}
   420  	return nil, fmt.Errorf("bad block %#x not found", hash)
   421  }
   422  
   423  // StandardTraceBlockToFile dumps the structured logs created during the
   424  // execution of EVM to the local file system and returns a list of files
   425  // to the caller.
   426  func (api *API) StandardTraceBlockToFile(ctx context.Context, hash common.Hash, config *StdTraceConfig) ([]string, error) {
   427  	block, err := api.blockByHash(ctx, hash)
   428  	if err != nil {
   429  		return nil, err
   430  	}
   431  	return api.standardTraceBlockToFile(ctx, block, config)
   432  }
   433  
   434  // StandardTraceBadBlockToFile dumps the structured logs created during the
   435  // execution of EVM against a block pulled from the pool of bad ones to the
   436  // local file system and returns a list of files to the caller.
   437  func (api *API) StandardTraceBadBlockToFile(ctx context.Context, hash common.Hash, config *StdTraceConfig) ([]string, error) {
   438  	for _, block := range rawdb.ReadAllBadBlocks(api.backend.ChainDb()) {
   439  		if block.Hash() == hash {
   440  			return api.standardTraceBlockToFile(ctx, block, config)
   441  		}
   442  	}
   443  	return nil, fmt.Errorf("bad block %#x not found", hash)
   444  }
   445  
   446  // traceBlock configures a new tracer according to the provided configuration, and
   447  // executes all the transactions contained within. The return value will be one item
   448  // per transaction, dependent on the requestd tracer.
   449  func (api *API) traceBlock(ctx context.Context, block *types.Block, config *TraceConfig) ([]*txTraceResult, error) {
   450  	if block.NumberU64() == 0 {
   451  		return nil, errors.New("genesis is not traceable")
   452  	}
   453  	parent, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(block.NumberU64()-1), block.ParentHash())
   454  	if err != nil {
   455  		return nil, err
   456  	}
   457  	reexec := defaultTraceReexec
   458  	if config != nil && config.Reexec != nil {
   459  		reexec = *config.Reexec
   460  	}
   461  	statedb, release, err := api.backend.StateAtBlock(ctx, parent, reexec)
   462  	if err != nil {
   463  		return nil, err
   464  	}
   465  	defer release()
   466  
   467  	// Execute all the transaction contained within the block concurrently
   468  	var (
   469  		signer  = types.MakeSigner(api.backend.ChainConfig(), block.Number())
   470  		txs     = block.Transactions()
   471  		results = make([]*txTraceResult, len(txs))
   472  
   473  		pend = new(sync.WaitGroup)
   474  		jobs = make(chan *txTraceTask, len(txs))
   475  	)
   476  	threads := runtime.NumCPU()
   477  	if threads > len(txs) {
   478  		threads = len(txs)
   479  	}
   480  	blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
   481  	for th := 0; th < threads; th++ {
   482  		pend.Add(1)
   483  		go func() {
   484  			defer pend.Done()
   485  			// Fetch and execute the next transaction trace tasks
   486  			for task := range jobs {
   487  				msg, _ := txs[task.index].AsMessage(signer)
   488  				res, err := api.traceTx(ctx, msg, blockCtx, task.statedb, config)
   489  				if err != nil {
   490  					results[task.index] = &txTraceResult{Error: err.Error()}
   491  					continue
   492  				}
   493  				results[task.index] = &txTraceResult{Result: res}
   494  			}
   495  		}()
   496  	}
   497  	// Feed the transactions into the tracers and return
   498  	var failed error
   499  	for i, tx := range txs {
   500  		// Send the trace task over for execution
   501  		jobs <- &txTraceTask{statedb: statedb.Copy(), index: i}
   502  
   503  		// Generate the next state snapshot fast without tracing
   504  		msg, _ := tx.AsMessage(signer)
   505  		txContext := core.NewEVMTxContext(msg)
   506  
   507  		vmenv := vm.NewEVM(blockCtx, txContext, statedb, api.backend.ChainConfig(), vm.Config{})
   508  		if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil {
   509  			failed = err
   510  			break
   511  		}
   512  		// Finalize the state so any modifications are written to the trie
   513  		// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
   514  		statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number()))
   515  	}
   516  	close(jobs)
   517  	pend.Wait()
   518  
   519  	// If execution failed in between, abort
   520  	if failed != nil {
   521  		return nil, failed
   522  	}
   523  	return results, nil
   524  }
   525  
   526  // standardTraceBlockToFile configures a new tracer which uses standard JSON output,
   527  // and traces either a full block or an individual transaction. The return value will
   528  // be one filename per transaction traced.
   529  func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block, config *StdTraceConfig) ([]string, error) {
   530  	// If we're tracing a single transaction, make sure it's present
   531  	if config != nil && config.TxHash != (common.Hash{}) {
   532  		if !containsTx(block, config.TxHash) {
   533  			return nil, fmt.Errorf("transaction %#x not found in block", config.TxHash)
   534  		}
   535  	}
   536  	if block.NumberU64() == 0 {
   537  		return nil, errors.New("genesis is not traceable")
   538  	}
   539  	parent, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(block.NumberU64()-1), block.ParentHash())
   540  	if err != nil {
   541  		return nil, err
   542  	}
   543  	reexec := defaultTraceReexec
   544  	if config != nil && config.Reexec != nil {
   545  		reexec = *config.Reexec
   546  	}
   547  	statedb, release, err := api.backend.StateAtBlock(ctx, parent, reexec)
   548  	if err != nil {
   549  		return nil, err
   550  	}
   551  	defer release()
   552  
   553  	// Retrieve the tracing configurations, or use default values
   554  	var (
   555  		logConfig vm.LogConfig
   556  		txHash    common.Hash
   557  	)
   558  	if config != nil {
   559  		logConfig = config.LogConfig
   560  		txHash = config.TxHash
   561  	}
   562  	logConfig.Debug = true
   563  
   564  	// Execute transaction, either tracing all or just the requested one
   565  	var (
   566  		dumps       []string
   567  		signer      = types.MakeSigner(api.backend.ChainConfig(), block.Number())
   568  		chainConfig = api.backend.ChainConfig()
   569  		vmctx       = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
   570  		canon       = true
   571  	)
   572  	// Check if there are any overrides: the caller may wish to enable a future
   573  	// fork when executing this block. Note, such overrides are only applicable to the
   574  	// actual specified block, not any preceding blocks that we have to go through
   575  	// in order to obtain the state.
   576  	// Therefore, it's perfectly valid to specify `"futureForkBlock": 0`, to enable `futureFork`
   577  
   578  	if config != nil && config.Overrides != nil {
   579  		// Copy the config, to not screw up the main config
   580  		// Note: the Clique-part is _not_ deep copied
   581  		chainConfigCopy := new(params.ChainConfig)
   582  		*chainConfigCopy = *chainConfig
   583  		chainConfig = chainConfigCopy
   584  		if yolov3 := config.LogConfig.Overrides.YoloV3Block; yolov3 != nil {
   585  			chainConfig.YoloV3Block = yolov3
   586  			canon = false
   587  		}
   588  	}
   589  	for i, tx := range block.Transactions() {
   590  		// Prepare the trasaction for un-traced execution
   591  		var (
   592  			msg, _    = tx.AsMessage(signer)
   593  			txContext = core.NewEVMTxContext(msg)
   594  			vmConf    vm.Config
   595  			dump      *os.File
   596  			writer    *bufio.Writer
   597  			err       error
   598  		)
   599  		// If the transaction needs tracing, swap out the configs
   600  		if tx.Hash() == txHash || txHash == (common.Hash{}) {
   601  			// Generate a unique temporary file to dump it into
   602  			prefix := fmt.Sprintf("block_%#x-%d-%#x-", block.Hash().Bytes()[:4], i, tx.Hash().Bytes()[:4])
   603  			if !canon {
   604  				prefix = fmt.Sprintf("%valt-", prefix)
   605  			}
   606  			dump, err = ioutil.TempFile(os.TempDir(), prefix)
   607  			if err != nil {
   608  				return nil, err
   609  			}
   610  			dumps = append(dumps, dump.Name())
   611  
   612  			// Swap out the noop logger to the standard tracer
   613  			writer = bufio.NewWriter(dump)
   614  			vmConf = vm.Config{
   615  				Debug:                   true,
   616  				Tracer:                  vm.NewJSONLogger(&logConfig, writer),
   617  				EnablePreimageRecording: true,
   618  			}
   619  		}
   620  		// Execute the transaction and flush any traces to disk
   621  		vmenv := vm.NewEVM(vmctx, txContext, statedb, chainConfig, vmConf)
   622  		_, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()))
   623  		if writer != nil {
   624  			writer.Flush()
   625  		}
   626  		if dump != nil {
   627  			dump.Close()
   628  			log.Info("Wrote standard trace", "file", dump.Name())
   629  		}
   630  		if err != nil {
   631  			return dumps, err
   632  		}
   633  		// Finalize the state so any modifications are written to the trie
   634  		// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
   635  		statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number()))
   636  
   637  		// If we've traced the transaction we were looking for, abort
   638  		if tx.Hash() == txHash {
   639  			break
   640  		}
   641  	}
   642  	return dumps, nil
   643  }
   644  
   645  // containsTx reports whether the transaction with a certain hash
   646  // is contained within the specified block.
   647  func containsTx(block *types.Block, hash common.Hash) bool {
   648  	for _, tx := range block.Transactions() {
   649  		if tx.Hash() == hash {
   650  			return true
   651  		}
   652  	}
   653  	return false
   654  }
   655  
   656  // TraceTransaction returns the structured logs created during the execution of EVM
   657  // and returns them as a JSON object.
   658  func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config *TraceConfig) (interface{}, error) {
   659  	_, blockHash, blockNumber, index, err := api.backend.GetTransaction(ctx, hash)
   660  	if err != nil {
   661  		return nil, err
   662  	}
   663  	// It shouldn't happen in practice.
   664  	if blockNumber == 0 {
   665  		return nil, errors.New("genesis is not traceable")
   666  	}
   667  	reexec := defaultTraceReexec
   668  	if config != nil && config.Reexec != nil {
   669  		reexec = *config.Reexec
   670  	}
   671  	block, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(blockNumber), blockHash)
   672  	if err != nil {
   673  		return nil, err
   674  	}
   675  	msg, vmctx, statedb, release, err := api.backend.StateAtTransaction(ctx, block, int(index), reexec)
   676  	if err != nil {
   677  		return nil, err
   678  	}
   679  	defer release()
   680  
   681  	return api.traceTx(ctx, msg, vmctx, statedb, config)
   682  }
   683  
   684  // TraceCall lets you trace a given eth_call. It collects the structured logs
   685  // created during the execution of EVM if the given transaction was added on
   686  // top of the provided block and returns them as a JSON object.
   687  // You can provide -2 as a block number to trace on top of the pending block.
   688  func (api *API) TraceCall(ctx context.Context, args ethapi.CallArgs, blockNrOrHash rpc.BlockNumberOrHash, config *TraceConfig) (interface{}, error) {
   689  	// Try to retrieve the specified block
   690  	var (
   691  		err   error
   692  		block *types.Block
   693  	)
   694  	if hash, ok := blockNrOrHash.Hash(); ok {
   695  		block, err = api.blockByHash(ctx, hash)
   696  	} else if number, ok := blockNrOrHash.Number(); ok {
   697  		block, err = api.blockByNumber(ctx, number)
   698  	}
   699  	if err != nil {
   700  		return nil, err
   701  	}
   702  	// try to recompute the state
   703  	reexec := defaultTraceReexec
   704  	if config != nil && config.Reexec != nil {
   705  		reexec = *config.Reexec
   706  	}
   707  	statedb, release, err := api.backend.StateAtBlock(ctx, block, reexec)
   708  	if err != nil {
   709  		return nil, err
   710  	}
   711  	defer release()
   712  
   713  	// Execute the trace
   714  	msg := args.ToMessage(api.backend.RPCGasCap())
   715  	vmctx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
   716  	return api.traceTx(ctx, msg, vmctx, statedb, config)
   717  }
   718  
   719  // traceTx configures a new tracer according to the provided configuration, and
   720  // executes the given message in the provided environment. The return value will
   721  // be tracer dependent.
   722  func (api *API) traceTx(ctx context.Context, message core.Message, vmctx vm.BlockContext, statedb *state.StateDB, config *TraceConfig) (interface{}, error) {
   723  	// Assemble the structured logger or the JavaScript tracer
   724  	var (
   725  		tracer    vm.Tracer
   726  		err       error
   727  		txContext = core.NewEVMTxContext(message)
   728  	)
   729  	switch {
   730  	case config != nil && config.Tracer != nil:
   731  		// Define a meaningful timeout of a single transaction trace
   732  		timeout := defaultTraceTimeout
   733  		if config.Timeout != nil {
   734  			if timeout, err = time.ParseDuration(*config.Timeout); err != nil {
   735  				return nil, err
   736  			}
   737  		}
   738  		// Constuct the JavaScript tracer to execute with
   739  		if tracer, err = New(*config.Tracer, txContext); err != nil {
   740  			return nil, err
   741  		}
   742  		// Handle timeouts and RPC cancellations
   743  		deadlineCtx, cancel := context.WithTimeout(ctx, timeout)
   744  		go func() {
   745  			<-deadlineCtx.Done()
   746  			tracer.(*Tracer).Stop(errors.New("execution timeout"))
   747  		}()
   748  		defer cancel()
   749  
   750  	case config == nil:
   751  		tracer = vm.NewStructLogger(nil)
   752  
   753  	default:
   754  		tracer = vm.NewStructLogger(config.LogConfig)
   755  	}
   756  
   757  	// Run the transaction with tracing enabled.
   758  	vmenv := vm.NewEVM(vmctx, txContext, statedb, api.backend.ChainConfig(), vm.Config{Debug: true, Tracer: tracer})
   759  	result, err := core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas()))
   760  	if err != nil {
   761  		return nil, fmt.Errorf("tracing failed: %v", err)
   762  	}
   763  
   764  	// Depending on the tracer type, format and return the output.
   765  	switch tracer := tracer.(type) {
   766  	case *vm.StructLogger:
   767  		// If the result contains a revert reason, return it.
   768  		returnVal := fmt.Sprintf("%x", result.Return())
   769  		if len(result.Revert()) > 0 {
   770  			returnVal = fmt.Sprintf("%x", result.Revert())
   771  		}
   772  		return &ethapi.ExecutionResult{
   773  			Gas:         result.UsedGas,
   774  			Failed:      result.Failed(),
   775  			ReturnValue: returnVal,
   776  			StructLogs:  ethapi.FormatLogs(tracer.StructLogs()),
   777  		}, nil
   778  
   779  	case *Tracer:
   780  		return tracer.GetResult()
   781  
   782  	default:
   783  		panic(fmt.Sprintf("bad tracer type %T", tracer))
   784  	}
   785  }
   786  
   787  // APIs return the collection of RPC services the tracer package offers.
   788  func APIs(backend Backend) []rpc.API {
   789  	// Append all the local APIs and return
   790  	return []rpc.API{
   791  		{
   792  			Namespace: "debug",
   793  			Version:   "1.0",
   794  			Service:   NewAPI(backend),
   795  			Public:    false,
   796  		},
   797  	}
   798  }