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