github.com/amazechain/amc@v0.1.3/internal/tracers/api.go (about)

     1  // Copyright 2023 The AmazeChain Authors
     2  // This file is part of the AmazeChain library.
     3  //
     4  // The AmazeChain 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 AmazeChain 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 AmazeChain library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package tracers
    18  
    19  import (
    20  	"bytes"
    21  	"context"
    22  	"encoding/json"
    23  	"errors"
    24  	"fmt"
    25  	common2 "github.com/amazechain/amc/common"
    26  	"github.com/amazechain/amc/common/transaction"
    27  	"github.com/amazechain/amc/internal/api"
    28  	"github.com/amazechain/amc/internal/avm/rlp"
    29  	"github.com/amazechain/amc/internal/vm/evmtypes"
    30  	"github.com/ledgerwatch/erigon-lib/kv"
    31  	"time"
    32  
    33  	types "github.com/amazechain/amc/common/block"
    34  	"github.com/amazechain/amc/common/hexutil"
    35  	common "github.com/amazechain/amc/common/types"
    36  	core "github.com/amazechain/amc/internal"
    37  	"github.com/amazechain/amc/internal/consensus"
    38  	"github.com/amazechain/amc/internal/tracers/logger"
    39  	"github.com/amazechain/amc/internal/vm"
    40  	rpc "github.com/amazechain/amc/modules/rpc/jsonrpc"
    41  	"github.com/amazechain/amc/modules/state"
    42  	"github.com/amazechain/amc/params"
    43  )
    44  
    45  const (
    46  	// defaultTraceTimeout is the amount of time a single transaction can execute
    47  	// by default before being forcefully aborted.
    48  	defaultTraceTimeout = 5 * time.Second
    49  
    50  	// defaultTraceReexec is the number of blocks the tracer is willing to go back
    51  	// and reexecute to produce missing historical state necessary to run a specific
    52  	// trace.
    53  	defaultTraceReexec = uint64(128)
    54  
    55  	// defaultTracechainMemLimit is the size of the triedb, at which traceChain
    56  	// switches over and tries to use a disk-backed database instead of building
    57  	// on top of memory.
    58  	// For non-archive nodes, this limit _will_ be overblown, as disk-backed tries
    59  	// will only be found every ~15K blocks or so.
    60  	defaultTracechainMemLimit = common.StorageSize(500 * 1024 * 1024)
    61  
    62  	// maximumPendingTraceStates is the maximum number of states allowed waiting
    63  	// for tracing. The creation of trace state will be paused if the unused
    64  	// trace states exceed this limit.
    65  	maximumPendingTraceStates = 128
    66  )
    67  
    68  var errTxNotFound = errors.New("transaction not found")
    69  
    70  // StateReleaseFunc is used to deallocate resources held by constructing a
    71  // historical state for tracing purposes.
    72  type StateReleaseFunc func()
    73  
    74  // Backend interface provides the common API services (that are provided by
    75  // both full and light clients) with access to necessary functions.
    76  type Backend interface {
    77  	HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error)
    78  	HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error)
    79  	BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error)
    80  	BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error)
    81  	GetTransaction(ctx context.Context, txHash common.Hash) (*transaction.Transaction, common.Hash, uint64, uint64, error)
    82  	RPCGasCap() uint64
    83  	ChainConfig() *params.ChainConfig
    84  	Engine() consensus.Engine
    85  	ChainDb() kv.RwDB
    86  	StateAtBlock(ctx context.Context, tx kv.Tx, block *types.Block /*, reexec uint64, base *state.IntraBlockState, readOnly bool, preferDisk bool*/) (*state.IntraBlockState, error)
    87  	StateAtTransaction(ctx context.Context, tx kv.Tx, block *types.Block, txIndex int /*, reexec uint64*/) (*transaction.Message, evmtypes.BlockContext, *state.IntraBlockState, error)
    88  }
    89  
    90  // API is the collection of tracing APIs exposed over the private debugging endpoint.
    91  type API struct {
    92  	backend Backend
    93  }
    94  
    95  // NewAPI creates a new API definition for the tracing methods of the Ethereum service.
    96  func NewAPI(backend Backend) *API {
    97  	return &API{backend: backend}
    98  }
    99  
   100  type chainContext struct {
   101  	api *API
   102  	ctx context.Context
   103  }
   104  
   105  func (context *chainContext) Engine() consensus.Engine {
   106  	return context.api.backend.Engine()
   107  }
   108  
   109  func (context *chainContext) GetHeader(hash common.Hash, number uint64) *types.Header {
   110  	header, err := context.api.backend.HeaderByNumber(context.ctx, rpc.BlockNumber(number))
   111  	if err != nil {
   112  		return nil
   113  	}
   114  	if header.Hash() == hash {
   115  		return header
   116  	}
   117  	header, err = context.api.backend.HeaderByHash(context.ctx, hash)
   118  	if err != nil {
   119  		return nil
   120  	}
   121  	return header
   122  }
   123  
   124  // chainContext constructs the context reader which is used by the evm for reading
   125  // the necessary chain context.
   126  //func (api *API) chainContext(ctx context.Context) core.ChainContext {
   127  //	return &chainContext{api: api, ctx: ctx}
   128  //}
   129  
   130  // blockByNumber is the wrapper of the chain access function offered by the backend.
   131  // It will return an error if the block is not found.
   132  func (api *API) blockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) {
   133  	block, err := api.backend.BlockByNumber(ctx, number)
   134  	if err != nil {
   135  		return nil, err
   136  	}
   137  	if block == nil {
   138  		return nil, fmt.Errorf("block #%d not found", number)
   139  	}
   140  	return block, nil
   141  }
   142  
   143  // blockByHash is the wrapper of the chain access function offered by the backend.
   144  // It will return an error if the block is not found.
   145  func (api *API) blockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) {
   146  	block, err := api.backend.BlockByHash(ctx, hash)
   147  	if err != nil {
   148  		return nil, err
   149  	}
   150  	if block == nil {
   151  		return nil, fmt.Errorf("block %s not found", hash.Hex())
   152  	}
   153  	return block, nil
   154  }
   155  
   156  // blockByNumberAndHash is the wrapper of the chain access function offered by
   157  // the backend. It will return an error if the block is not found.
   158  //
   159  // Note this function is friendly for the light client which can only retrieve the
   160  // historical(before the CHT) header/block by number.
   161  func (api *API) blockByNumberAndHash(ctx context.Context, number rpc.BlockNumber, hash common.Hash) (*types.Block, error) {
   162  	block, err := api.blockByNumber(ctx, number)
   163  	if err != nil {
   164  		return nil, err
   165  	}
   166  	if block.Hash() == hash {
   167  		return block, nil
   168  	}
   169  	return api.blockByHash(ctx, hash)
   170  }
   171  
   172  // TraceConfig holds extra parameters to trace functions.
   173  type TraceConfig struct {
   174  	*logger.Config
   175  	Tracer  *string
   176  	Timeout *string
   177  	Reexec  *uint64
   178  	// Config specific to given tracer. Note struct logger
   179  	// config are historically embedded in main object.
   180  	TracerConfig json.RawMessage
   181  }
   182  
   183  // TraceCallConfig is the config for traceCall API. It holds one more
   184  // field to override the state for tracing.
   185  type TraceCallConfig struct {
   186  	TraceConfig
   187  	StateOverrides *api.StateOverride
   188  	BlockOverrides *api.BlockOverrides
   189  }
   190  
   191  // StdTraceConfig holds extra parameters to standard-json trace functions.
   192  type StdTraceConfig struct {
   193  	logger.Config
   194  	Reexec *uint64
   195  	TxHash common.Hash
   196  }
   197  
   198  // txTraceResult is the result of a single transaction trace.
   199  type txTraceResult struct {
   200  	Result interface{} `json:"result,omitempty"` // Trace results produced by the tracer
   201  	Error  string      `json:"error,omitempty"`  // Trace failure produced by the tracer
   202  }
   203  
   204  // blockTraceTask represents a single block trace task when an entire chain is
   205  // being traced.
   206  type blockTraceTask struct {
   207  	statedb *state.IntraBlockState // Intermediate state prepped for tracing
   208  	block   *types.Block           // Block to trace the transactions from
   209  	release StateReleaseFunc       // The function to release the held resource for this task
   210  	results []*txTraceResult       // Trace results produced by the task
   211  }
   212  
   213  // blockTraceResult represents the results of tracing a single block when an entire
   214  // chain is being traced.
   215  type blockTraceResult struct {
   216  	Block  hexutil.Uint64   `json:"block"`  // Block number corresponding to this trace
   217  	Hash   common.Hash      `json:"hash"`   // Block hash corresponding to this trace
   218  	Traces []*txTraceResult `json:"traces"` // Trace results produced by the task
   219  }
   220  
   221  // txTraceTask represents a single transaction trace task when an entire block
   222  // is being traced.
   223  type txTraceTask struct {
   224  	statedb *state.IntraBlockState // Intermediate state prepped for tracing
   225  	index   int                    // Transaction offset in the block
   226  }
   227  
   228  // TraceChain returns the structured logs created during the execution of EVM
   229  // between two blocks (excluding start) and returns them as a JSON object.
   230  //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
   231  //	from, err := api.blockByNumber(ctx, start)
   232  //	if err != nil {
   233  //		return nil, err
   234  //	}
   235  //	to, err := api.blockByNumber(ctx, end)
   236  //	if err != nil {
   237  //		return nil, err
   238  //	}
   239  //	if from.Number64().Cmp(to.Number64()) >= 0 {
   240  //		return nil, fmt.Errorf("end block (#%d) needs to come after start block (#%d)", end, start)
   241  //	}
   242  //	// Tracing a chain is a **long** operation, only do with subscriptions
   243  //	notifier, supported := rpc.NotifierFromContext(ctx)
   244  //	if !supported {
   245  //		return &rpc.Subscription{}, rpc.ErrNotificationsUnsupported
   246  //	}
   247  //	sub := notifier.CreateSubscription()
   248  //
   249  //	resCh := api.traceChain(from, to, config, notifier.Closed())
   250  //	go func() {
   251  //		for result := range resCh {
   252  //			notifier.Notify(sub.ID, result)
   253  //		}
   254  //	}()
   255  //	return sub, nil
   256  //}
   257  
   258  // traceChain configures a new tracer according to the provided configuration, and
   259  // executes all the transactions contained within. The tracing chain range includes
   260  // the end block but excludes the start one. The return value will be one item per
   261  // transaction, dependent on the requested tracer.
   262  // The tracing procedure should be aborted in case the closed signal is received.
   263  //func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed <-chan interface{}) chan *blockTraceResult {
   264  //	reexec := defaultTraceReexec
   265  //	if config != nil && config.Reexec != nil {
   266  //		reexec = *config.Reexec
   267  //	}
   268  //	blocks := int(end.Number64().Uint64() - start.Number64().Uint64())
   269  //	threads := runtime.NumCPU()
   270  //	if threads > blocks {
   271  //		threads = blocks
   272  //	}
   273  //	var (
   274  //		pend    = new(sync.WaitGroup)
   275  //		ctx     = context.Background()
   276  //		taskCh  = make(chan *blockTraceTask, threads)
   277  //		resCh   = make(chan *blockTraceTask, threads)
   278  //		tracker = newStateTracker(maximumPendingTraceStates, start.Number64().Uint64())
   279  //	)
   280  //	for th := 0; th < threads; th++ {
   281  //		pend.Add(1)
   282  //		go func() {
   283  //			defer pend.Done()
   284  //
   285  //			// Fetch and execute the block trace taskCh
   286  //			for task := range taskCh {
   287  //				var (
   288  //					signer   = transaction.MakeSigner(api.backend.ChainConfig(), task.block.Number64().ToBig())
   289  //					blockCtx = core.NewEVMBlockContext(task.block.Header(), api.chainContext(ctx), nil)
   290  //				)
   291  //				// Trace all the transactions contained within
   292  //				for i, tx := range task.block.Transactions() {
   293  //					msg, _ := core.TransactionToMessage(tx, signer, task.block.BaseFee())
   294  //					txctx := &Context{
   295  //						BlockHash:   task.block.Hash(),
   296  //						BlockNumber: task.block.Number64().ToBig(),
   297  //						TxIndex:     i,
   298  //						TxHash:      tx.Hash(),
   299  //					}
   300  //					res, err := api.traceTx(ctx, msg, txctx, blockCtx, task.statedb, config)
   301  //					if err != nil {
   302  //						task.results[i] = &txTraceResult{Error: err.Error()}
   303  //						log.Warn("Tracing failed", "hash", tx.Hash(), "block", task.block.NumberU64(), "err", err)
   304  //						break
   305  //					}
   306  //					// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
   307  //					task.statedb.Finalise(api.backend.ChainConfig().IsEIP158(task.block.Number()))
   308  //					task.results[i] = &txTraceResult{Result: res}
   309  //				}
   310  //				// Tracing state is used up, queue it for de-referencing. Note the
   311  //				// state is the parent state of trace block, use block.number-1 as
   312  //				// the state number.
   313  //				tracker.releaseState(task.block.NumberU64()-1, task.release)
   314  //
   315  //				// Stream the result back to the result catcher or abort on teardown
   316  //				select {
   317  //				case resCh <- task:
   318  //				case <-closed:
   319  //					return
   320  //				}
   321  //			}
   322  //		}()
   323  //	}
   324  //	// Start a goroutine to feed all the blocks into the tracers
   325  //	go func() {
   326  //		var (
   327  //			logged  time.Time
   328  //			begin   = time.Now()
   329  //			number  uint64
   330  //			traced  uint64
   331  //			failed  error
   332  //			statedb *state.IntraBlockState
   333  //			release StateReleaseFunc
   334  //		)
   335  //		// Ensure everything is properly cleaned up on any exit path
   336  //		defer func() {
   337  //			close(taskCh)
   338  //			pend.Wait()
   339  //
   340  //			// Clean out any pending release functions of trace states.
   341  //			tracker.callReleases()
   342  //
   343  //			// Log the chain result
   344  //			switch {
   345  //			case failed != nil:
   346  //				log.Warn("Chain tracing failed", "start", start.Number64(), "end", end.Number64(), "transactions", traced, "elapsed", time.Since(begin), "err", failed)
   347  //			case number < end.Number64().Uint64():
   348  //				log.Warn("Chain tracing aborted", "start", start.Number64(), "end", end.Number64(), "abort", number, "transactions", traced, "elapsed", time.Since(begin))
   349  //			default:
   350  //				log.Info("Chain tracing finished", "start", start.Number64(), "end", end.Number64(), "transactions", traced, "elapsed", time.Since(begin))
   351  //			}
   352  //			close(resCh)
   353  //		}()
   354  //		// Feed all the blocks both into the tracer, as well as fast process concurrently
   355  //		for number = start.Number64().Uint64(); number < end.Number64().Uint64(); number++ {
   356  //			// Stop tracing if interruption was requested
   357  //			select {
   358  //			case <-closed:
   359  //				return
   360  //			default:
   361  //			}
   362  //			// Print progress logs if long enough time elapsed
   363  //			if time.Since(logged) > 8*time.Second {
   364  //				logged = time.Now()
   365  //				log.Info("Tracing chain segment", "start", start.NumberU64(), "end", end.NumberU64(), "current", number, "transactions", traced, "elapsed", time.Since(begin))
   366  //			}
   367  //			// Retrieve the parent block and target block for tracing.
   368  //			block, err := api.blockByNumber(ctx, rpc.BlockNumber(number))
   369  //			if err != nil {
   370  //				failed = err
   371  //				break
   372  //			}
   373  //			next, err := api.blockByNumber(ctx, rpc.BlockNumber(number+1))
   374  //			if err != nil {
   375  //				failed = err
   376  //				break
   377  //			}
   378  //			// Make sure the state creator doesn't go too far. Too many unprocessed
   379  //			// trace state may cause the oldest state to become stale(e.g. in
   380  //			// path-based scheme).
   381  //			if err = tracker.wait(number); err != nil {
   382  //				failed = err
   383  //				break
   384  //			}
   385  //			// Prepare the statedb for tracing. Don't use the live database for
   386  //			// tracing to avoid persisting state junks into the database. Switch
   387  //			// over to `preferDisk` mode only if the memory usage exceeds the
   388  //			// limit, the trie database will be reconstructed from scratch only
   389  //			// if the relevant state is available in disk.
   390  //			var preferDisk bool
   391  //			if statedb != nil {
   392  //				s1, s2 := statedb.Database().TrieDB().Size()
   393  //				preferDisk = s1+s2 > defaultTracechainMemLimit
   394  //			}
   395  //			statedb, release, err = api.backend.StateAtBlock(ctx, block, reexec, statedb, false, preferDisk)
   396  //			if err != nil {
   397  //				failed = err
   398  //				break
   399  //			}
   400  //			// Clean out any pending release functions of trace state. Note this
   401  //			// step must be done after constructing tracing state, because the
   402  //			// tracing state of block next depends on the parent state and construction
   403  //			// may fail if we release too early.
   404  //			tracker.callReleases()
   405  //
   406  //			// Send the block over to the concurrent tracers (if not in the fast-forward phase)
   407  //			txs := next.Transactions()
   408  //			select {
   409  //			case taskCh <- &blockTraceTask{statedb: statedb.copy(), block: next, release: release, results: make([]*txTraceResult, len(txs))}:
   410  //			case <-closed:
   411  //				tracker.releaseState(number, release)
   412  //				return
   413  //			}
   414  //			traced += uint64(len(txs))
   415  //		}
   416  //	}()
   417  //
   418  //	// Keep reading the trace results and stream them to result channel.
   419  //	retCh := make(chan *blockTraceResult)
   420  //	go func() {
   421  //		defer close(retCh)
   422  //		var (
   423  //			next = start.Number64().Uint64() + 1
   424  //			done = make(map[uint64]*blockTraceResult)
   425  //		)
   426  //		for res := range resCh {
   427  //			// Queue up next received result
   428  //			result := &blockTraceResult{
   429  //				Block:  hexutil.Uint64(res.block.Number64().Uint64()),
   430  //				Hash:   res.block.Hash(),
   431  //				Traces: res.results,
   432  //			}
   433  //			done[uint64(result.Block)] = result
   434  //
   435  //			// Stream completed traces to the result channel
   436  //			for result, ok := done[next]; ok; result, ok = done[next] {
   437  //				if len(result.Traces) > 0 || next == end.Number64().Uint64() {
   438  //					// It will be blocked in case the channel consumer doesn't take the
   439  //					// tracing result in time(e.g. the websocket connect is not stable)
   440  //					// which will eventually block the entire chain tracer. It's the
   441  //					// expected behavior to not waste node resources for a non-active user.
   442  //					retCh <- result
   443  //				}
   444  //				delete(done, next)
   445  //				next++
   446  //			}
   447  //		}
   448  //	}()
   449  //	return retCh
   450  //}
   451  
   452  // TraceBlockByNumber returns the structured logs created during the execution of
   453  // EVM and returns them as a JSON object.
   454  func (api *API) TraceBlockByNumber(ctx context.Context, number rpc.BlockNumber, config *TraceConfig) ([]*txTraceResult, error) {
   455  	block, err := api.blockByNumber(ctx, number)
   456  	if err != nil {
   457  		return nil, err
   458  	}
   459  	return api.traceBlock(ctx, block, config)
   460  }
   461  
   462  // TraceBlockByHash returns the structured logs created during the execution of
   463  // EVM and returns them as a JSON object.
   464  func (api *API) TraceBlockByHash(ctx context.Context, hash common.Hash, config *TraceConfig) ([]*txTraceResult, error) {
   465  	block, err := api.blockByHash(ctx, hash)
   466  	if err != nil {
   467  		return nil, err
   468  	}
   469  	return api.traceBlock(ctx, block, config)
   470  }
   471  
   472  // TraceBlock returns the structured logs created during the execution of EVM
   473  // and returns them as a JSON object.
   474  func (api *API) TraceBlock(ctx context.Context, blob hexutil.Bytes, config *TraceConfig) ([]*txTraceResult, error) {
   475  	block := new(types.Block)
   476  	if err := rlp.Decode(bytes.NewReader(blob), block); err != nil {
   477  		return nil, fmt.Errorf("could not decode block: %v", err)
   478  	}
   479  	return api.traceBlock(ctx, block, config)
   480  }
   481  
   482  // TraceBlockFromFile returns the structured logs created during the execution of
   483  // EVM and returns them as a JSON object.
   484  //func (api *API) TraceBlockFromFile(ctx context.Context, file string, config *TraceConfig) ([]*txTraceResult, error) {
   485  //	blob, err := os.ReadFile(file)
   486  //	if err != nil {
   487  //		return nil, fmt.Errorf("could not read file: %v", err)
   488  //	}
   489  //	return api.TraceBlock(ctx, blob, config)
   490  //}
   491  
   492  // TraceBadBlock returns the structured logs created during the execution of
   493  // EVM against a block pulled from the pool of bad ones and returns them as a JSON
   494  // object.
   495  //func (api *API) TraceBadBlock(ctx context.Context, hash common.Hash, config *TraceConfig) ([]*txTraceResult, error) {
   496  //	block := rawdb.ReadBadBlock(api.backend.ChainDb(), hash)
   497  //	if block == nil {
   498  //		return nil, fmt.Errorf("bad block %#x not found", hash)
   499  //	}
   500  //	return api.traceBlock(ctx, block, config)
   501  //}
   502  
   503  // StandardTraceBlockToFile dumps the structured logs created during the
   504  // execution of EVM to the local file system and returns a list of files
   505  // to the caller.
   506  //func (api *API) StandardTraceBlockToFile(ctx context.Context, hash common.Hash, config *StdTraceConfig) ([]string, error) {
   507  //	block, err := api.blockByHash(ctx, hash)
   508  //	if err != nil {
   509  //		return nil, err
   510  //	}
   511  //	return api.standardTraceBlockToFile(ctx, block, config)
   512  //}
   513  
   514  // IntermediateRoots executes a block (bad- or canon- or side-), and returns a list
   515  // of intermediate roots: the stateroot after each transaction.
   516  //func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config *TraceConfig) ([]common.Hash, error) {
   517  //	block, _ := api.blockByHash(ctx, hash)
   518  //	if block == nil {
   519  //		// Check in the bad blocks
   520  //		block = rawdb.ReadBadBlock(api.backend.ChainDb(), hash)
   521  //	}
   522  //	if block == nil {
   523  //		return nil, fmt.Errorf("block %#x not found", hash)
   524  //	}
   525  //	if block.NumberU64() == 0 {
   526  //		return nil, errors.New("genesis is not traceable")
   527  //	}
   528  //	parent, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(block.NumberU64()-1), block.ParentHash())
   529  //	if err != nil {
   530  //		return nil, err
   531  //	}
   532  //	reexec := defaultTraceReexec
   533  //	if config != nil && config.Reexec != nil {
   534  //		reexec = *config.Reexec
   535  //	}
   536  //	statedb, release, err := api.backend.StateAtBlock(ctx, parent, reexec, nil, true, false)
   537  //	if err != nil {
   538  //		return nil, err
   539  //	}
   540  //	defer release()
   541  //
   542  //	var (
   543  //		roots              []common.Hash
   544  //		signer             = types.MakeSigner(api.backend.ChainConfig(), block.Number())
   545  //		chainConfig        = api.backend.ChainConfig()
   546  //		vmctx              = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
   547  //		deleteEmptyObjects = chainConfig.IsEIP158(block.Number())
   548  //	)
   549  //	for i, tx := range block.Transactions() {
   550  //		if err := ctx.Err(); err != nil {
   551  //			return nil, err
   552  //		}
   553  //		var (
   554  //			msg, _    = core.TransactionToMessage(tx, signer, block.BaseFee())
   555  //			txContext = core.NewEVMTxContext(msg)
   556  //			vmenv     = vm.NewEVM(vmctx, txContext, statedb, chainConfig, vm.Config{})
   557  //		)
   558  //		statedb.SetTxContext(tx.Hash(), i)
   559  //		if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit)); err != nil {
   560  //			log.Warn("Tracing intermediate roots did not complete", "txindex", i, "txhash", tx.Hash(), "err", err)
   561  //			// We intentionally don't return the error here: if we do, then the RPC server will not
   562  //			// return the roots. Most likely, the caller already knows that a certain transaction fails to
   563  //			// be included, but still want the intermediate roots that led to that point.
   564  //			// It may happen the tx_N causes an erroneous state, which in turn causes tx_N+M to not be
   565  //			// executable.
   566  //			// N.B: This should never happen while tracing canon blocks, only when tracing bad blocks.
   567  //			return roots, nil
   568  //		}
   569  //		// calling IntermediateRoot will internally call Finalize on the state
   570  //		// so any modifications are written to the trie
   571  //		roots = append(roots, statedb.IntermediateRoot(deleteEmptyObjects))
   572  //	}
   573  //	return roots, nil
   574  //}
   575  
   576  // StandardTraceBadBlockToFile dumps the structured logs created during the
   577  // execution of EVM against a block pulled from the pool of bad ones to the
   578  // local file system and returns a list of files to the caller.
   579  //func (api *API) StandardTraceBadBlockToFile(ctx context.Context, hash common.Hash, config *StdTraceConfig) ([]string, error) {
   580  //	block := rawdb.ReadBadBlock(api.backend.ChainDb(), hash)
   581  //	if block == nil {
   582  //		return nil, fmt.Errorf("bad block %#x not found", hash)
   583  //	}
   584  //	return api.standardTraceBlockToFile(ctx, block, config)
   585  //}
   586  
   587  // traceBlock configures a new tracer according to the provided configuration, and
   588  // executes all the transactions contained within. The return value will be one item
   589  // per transaction, dependent on the requested tracer.
   590  func (api *API) traceBlock(ctx context.Context, block *types.Block, config *TraceConfig) ([]*txTraceResult, error) {
   591  	if block.Number64().Uint64() == 0 {
   592  		return nil, errors.New("genesis is not traceable")
   593  	}
   594  	// Prepare base state
   595  	parent, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(block.Number64().Uint64()-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  
   604  	rtx, err := api.backend.ChainDb().BeginRo(ctx)
   605  	if nil != err {
   606  		return nil, err
   607  	}
   608  	defer rtx.Rollback()
   609  
   610  	statedb, err := api.backend.StateAtBlock(ctx, rtx, parent /*, reexec, nil, true, false*/)
   611  	if err != nil {
   612  		return nil, err
   613  	}
   614  	// defer release()
   615  
   616  	// JS tracers have high overhead. In this case run a parallel
   617  	// process that generates states in one thread and traces txes
   618  	// in separate worker threads.
   619  	//if config != nil && config.Tracer != nil && *config.Tracer != "" {
   620  	//	if isJS := DefaultDirectory.IsJS(*config.Tracer); isJS {
   621  	//		return api.traceBlockParallel(ctx, block, statedb, config)
   622  	//	}
   623  	//}
   624  
   625  	// Native tracers have low overhead
   626  	var (
   627  		txs       = block.Transactions()
   628  		blockHash = block.Hash()
   629  		//is158     = api.backend.ChainConfig().IsSpuriousDragon(block.Number64().Uint64())
   630  		blockCtx = core.NewEVMBlockContext(block.Header().(*types.Header), core.GetHashFn(block.Header().(*types.Header), api.chainContext(ctx).GetHeader), api.chainContext(ctx).Engine(), nil)
   631  		signer   = transaction.MakeSigner(api.backend.ChainConfig(), block.Number64().ToBig())
   632  		results  = make([]*txTraceResult, len(txs))
   633  	)
   634  	for i, tx := range txs {
   635  		// Generate the next state snapshot fast without tracing
   636  		msg, _ := tx.AsMessage(signer, block.BaseFee64())
   637  		txctx := &Context{
   638  			BlockHash:   blockHash,
   639  			BlockNumber: block.Number64().ToBig(),
   640  			TxIndex:     i,
   641  			TxHash:      tx.Hash(),
   642  		}
   643  		res, err := api.traceTx(ctx, &msg, txctx, blockCtx, statedb, config)
   644  		if err != nil {
   645  			return nil, err
   646  		}
   647  		results[i] = &txTraceResult{Result: res}
   648  		// Finalize the state so any modifications are written to the trie
   649  		// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
   650  		//statedb.SoftFinalise(is158)
   651  		statedb.FinalizeTx(api.backend.ChainConfig().Rules(block.Number64().Uint64()), state.NewNoopWriter())
   652  	}
   653  	return results, nil
   654  }
   655  
   656  // chainContext constructs the context reader which is used by the evm for reading
   657  // the necessary chain context.
   658  func (api *API) chainContext(ctx context.Context) core.ChainContext {
   659  	return &chainContext{api: api, ctx: ctx}
   660  }
   661  
   662  // traceBlockParallel is for tracers that have a high overhead (read JS tracers). One thread
   663  // runs along and executes txes without tracing enabled to generate their prestate.
   664  // Worker threads take the tasks and the prestate and trace them.
   665  //func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, statedb *state.IntraBlockState, config *TraceConfig) ([]*txTraceResult, error) {
   666  //	// Execute all the transaction contained within the block concurrently
   667  //	var (
   668  //		txs       = block.Transactions()
   669  //		blockHash = block.Hash()
   670  //		blockCtx  = core.NewEVMBlockContext(block.Header().(*types.Header), core.GetHashFn(block.Header().(*types.Header), api.chainContext(ctx).GetHeader), api.chainContext(ctx).Engine(), nil)
   671  //		signer    = transaction.MakeSigner(api.backend.ChainConfig(), block.Number64().ToBig())
   672  //		results   = make([]*txTraceResult, len(txs))
   673  //		pend      sync.WaitGroup
   674  //	)
   675  //	threads := runtime.NumCPU()
   676  //	if threads > len(txs) {
   677  //		threads = len(txs)
   678  //	}
   679  //	jobs := make(chan *txTraceTask, threads)
   680  //	for th := 0; th < threads; th++ {
   681  //		pend.Add(1)
   682  //		go func() {
   683  //			defer pend.Done()
   684  //			// Fetch and execute the next transaction trace tasks
   685  //			for task := range jobs {
   686  //				msg, _ := txs[task.index].AsMessage(signer, block.BaseFee64())
   687  //				txctx := &Context{
   688  //					BlockHash:   blockHash,
   689  //					BlockNumber: block.Number64().ToBig(),
   690  //					TxIndex:     task.index,
   691  //					TxHash:      txs[task.index].Hash(),
   692  //				}
   693  //				res, err := api.traceTx(ctx, &msg, txctx, blockCtx, task.statedb, config)
   694  //				if err != nil {
   695  //					results[task.index] = &txTraceResult{Error: err.Error()}
   696  //					continue
   697  //				}
   698  //				results[task.index] = &txTraceResult{Result: res}
   699  //			}
   700  //		}()
   701  //	}
   702  //
   703  //	// Feed the transactions into the tracers and return
   704  //	var failed error
   705  //txloop:
   706  //	for i, tx := range txs {
   707  //		// Send the trace task over for execution
   708  //		task := &txTraceTask{statedb: statedb.Copy(), index: i}
   709  //		select {
   710  //		case <-ctx.Done():
   711  //			failed = ctx.Err()
   712  //			break txloop
   713  //		case jobs <- task:
   714  //		}
   715  //
   716  //		// Generate the next state snapshot fast without tracing
   717  //		msg, _ := tx.AsMessage(signer, block.BaseFee64())
   718  //		statedb.Prepare(tx.Hash(), blockHash, i)
   719  //		vmenv := vm.NewEVM(blockCtx, core.NewEVMTxContext(msg), statedb, api.backend.ChainConfig(), vm.Config{})
   720  //		if _, err := core.ApplyMessage(vmenv, msg, new(common2.GasPool).AddGas(msg.Gas())); err != nil {
   721  //			failed = err
   722  //			break txloop
   723  //		}
   724  //		// Finalize the state so any modifications are written to the trie
   725  //		// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
   726  //		statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number()))
   727  //	}
   728  //
   729  //	close(jobs)
   730  //	pend.Wait()
   731  //
   732  //	// If execution failed in between, abort
   733  //	if failed != nil {
   734  //		return nil, failed
   735  //	}
   736  //	return results, nil
   737  //}
   738  
   739  // standardTraceBlockToFile configures a new tracer which uses standard JSON output,
   740  // and traces either a full block or an individual transaction. The return value will
   741  // be one filename per transaction traced.
   742  //func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block, config *StdTraceConfig) ([]string, error) {
   743  //	// If we're tracing a single transaction, make sure it's present
   744  //	if config != nil && config.TxHash != (common.Hash{}) {
   745  //		if !containsTx(block, config.TxHash) {
   746  //			return nil, fmt.Errorf("transaction %#x not found in block", config.TxHash)
   747  //		}
   748  //	}
   749  //	if block.NumberU64() == 0 {
   750  //		return nil, errors.New("genesis is not traceable")
   751  //	}
   752  //	parent, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(block.NumberU64()-1), block.ParentHash())
   753  //	if err != nil {
   754  //		return nil, err
   755  //	}
   756  //	reexec := defaultTraceReexec
   757  //	if config != nil && config.Reexec != nil {
   758  //		reexec = *config.Reexec
   759  //	}
   760  //	statedb, release, err := api.backend.StateAtBlock(ctx, parent, reexec, nil, true, false)
   761  //	if err != nil {
   762  //		return nil, err
   763  //	}
   764  //	defer release()
   765  //
   766  //	// Retrieve the tracing configurations, or use default values
   767  //	var (
   768  //		logConfig logger.Config
   769  //		txHash    common.Hash
   770  //	)
   771  //	if config != nil {
   772  //		logConfig = config.Config
   773  //		txHash = config.TxHash
   774  //	}
   775  //	logConfig.Debug = true
   776  //
   777  //	// Execute transaction, either tracing all or just the requested one
   778  //	var (
   779  //		dumps       []string
   780  //		signer      = transaction.MakeSigner(api.backend.ChainConfig(), block.Number64().ToBig())
   781  //		chainConfig = api.backend.ChainConfig()
   782  //		vmctx       = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
   783  //		canon       = true
   784  //	)
   785  //	// Check if there are any overrides: the caller may wish to enable a future
   786  //	// fork when executing this block. Note, such overrides are only applicable to the
   787  //	// actual specified block, not any preceding blocks that we have to go through
   788  //	// in order to obtain the state.
   789  //	// Therefore, it's perfectly valid to specify `"futureForkBlock": 0`, to enable `futureFork`
   790  //	if config != nil && config.Overrides != nil {
   791  //		// Note: This copies the config, to not screw up the main config
   792  //		chainConfig, canon = overrideConfig(chainConfig, config.Overrides)
   793  //	}
   794  //	for i, tx := range block.Transactions() {
   795  //		// Prepare the transaction for un-traced execution
   796  //		var (
   797  //			msg, _    = core.TransactionToMessage(tx, signer, block.BaseFee())
   798  //			txContext = core.NewEVMTxContext(msg)
   799  //			vmConf    vm.Config
   800  //			dump      *os.File
   801  //			writer    *bufio.Writer
   802  //			err       error
   803  //		)
   804  //		// If the transaction needs tracing, swap out the configs
   805  //		if tx.Hash() == txHash || txHash == (common.Hash{}) {
   806  //			// Generate a unique temporary file to dump it into
   807  //			prefix := fmt.Sprintf("block_%#x-%d-%#x-", block.Hash().Bytes()[:4], i, tx.Hash().Bytes()[:4])
   808  //			if !canon {
   809  //				prefix = fmt.Sprintf("%valt-", prefix)
   810  //			}
   811  //			dump, err = os.CreateTemp(os.TempDir(), prefix)
   812  //			if err != nil {
   813  //				return nil, err
   814  //			}
   815  //			dumps = append(dumps, dump.Name())
   816  //
   817  //			// Swap out the noop logger to the standard tracer
   818  //			writer = bufio.NewWriter(dump)
   819  //			vmConf = vm.Config{
   820  //				Debug:                   true,
   821  //				Tracer:                  logger.NewJSONLogger(&logConfig, writer),
   822  //				EnablePreimageRecording: true,
   823  //			}
   824  //		}
   825  //		// Execute the transaction and flush any traces to disk
   826  //		vmenv := vm.NewEVM(vmctx, txContext, statedb, chainConfig, vmConf)
   827  //		statedb.SetTxContext(tx.Hash(), i)
   828  //		_, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit))
   829  //		if writer != nil {
   830  //			writer.Flush()
   831  //		}
   832  //		if dump != nil {
   833  //			dump.Close()
   834  //			log.Info("Wrote standard trace", "file", dump.Name())
   835  //		}
   836  //		if err != nil {
   837  //			return dumps, err
   838  //		}
   839  //		// Finalize the state so any modifications are written to the trie
   840  //		// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
   841  //		statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number()))
   842  //
   843  //		// If we've traced the transaction we were looking for, abort
   844  //		if tx.Hash() == txHash {
   845  //			break
   846  //		}
   847  //	}
   848  //	return dumps, nil
   849  //}
   850  
   851  // containsTx reports whether the transaction with a certain hash
   852  // is contained within the specified block.
   853  func containsTx(block *types.Block, hash common.Hash) bool {
   854  	for _, tx := range block.Transactions() {
   855  		if tx.Hash() == hash {
   856  			return true
   857  		}
   858  	}
   859  	return false
   860  }
   861  
   862  // TraceTransaction returns the structured logs created during the execution of EVM
   863  // and returns them as a JSON object.
   864  func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config *TraceConfig) (interface{}, error) {
   865  	tx, blockHash, blockNumber, index, err := api.backend.GetTransaction(ctx, hash)
   866  	if err != nil {
   867  		return nil, err
   868  	}
   869  	// Only mined txes are supported
   870  	if tx == nil {
   871  		return nil, errTxNotFound
   872  	}
   873  	// It shouldn't happen in practice.
   874  	if blockNumber == 0 {
   875  		return nil, errors.New("genesis is not traceable")
   876  	}
   877  	//reexec := defaultTraceReexec
   878  	//if config != nil && config.Reexec != nil {
   879  	//	reexec = *config.Reexec
   880  	//}
   881  	block, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(blockNumber), blockHash)
   882  	if err != nil {
   883  		return nil, err
   884  	}
   885  
   886  	dbTx, err := api.backend.ChainDb().BeginRo(ctx)
   887  	if nil != err {
   888  		return nil, err
   889  	}
   890  	defer dbTx.Rollback()
   891  
   892  	msg, vmctx, statedb, err := api.backend.StateAtTransaction(ctx, dbTx, block, int(index))
   893  	if err != nil {
   894  		return nil, err
   895  	}
   896  	//defer release()
   897  
   898  	txctx := &Context{
   899  		BlockHash:   blockHash,
   900  		BlockNumber: block.Number64().ToBig(),
   901  		TxIndex:     int(index),
   902  		TxHash:      hash,
   903  	}
   904  	return api.traceTx(ctx, msg, txctx, vmctx, statedb, config)
   905  }
   906  
   907  // TraceCall lets you trace a given eth_call. It collects the structured logs
   908  // created during the execution of EVM if the given transaction was added on
   909  // top of the provided block and returns them as a JSON object.
   910  func (api *API) TraceCall(ctx context.Context, args api.TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, config *TraceCallConfig) (interface{}, error) {
   911  	// Try to retrieve the specified block
   912  	var (
   913  		err   error
   914  		block *types.Block
   915  	)
   916  	if hash, ok := blockNrOrHash.Hash(); ok {
   917  		block, err = api.blockByHash(ctx, hash)
   918  	} else if number, ok := blockNrOrHash.Number(); ok {
   919  		if number == rpc.PendingBlockNumber {
   920  			// We don't have access to the miner here. For tracing 'future' transactions,
   921  			// it can be done with block- and state-overrides instead, which offers
   922  			// more flexibility and stability than trying to trace on 'pending', since
   923  			// the contents of 'pending' is unstable and probably not a true representation
   924  			// of what the next actual block is likely to contain.
   925  			return nil, errors.New("tracing on top of pending is not supported")
   926  		}
   927  		block, err = api.blockByNumber(ctx, number)
   928  	} else {
   929  		return nil, errors.New("invalid arguments; neither block nor hash specified")
   930  	}
   931  	if err != nil {
   932  		return nil, err
   933  	}
   934  	// try to recompute the state
   935  	//reexec := defaultTraceReexec
   936  	//if config != nil && config.Reexec != nil {
   937  	//	reexec = *config.Reexec
   938  	//}
   939  
   940  	rtx, err := api.backend.ChainDb().BeginRo(ctx)
   941  	if nil != err {
   942  		return nil, err
   943  	}
   944  	defer rtx.Rollback()
   945  
   946  	statedb, err := api.backend.StateAtBlock(ctx, rtx, block /*, reexec, nil, true, false*/)
   947  	if err != nil {
   948  		return nil, err
   949  	}
   950  
   951  	vmctx := core.NewEVMBlockContext(block.Header().(*types.Header), core.GetHashFn(block.Header().(*types.Header), api.chainContext(ctx).GetHeader), api.backend.Engine(), nil)
   952  	// Apply the customization rules if required.
   953  	if config != nil {
   954  		if err := config.StateOverrides.Apply(statedb); err != nil {
   955  			return nil, err
   956  		}
   957  		config.BlockOverrides.Apply(&vmctx)
   958  	}
   959  	// Execute the trace
   960  	msg, err := args.ToMessage(api.backend.RPCGasCap(), block.BaseFee64().ToBig())
   961  	if err != nil {
   962  		return nil, err
   963  	}
   964  
   965  	var traceConfig *TraceConfig
   966  	if config != nil {
   967  		traceConfig = &config.TraceConfig
   968  	}
   969  	return api.traceTx(ctx, &msg, new(Context), vmctx, statedb, traceConfig)
   970  }
   971  
   972  // traceTx configures a new tracer according to the provided configuration, and
   973  // executes the given message in the provided environment. The return value will
   974  // be tracer dependent.
   975  func (api *API) traceTx(ctx context.Context, message *transaction.Message, txctx *Context, vmctx evmtypes.BlockContext, statedb *state.IntraBlockState, config *TraceConfig) (interface{}, error) {
   976  	var (
   977  		tracer    Tracer
   978  		err       error
   979  		timeout   = defaultTraceTimeout
   980  		txContext = core.NewEVMTxContext(message)
   981  	)
   982  	if config == nil {
   983  		config = &TraceConfig{}
   984  	}
   985  	// Default tracer is the struct logger
   986  	tracer = logger.NewStructLogger(config.Config)
   987  	if config.Tracer != nil {
   988  		tracer, err = DefaultDirectory.New(*config.Tracer, txctx, config.TracerConfig)
   989  		if err != nil {
   990  			return nil, err
   991  		}
   992  	}
   993  	//Debug: true, Tracer: logger.NewMarkdownLogger(nil, os.Stdout)
   994  	vmenv := vm.NewEVM(vmctx, txContext, statedb, api.backend.ChainConfig(), vm.Config{Debug: true, Tracer: tracer, NoBaseFee: true})
   995  
   996  	// Define a meaningful timeout of a single transaction trace
   997  	if config.Timeout != nil {
   998  		if timeout, err = time.ParseDuration(*config.Timeout); err != nil {
   999  			return nil, err
  1000  		}
  1001  	}
  1002  	deadlineCtx, cancel := context.WithTimeout(ctx, timeout)
  1003  	go func() {
  1004  		<-deadlineCtx.Done()
  1005  		if errors.Is(deadlineCtx.Err(), context.DeadlineExceeded) {
  1006  			tracer.Stop(errors.New("execution timeout"))
  1007  			// Stop evm execution. Note cancellation is not necessarily immediate.
  1008  			vmenv.Cancel()
  1009  		}
  1010  	}()
  1011  	defer cancel()
  1012  
  1013  	// Call Prepare to clear out the statedb access list
  1014  	statedb.Prepare(txctx.TxHash, txctx.BlockHash, txctx.TxIndex)
  1015  	if _, err = core.ApplyMessage(vmenv, message, new(common2.GasPool).AddGas(message.Gas()), true, false); err != nil {
  1016  		return nil, fmt.Errorf("tracing failed: %w", err)
  1017  	}
  1018  	return tracer.GetResult()
  1019  }
  1020  
  1021  // APIs return the collection of RPC services the tracer package offers.
  1022  func APIs(backend Backend) []rpc.API {
  1023  	// Append all the local APIs and return
  1024  	return []rpc.API{
  1025  		{
  1026  			Namespace: "debug",
  1027  			Service:   NewAPI(backend),
  1028  		},
  1029  	}
  1030  }
  1031  
  1032  // overrideConfig returns a copy of original with forks enabled by override enabled,
  1033  // along with a boolean that indicates whether the copy is canonical (equivalent to the original).
  1034  // Note: the Clique-part is _not_ deep copied
  1035  func overrideConfig(original *params.ChainConfig, override *params.ChainConfig) (*params.ChainConfig, bool) {
  1036  	copy := new(params.ChainConfig)
  1037  	*copy = *original
  1038  	canon := true
  1039  
  1040  	// Apply forks (after Berlin) to the copy.
  1041  	if block := override.BerlinBlock; block != nil {
  1042  		copy.BerlinBlock = block
  1043  		canon = false
  1044  	}
  1045  	if block := override.LondonBlock; block != nil {
  1046  		copy.LondonBlock = block
  1047  		canon = false
  1048  	}
  1049  	if block := override.ArrowGlacierBlock; block != nil {
  1050  		copy.ArrowGlacierBlock = block
  1051  		canon = false
  1052  	}
  1053  	if block := override.GrayGlacierBlock; block != nil {
  1054  		copy.GrayGlacierBlock = block
  1055  		canon = false
  1056  	}
  1057  	if block := override.MergeNetsplitBlock; block != nil {
  1058  		copy.MergeNetsplitBlock = block
  1059  		canon = false
  1060  	}
  1061  	if timestamp := override.ShanghaiBlock; timestamp != nil {
  1062  		copy.ShanghaiBlock = timestamp
  1063  		canon = false
  1064  	}
  1065  	if timestamp := override.CancunBlock; timestamp != nil {
  1066  		copy.CancunBlock = timestamp
  1067  		canon = false
  1068  	}
  1069  	if timestamp := override.PragueTime; timestamp != nil {
  1070  		copy.PragueTime = timestamp
  1071  		canon = false
  1072  	}
  1073  
  1074  	return copy, canon
  1075  }