github.com/phillinzzz/newBsc@v1.1.6/eth/tracers/api.go (about)

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