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