github.com/unicornultrafoundation/go-u2u@v1.0.0-rc1.0.20240205080301-e74a83d3fadc/ethapi/tx_tracer.go (about)

     1  // Copyright 2015 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 ethapi
    18  
    19  import (
    20  	"context"
    21  	"encoding/json"
    22  	"errors"
    23  	"fmt"
    24  	"runtime"
    25  	"sync"
    26  	"time"
    27  
    28  	"github.com/unicornultrafoundation/go-u2u/common"
    29  	"github.com/unicornultrafoundation/go-u2u/common/hexutil"
    30  	"github.com/unicornultrafoundation/go-u2u/core/state"
    31  	"github.com/unicornultrafoundation/go-u2u/core/types"
    32  	"github.com/unicornultrafoundation/go-u2u/core/vm"
    33  	"github.com/unicornultrafoundation/go-u2u/evmcore"
    34  	"github.com/unicornultrafoundation/go-u2u/evmcore/txtracer"
    35  	"github.com/unicornultrafoundation/go-u2u/log"
    36  	"github.com/unicornultrafoundation/go-u2u/params"
    37  	"github.com/unicornultrafoundation/go-u2u/rpc"
    38  	"github.com/unicornultrafoundation/go-u2u/u2u"
    39  	"github.com/unicornultrafoundation/go-u2u/u2u/contracts/sfc"
    40  	"github.com/unicornultrafoundation/go-u2u/utils/signers/gsignercache"
    41  )
    42  
    43  // PublicTxTraceAPI provides an API to access transaction tracing.
    44  // It offers only methods that operate on public data that is freely available to anyone.
    45  type PublicTxTraceAPI struct {
    46  	b Backend
    47  }
    48  
    49  // NewPublicTxTraceAPI creates a new transaction trace API.
    50  func NewPublicTxTraceAPI(b Backend) *PublicTxTraceAPI {
    51  	return &PublicTxTraceAPI{b}
    52  }
    53  
    54  // Trace transaction and return processed result
    55  func (s *PublicTxTraceAPI) traceTx(
    56  	ctx context.Context, blockCtx vm.BlockContext, msg types.Message,
    57  	state *state.StateDB, block *evmcore.EvmBlock, tx *types.Transaction, index uint64,
    58  	status uint64, chainConfig *params.ChainConfig) (*[]txtracer.ActionTrace, error) {
    59  
    60  	// Providing default config
    61  	// In case of trace transaction node, this config is changed
    62  	cfg := u2u.DefaultVMConfig
    63  	cfg.Debug = true
    64  	txTracer := txtracer.NewTraceStructLogger(nil)
    65  	cfg.Tracer = txTracer
    66  	cfg.NoBaseFee = true
    67  
    68  	// Setup context so it may be cancelled the call has completed
    69  	// or, in case of unmetered gas, setup a context with a timeout.
    70  	var timeout time.Duration = 5 * time.Second
    71  	if s.b.RPCTimeout() > 0 {
    72  		timeout = s.b.RPCTimeout()
    73  	}
    74  	var cancel context.CancelFunc
    75  	ctx, cancel = context.WithTimeout(ctx, timeout)
    76  
    77  	// Make sure the context is cancelled when the call has completed
    78  	// this makes sure resources are cleaned up.
    79  	defer cancel()
    80  	txTracer.SetTx(tx.Hash())
    81  	txTracer.SetFrom(msg.From())
    82  	txTracer.SetTo(msg.To())
    83  	txTracer.SetValue(*msg.Value())
    84  	txTracer.SetBlockHash(block.Hash)
    85  	txTracer.SetBlockNumber(block.Number)
    86  	txTracer.SetTxIndex(uint(index))
    87  	txTracer.SetGasUsed(tx.Gas())
    88  
    89  	var txContext = evmcore.NewEVMTxContext(msg)
    90  	vmenv := vm.NewEVM(blockCtx, txContext, state, chainConfig, cfg)
    91  
    92  	// Wait for the context to be done and cancel the evm. Even if the
    93  	// EVM has finished, cancelling may be done (repeatedly)
    94  	go func() {
    95  		<-ctx.Done()
    96  		vmenv.Cancel()
    97  	}()
    98  
    99  	// Setup the gas pool and stateDB
   100  	gp := new(evmcore.GasPool).AddGas(msg.Gas())
   101  	state.Prepare(tx.Hash(), int(index))
   102  	result, err := evmcore.ApplyMessage(vmenv, msg, gp)
   103  
   104  	if result != nil {
   105  		txTracer.SetGasUsed(result.UsedGas)
   106  	}
   107  	// Process traces if any
   108  	txTracer.ProcessTx()
   109  	traceActions := txTracer.GetTraceActions()
   110  	state.Finalise(true)
   111  	if err != nil {
   112  		errTrace := txtracer.GetErrorTraceFromMsg(&msg, block.Hash, *block.Number, tx.Hash(), index, err)
   113  		at := make([]txtracer.ActionTrace, 0)
   114  		at = append(at, *errTrace)
   115  		if status == 1 {
   116  			return nil, fmt.Errorf("invalid transaction replay state at %s", tx.Hash().String())
   117  		}
   118  		return &at, nil
   119  	}
   120  	// If the timer caused an abort, return an appropriate error message
   121  	if vmenv.Cancelled() {
   122  		log.Info("EVM was canceled due to timeout when replaying transaction ", "txHash", tx.Hash().String())
   123  		return nil, fmt.Errorf("timeout when replaying tx")
   124  	}
   125  
   126  	if result != nil && result.Err != nil {
   127  		if len(*traceActions) == 0 {
   128  			log.Error("error in result when replaying transaction:", "txHash", tx.Hash().String(), " err", result.Err.Error())
   129  			errTrace := txtracer.GetErrorTraceFromMsg(&msg, block.Hash, *block.Number, tx.Hash(), index, result.Err)
   130  			at := make([]txtracer.ActionTrace, 0)
   131  			at = append(at, *errTrace)
   132  			return &at, nil
   133  		}
   134  		if status == 1 {
   135  			return nil, fmt.Errorf("invalid transaction replay state at %s", tx.Hash().String())
   136  		}
   137  		return traceActions, nil
   138  	}
   139  
   140  	if status == 0 {
   141  		return nil, fmt.Errorf("invalid transaction replay state at %s", tx.Hash().String())
   142  	}
   143  	return traceActions, nil
   144  }
   145  
   146  // Gets all transaction from specified block and process them
   147  func (s *PublicTxTraceAPI) traceBlock(ctx context.Context, block *evmcore.EvmBlock, txHash *common.Hash, traceIndex *[]hexutil.Uint) (*[]txtracer.ActionTrace, error) {
   148  	var (
   149  		blockNumber   int64
   150  		parentBlockNr rpc.BlockNumber
   151  	)
   152  
   153  	if block != nil && block.NumberU64() > 0 {
   154  		blockNumber = block.Number.Int64()
   155  		parentBlockNr = rpc.BlockNumber(blockNumber - 1)
   156  	} else {
   157  		return nil, fmt.Errorf("invalid block for tracing")
   158  	}
   159  
   160  	// Check if node is synced
   161  	if s.b.CurrentBlock().Number.Int64() < blockNumber {
   162  		return nil, fmt.Errorf("invalid block %v for tracing, current block is %v", blockNumber, s.b.CurrentBlock())
   163  	}
   164  
   165  	callTrace := txtracer.CallTrace{
   166  		Actions: make([]txtracer.ActionTrace, 0),
   167  	}
   168  
   169  	signer := gsignercache.Wrap(types.MakeSigner(s.b.ChainConfig(), block.Number))
   170  	blockCtx := s.b.GetBlockContext(block.Header())
   171  
   172  	allTxOK := true
   173  	// loop thru all transactions in the block get them from DB
   174  	for _, tx := range block.Transactions {
   175  		// Get transaction trace from backend persistent store
   176  		// Otherwise replay transaction and save trace to db
   177  		traces, err := s.b.TxTraceByHash(ctx, tx.Hash())
   178  		if err == nil {
   179  			if txHash == nil || *txHash == tx.Hash() {
   180  				callTrace.AddTraces(traces, traceIndex)
   181  				if txHash != nil {
   182  					break
   183  				}
   184  			}
   185  		} else {
   186  			allTxOK = false
   187  			break
   188  		}
   189  	}
   190  
   191  	if !allTxOK {
   192  
   193  		// get state from block parent, to be able to recreate correct nonces
   194  		state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, rpc.BlockNumberOrHash{BlockNumber: &parentBlockNr})
   195  		if err != nil {
   196  			return nil, fmt.Errorf("cannot get state for block %v, error: %v", block.NumberU64(), err.Error())
   197  		}
   198  		receipts, err := s.b.GetReceiptsByNumber(ctx, rpc.BlockNumber(blockNumber))
   199  		if err != nil {
   200  			log.Debug("Cannot get receipts for block", "block", blockNumber, "err", err.Error())
   201  			return nil, fmt.Errorf("cannot get receipts for block %v, error: %v", block.NumberU64(), err.Error())
   202  		}
   203  
   204  		callTrace = txtracer.CallTrace{
   205  			Actions: make([]txtracer.ActionTrace, 0),
   206  		}
   207  
   208  		// loop thru all transactions in the block and process them
   209  		for i, tx := range block.Transactions {
   210  			if txHash == nil || *txHash == tx.Hash() {
   211  
   212  				log.Info("Replaying transaction", "txHash", tx.Hash().String())
   213  				// get full transaction info
   214  				tx, _, index, err := s.b.GetTransaction(ctx, tx.Hash())
   215  				if err != nil {
   216  					log.Error("cannot replay tranasction", "txHash", tx.Hash().String(), "err", err.Error())
   217  					return nil, fmt.Errorf("cannot replay tranasction %s, error %s", tx.Hash().String(), err)
   218  				}
   219  				msg, err := evmcore.TxAsMessage(tx, signer, block.BaseFee)
   220  				if err != nil {
   221  					log.Error("cannot get message from transaction", "txHash", tx.Hash().String(), "err", err.Error())
   222  					return nil, fmt.Errorf("cannot get message from transaction %s, error %s", tx.Hash().String(), err)
   223  				}
   224  				from := msg.From()
   225  				if tx.To() != nil && *tx.To() == sfc.ContractAddress {
   226  					errTrace := txtracer.GetErrorTrace(block.Hash, *block.Number, &from, tx.To(), tx.Hash(), index, errors.New("sfc tx"))
   227  					at := make([]txtracer.ActionTrace, 0)
   228  					at = append(at, *errTrace)
   229  					callTrace.AddTrace(errTrace)
   230  					jsonTraceBytes, _ := json.Marshal(&at)
   231  					s.b.TxTraceSave(ctx, tx.Hash(), jsonTraceBytes)
   232  				} else {
   233  					txTraces, err := s.traceTx(ctx, blockCtx, msg, state, block, tx, index, receipts[i].Status, s.b.ChainConfig())
   234  					if err != nil {
   235  						log.Debug("Cannot get transaction trace for transaction", "txHash", tx.Hash().String(), "err", err.Error())
   236  						callTrace.AddTrace(txtracer.GetErrorTraceFromMsg(&msg, block.Hash, *block.Number, tx.Hash(), index, err))
   237  					} else {
   238  						callTrace.AddTraces(txTraces, traceIndex)
   239  
   240  						// Save trace result into persistent key-value store
   241  						jsonTraceBytes, _ := json.Marshal(txTraces)
   242  						s.b.TxTraceSave(ctx, tx.Hash(), jsonTraceBytes)
   243  					}
   244  				}
   245  				if txHash != nil {
   246  					break
   247  				}
   248  			} else if txHash != nil {
   249  				log.Info("Replaying transaction without trace", "txHash", tx.Hash().String())
   250  				// Generate the next state snapshot fast without tracing
   251  				msg, err := evmcore.TxAsMessage(tx, signer, block.BaseFee)
   252  				if err != nil {
   253  					return nil, fmt.Errorf("cannot replay tranasction %s, error %s", tx.Hash().String(), err)
   254  				}
   255  				state.Prepare(tx.Hash(), i)
   256  				vmConfig := u2u.DefaultVMConfig
   257  				vmConfig.NoBaseFee = true
   258  				vmConfig.Debug = false
   259  				vmConfig.Tracer = nil
   260  				vmenv := vm.NewEVM(blockCtx, evmcore.NewEVMTxContext(msg), state, s.b.ChainConfig(), vmConfig)
   261  				res, err := evmcore.ApplyMessage(vmenv, msg, new(evmcore.GasPool).AddGas(msg.Gas()))
   262  				failed := false
   263  				if err != nil {
   264  					failed = true
   265  					log.Error("Cannot replay transaction", "txHash", tx.Hash().String(), "err", err.Error())
   266  				}
   267  				if res != nil && res.Err != nil {
   268  					failed = true
   269  					log.Debug("Error replaying transaction", "txHash", tx.Hash().String(), "err", res.Err.Error())
   270  				}
   271  				// Finalize the state so any modifications are written to the trie
   272  				state.Finalise(true)
   273  				if (failed && receipts[i].Status == 1) || (!failed && receipts[i].Status == 0) {
   274  					return nil, fmt.Errorf("invalid transaction replay state at %s", tx.Hash().String())
   275  				}
   276  			}
   277  		}
   278  	}
   279  
   280  	// In case of empty result create empty trace for empty block
   281  	if len(callTrace.Actions) == 0 {
   282  		if traceIndex != nil || txHash != nil {
   283  			return nil, nil
   284  		} else {
   285  			emptyTrace := txtracer.CallTrace{
   286  				Actions: make([]txtracer.ActionTrace, 0),
   287  			}
   288  			blockTrace := txtracer.NewActionTrace(block.Hash, *block.Number, common.Hash{}, 0, "empty")
   289  			txAction := txtracer.NewAddressAction(&common.Address{}, 0, []byte{}, nil, hexutil.Big{}, nil)
   290  			blockTrace.Action = *txAction
   291  			blockTrace.Error = "Empty block"
   292  			emptyTrace.AddTrace(blockTrace)
   293  			return &emptyTrace.Actions, nil
   294  		}
   295  	}
   296  
   297  	return &callTrace.Actions, nil
   298  }
   299  
   300  /* trace_block function returns transaction traces in givven block
   301  * When blockNr is -1 the chain head is returned.
   302  * When blockNr is -2 the pending chain head is returned.
   303  * When fullTx is true all transactions in the block are returned, otherwise
   304  * only the transaction hash is returned.
   305   */
   306  func (s *PublicTxTraceAPI) Block(ctx context.Context, numberOrHash rpc.BlockNumberOrHash) (*[]txtracer.ActionTrace, error) {
   307  
   308  	blockNr, _ := numberOrHash.Number()
   309  
   310  	defer func(start time.Time) {
   311  		log.Info("Executing trace_block call finished", "blockNr", blockNr.Int64(), "runtime", time.Since(start))
   312  	}(time.Now())
   313  
   314  	block, err := s.b.BlockByNumber(ctx, blockNr)
   315  	if err != nil {
   316  		log.Debug("Cannot get block from db", "blockNr", blockNr)
   317  		return nil, err
   318  	}
   319  
   320  	return s.traceBlock(ctx, block, nil, nil)
   321  }
   322  
   323  // Transaction trace_transaction function returns transaction traces
   324  func (s *PublicTxTraceAPI) Transaction(ctx context.Context, hash common.Hash) (*[]txtracer.ActionTrace, error) {
   325  	defer func(start time.Time) {
   326  		log.Info("Executing trace_transaction call finished", "txHash", hash.String(), "runtime", time.Since(start))
   327  	}(time.Now())
   328  	return s.traceTxHash(ctx, hash, nil)
   329  }
   330  
   331  // Get trace_get function returns transaction traces on specified index position of the traces
   332  // If index is nil, then just root trace is returned
   333  func (s *PublicTxTraceAPI) Get(ctx context.Context, hash common.Hash, traceIndex []hexutil.Uint) (*[]txtracer.ActionTrace, error) {
   334  	defer func(start time.Time) {
   335  		log.Info("Executing trace_get call finished", "txHash", hash.String(), "index", traceIndex, "runtime", time.Since(start))
   336  	}(time.Now())
   337  	return s.traceTxHash(ctx, hash, &traceIndex)
   338  }
   339  
   340  // traceTxHash looks for a block of this transaction hash and trace it
   341  func (s *PublicTxTraceAPI) traceTxHash(ctx context.Context, hash common.Hash, traceIndex *[]hexutil.Uint) (*[]txtracer.ActionTrace, error) {
   342  	_, blockNumber, _, _ := s.b.GetTransaction(ctx, hash)
   343  	blkNr := rpc.BlockNumber(blockNumber)
   344  	block, err := s.b.BlockByNumber(ctx, blkNr)
   345  	if err != nil {
   346  		log.Debug("Cannot get block from db", "blockNr", blkNr)
   347  		return nil, err
   348  	}
   349  	callTrace := txtracer.CallTrace{
   350  		Actions: make([]txtracer.ActionTrace, 0),
   351  	}
   352  
   353  	// Get transaction trace from backend persistent store
   354  	// Otherwise replay transaction and save trace to db
   355  	traces, err := s.b.TxTraceByHash(ctx, hash)
   356  	if err == nil && len(*traces) > 0 {
   357  		callTrace.AddTraces(traces, traceIndex)
   358  	}
   359  	if len(callTrace.Actions) != 0 {
   360  		return &callTrace.Actions, nil
   361  	}
   362  
   363  	return s.traceBlock(ctx, block, &hash, traceIndex)
   364  }
   365  
   366  // FilterArgs represents the arguments for specifiing trace targets
   367  type FilterArgs struct {
   368  	FromAddress *[]common.Address      `json:"fromAddress"`
   369  	ToAddress   *[]common.Address      `json:"toAddress"`
   370  	FromBlock   *rpc.BlockNumberOrHash `json:"fromBlock"`
   371  	ToBlock     *rpc.BlockNumberOrHash `json:"toBlock"`
   372  	After       uint                   `json:"after"`
   373  	Count       uint                   `json:"count"`
   374  }
   375  
   376  // Filter is function for trace_filter rpc call
   377  func (s *PublicTxTraceAPI) Filter(ctx context.Context, args FilterArgs) (*[]txtracer.ActionTrace, error) {
   378  	// add log after execution
   379  	defer func(start time.Time) {
   380  
   381  		var data []interface{}
   382  		if args.FromBlock != nil {
   383  			data = append(data, "fromBlock", args.FromBlock.BlockNumber.Int64())
   384  		}
   385  		if args.ToBlock != nil {
   386  			data = append(data, "toBlock", args.ToBlock.BlockNumber.Int64())
   387  		}
   388  		if args.FromAddress != nil {
   389  			adresses := make([]string, 0)
   390  			for _, addr := range *args.FromAddress {
   391  				adresses = append(adresses, addr.String())
   392  			}
   393  			data = append(data, "fromAddr", adresses)
   394  		}
   395  		if args.ToAddress != nil {
   396  			adresses := make([]string, 0)
   397  			for _, addr := range *args.ToAddress {
   398  				adresses = append(adresses, addr.String())
   399  			}
   400  			data = append(data, "toAddr", adresses)
   401  		}
   402  		data = append(data, "time", time.Since(start))
   403  		log.Info("Executing trace_filter call finished", data...)
   404  	}(time.Now())
   405  
   406  	// process arguments
   407  	var (
   408  		fromBlock, toBlock rpc.BlockNumber
   409  		mainErr            error
   410  	)
   411  	if args.FromBlock != nil {
   412  		fromBlock = *args.FromBlock.BlockNumber
   413  	}
   414  	if args.ToBlock != nil {
   415  		toBlock = *args.ToBlock.BlockNumber
   416  		if toBlock == rpc.LatestBlockNumber || toBlock == rpc.PendingBlockNumber {
   417  			toBlock = rpc.BlockNumber(s.b.CurrentBlock().NumberU64())
   418  		}
   419  	} else {
   420  		toBlock = rpc.BlockNumber(s.b.CurrentBlock().NumberU64())
   421  	}
   422  
   423  	// counter of processed traces
   424  	var traceAdded, traceCount uint
   425  	var fromAddresses, toAddresses map[common.Address]struct{}
   426  	if args.FromAddress != nil {
   427  		fromAddresses = make(map[common.Address]struct{})
   428  		for _, addr := range *args.FromAddress {
   429  			fromAddresses[addr] = struct{}{}
   430  		}
   431  	}
   432  	if args.ToAddress != nil {
   433  		toAddresses = make(map[common.Address]struct{})
   434  		for _, addr := range *args.ToAddress {
   435  			toAddresses[addr] = struct{}{}
   436  		}
   437  	}
   438  
   439  	// check for context timeout
   440  	contextDone := false
   441  	go func() {
   442  		<-ctx.Done()
   443  		contextDone = true
   444  	}()
   445  
   446  	// struct for collecting result traces
   447  	callTrace := txtracer.CallTrace{
   448  		Actions: make([]txtracer.ActionTrace, 0),
   449  	}
   450  
   451  	// count of traces doesn't matter so use parallel workers
   452  	if args.Count == 0 {
   453  		workerCount := runtime.NumCPU() / 2
   454  		blocks := make(chan rpc.BlockNumber, 10000)
   455  		results := make(chan txtracer.ActionTrace, 100000)
   456  
   457  		// create workers and their sync group
   458  		var wg sync.WaitGroup
   459  		for w := 0; w < workerCount; w++ {
   460  			wg.Add(1)
   461  			wId := w
   462  			go func() {
   463  				defer wg.Done()
   464  				worker(wId, s, ctx, blocks, results, fromAddresses, toAddresses)
   465  			}()
   466  		}
   467  
   468  		// add all blocks in specified range for processing
   469  		for i := fromBlock; i <= toBlock; i++ {
   470  			blocks <- i
   471  		}
   472  		close(blocks)
   473  
   474  		var wgResult sync.WaitGroup
   475  		wgResult.Add(1)
   476  		go func() {
   477  			defer wgResult.Done()
   478  			// collect results
   479  			for trace := range results {
   480  				callTrace.AddTrace(&trace)
   481  			}
   482  		}()
   483  
   484  		// wait for proccessing all blocks
   485  		wg.Wait()
   486  		close(results)
   487  
   488  		wgResult.Wait()
   489  	} else {
   490  	blocks:
   491  		// go thru all blocks in specified range
   492  		for i := fromBlock; i <= toBlock; i++ {
   493  			block, err := s.b.BlockByNumber(ctx, i)
   494  			if err != nil {
   495  				mainErr = err
   496  				break
   497  			}
   498  
   499  			// when block has any transaction, then process it
   500  			if block != nil && block.Transactions.Len() > 0 {
   501  				traces, err := s.traceBlock(ctx, block, nil, nil)
   502  				if err != nil {
   503  					mainErr = err
   504  					break
   505  				}
   506  
   507  				// loop thru all traces from the block
   508  				// and check
   509  				for _, trace := range *traces {
   510  
   511  					if args.Count == 0 || traceAdded < args.Count {
   512  						addTrace := true
   513  
   514  						if args.FromAddress != nil || args.ToAddress != nil {
   515  							if args.FromAddress != nil {
   516  								if trace.Action.From == nil {
   517  									addTrace = false
   518  								} else {
   519  									if _, ok := fromAddresses[*trace.Action.From]; !ok {
   520  										addTrace = false
   521  									}
   522  								}
   523  							}
   524  							if args.ToAddress != nil {
   525  								if trace.Action.To == nil {
   526  									addTrace = false
   527  								} else if _, ok := toAddresses[*trace.Action.To]; !ok {
   528  									addTrace = false
   529  								}
   530  							}
   531  						}
   532  						if addTrace {
   533  							if traceCount >= args.After {
   534  								callTrace.AddTrace(&trace)
   535  								traceAdded++
   536  							}
   537  							traceCount++
   538  						}
   539  					} else {
   540  						// already reached desired count of traces in batch
   541  						break blocks
   542  					}
   543  				}
   544  			}
   545  			if contextDone {
   546  				break
   547  			}
   548  		}
   549  	}
   550  
   551  	//when timeout occured or another error
   552  	if contextDone || mainErr != nil {
   553  		if mainErr != nil {
   554  			return nil, mainErr
   555  		}
   556  		return nil, fmt.Errorf("timeout when scanning blocks")
   557  	}
   558  
   559  	return &callTrace.Actions, nil
   560  }
   561  
   562  func worker(id int,
   563  	s *PublicTxTraceAPI,
   564  	ctx context.Context,
   565  	blocks <-chan rpc.BlockNumber,
   566  	results chan<- txtracer.ActionTrace,
   567  	fromAddresses map[common.Address]struct{},
   568  	toAddresses map[common.Address]struct{}) {
   569  
   570  	for i := range blocks {
   571  		block, err := s.b.BlockByNumber(ctx, i)
   572  		if err != nil {
   573  			break
   574  		}
   575  
   576  		// when block has any transaction, then process it
   577  		if block != nil && block.Transactions.Len() > 0 {
   578  			traces, err := s.traceBlock(ctx, block, nil, nil)
   579  			if err != nil {
   580  				break
   581  			}
   582  			for _, trace := range *traces {
   583  				addTrace := true
   584  
   585  				if len(fromAddresses) > 0 {
   586  
   587  					if trace.Action.From == nil {
   588  						addTrace = false
   589  					} else {
   590  						if _, ok := fromAddresses[*trace.Action.From]; !ok {
   591  							addTrace = false
   592  						}
   593  					}
   594  				}
   595  				if len(toAddresses) > 0 {
   596  					if trace.Action.To == nil {
   597  						addTrace = false
   598  					} else if _, ok := toAddresses[*trace.Action.To]; !ok {
   599  						addTrace = false
   600  					}
   601  				}
   602  				if addTrace {
   603  					results <- trace
   604  				}
   605  			}
   606  		}
   607  	}
   608  }