github.com/coltonfike/e2c@v21.1.0+incompatible/eth/api_tracer.go (about)

     1  // Copyright 2017 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 eth
    18  
    19  import (
    20  	"bufio"
    21  	"bytes"
    22  	"context"
    23  	"errors"
    24  	"fmt"
    25  	"io/ioutil"
    26  	"os"
    27  	"runtime"
    28  	"sync"
    29  	"time"
    30  
    31  	"github.com/ethereum/go-ethereum/common"
    32  	"github.com/ethereum/go-ethereum/common/hexutil"
    33  	"github.com/ethereum/go-ethereum/core"
    34  	"github.com/ethereum/go-ethereum/core/rawdb"
    35  	"github.com/ethereum/go-ethereum/core/state"
    36  	"github.com/ethereum/go-ethereum/core/types"
    37  	"github.com/ethereum/go-ethereum/core/vm"
    38  	"github.com/ethereum/go-ethereum/eth/tracers"
    39  	"github.com/ethereum/go-ethereum/internal/ethapi"
    40  	"github.com/ethereum/go-ethereum/log"
    41  	"github.com/ethereum/go-ethereum/rlp"
    42  	"github.com/ethereum/go-ethereum/rpc"
    43  	"github.com/ethereum/go-ethereum/trie"
    44  )
    45  
    46  const (
    47  	// defaultTraceTimeout is the amount of time a single transaction can execute
    48  	// by default before being forcefully aborted.
    49  	defaultTraceTimeout = 5 * time.Second
    50  
    51  	// defaultTraceReexec is the number of blocks the tracer is willing to go back
    52  	// and reexecute to produce missing historical state necessary to run a specific
    53  	// trace.
    54  	defaultTraceReexec = uint64(128)
    55  )
    56  
    57  // TraceConfig holds extra parameters to trace functions.
    58  type TraceConfig struct {
    59  	*vm.LogConfig
    60  	Tracer  *string
    61  	Timeout *string
    62  	Reexec  *uint64
    63  }
    64  
    65  // StdTraceConfig holds extra parameters to standard-json trace functions.
    66  type StdTraceConfig struct {
    67  	*vm.LogConfig
    68  	Reexec *uint64
    69  	TxHash common.Hash
    70  }
    71  
    72  // txTraceResult is the result of a single transaction trace.
    73  type txTraceResult struct {
    74  	Result interface{} `json:"result,omitempty"` // Trace results produced by the tracer
    75  	Error  string      `json:"error,omitempty"`  // Trace failure produced by the tracer
    76  }
    77  
    78  // blockTraceTask represents a single block trace task when an entire chain is
    79  // being traced.
    80  type blockTraceTask struct {
    81  	statedb        *state.StateDB   // Intermediate state prepped for tracing
    82  	privateStateDb *state.StateDB   // Quorum
    83  	block          *types.Block     // Block to trace the transactions from
    84  	rootref        common.Hash      // Trie root reference held for this task
    85  	results        []*txTraceResult // Trace results procudes by the task
    86  }
    87  
    88  // blockTraceResult represets the results of tracing a single block when an entire
    89  // chain is being traced.
    90  type blockTraceResult struct {
    91  	Block  hexutil.Uint64   `json:"block"`  // Block number corresponding to this trace
    92  	Hash   common.Hash      `json:"hash"`   // Block hash corresponding to this trace
    93  	Traces []*txTraceResult `json:"traces"` // Trace results produced by the task
    94  }
    95  
    96  // txTraceTask represents a single transaction trace task when an entire block
    97  // is being traced.
    98  type txTraceTask struct {
    99  	statedb        *state.StateDB // Intermediate state prepped for tracing
   100  	privateStateDb *state.StateDB
   101  	index          int // Transaction offset in the block
   102  }
   103  
   104  // TraceChain returns the structured logs created during the execution of EVM
   105  // between two blocks (excluding start) and returns them as a JSON object.
   106  func (api *PrivateDebugAPI) TraceChain(ctx context.Context, start, end rpc.BlockNumber, config *TraceConfig) (*rpc.Subscription, error) {
   107  	// Fetch the block interval that we want to trace
   108  	var from, to *types.Block
   109  
   110  	switch start {
   111  	case rpc.PendingBlockNumber:
   112  		from = api.eth.miner.PendingBlock()
   113  	case rpc.LatestBlockNumber:
   114  		from = api.eth.blockchain.CurrentBlock()
   115  	default:
   116  		from = api.eth.blockchain.GetBlockByNumber(uint64(start))
   117  	}
   118  	switch end {
   119  	case rpc.PendingBlockNumber:
   120  		to = api.eth.miner.PendingBlock()
   121  	case rpc.LatestBlockNumber:
   122  		to = api.eth.blockchain.CurrentBlock()
   123  	default:
   124  		to = api.eth.blockchain.GetBlockByNumber(uint64(end))
   125  	}
   126  	// Trace the chain if we've found all our blocks
   127  	if from == nil {
   128  		return nil, fmt.Errorf("starting block #%d not found", start)
   129  	}
   130  	if to == nil {
   131  		return nil, fmt.Errorf("end block #%d not found", end)
   132  	}
   133  	if from.Number().Cmp(to.Number()) >= 0 {
   134  		return nil, fmt.Errorf("end block (#%d) needs to come after start block (#%d)", end, start)
   135  	}
   136  	return api.traceChain(ctx, from, to, config)
   137  }
   138  
   139  // traceChain configures a new tracer according to the provided configuration, and
   140  // executes all the transactions contained within. The return value will be one item
   141  // per transaction, dependent on the requested tracer.
   142  func (api *PrivateDebugAPI) traceChain(ctx context.Context, start, end *types.Block, config *TraceConfig) (*rpc.Subscription, error) {
   143  	// Tracing a chain is a **long** operation, only do with subscriptions
   144  	notifier, supported := rpc.NotifierFromContext(ctx)
   145  	if !supported {
   146  		return &rpc.Subscription{}, rpc.ErrNotificationsUnsupported
   147  	}
   148  	sub := notifier.CreateSubscription()
   149  
   150  	// Ensure we have a valid starting state before doing any work
   151  	origin := start.NumberU64()
   152  	database := state.NewDatabaseWithCache(api.eth.ChainDb(), 16) // Chain tracing will probably start at genesis
   153  
   154  	if number := start.NumberU64(); number > 0 {
   155  		start = api.eth.blockchain.GetBlock(start.ParentHash(), start.NumberU64()-1)
   156  		if start == nil {
   157  			return nil, fmt.Errorf("parent block #%d not found", number-1)
   158  		}
   159  	}
   160  	statedb, privateStateDb, err := api.eth.blockchain.StateAt(start.Root())
   161  	if err != nil {
   162  		// If the starting state is missing, allow some number of blocks to be reexecuted
   163  		reexec := defaultTraceReexec
   164  		if config != nil && config.Reexec != nil {
   165  			reexec = *config.Reexec
   166  		}
   167  		// Find the most recent block that has the state available
   168  		for i := uint64(0); i < reexec; i++ {
   169  			start = api.eth.blockchain.GetBlock(start.ParentHash(), start.NumberU64()-1)
   170  			if start == nil {
   171  				break
   172  			}
   173  			statedb, privateStateDb, err = api.eth.blockchain.StateAt(start.Root())
   174  			if err == nil {
   175  				break
   176  			}
   177  		}
   178  		// If we still don't have the state available, bail out
   179  		if err != nil {
   180  			switch err.(type) {
   181  			case *trie.MissingNodeError:
   182  				return nil, errors.New("required historical state unavailable")
   183  			default:
   184  				return nil, err
   185  			}
   186  		}
   187  	}
   188  	// Execute all the transaction contained within the chain concurrently for each block
   189  	blocks := int(end.NumberU64() - origin)
   190  
   191  	threads := runtime.NumCPU()
   192  	if threads > blocks {
   193  		threads = blocks
   194  	}
   195  	var (
   196  		pend    = new(sync.WaitGroup)
   197  		tasks   = make(chan *blockTraceTask, threads)
   198  		results = make(chan *blockTraceTask, threads)
   199  	)
   200  	for th := 0; th < threads; th++ {
   201  		pend.Add(1)
   202  		go func() {
   203  			defer pend.Done()
   204  
   205  			// Fetch and execute the next block trace tasks
   206  			for task := range tasks {
   207  				signer := types.MakeSigner(api.eth.blockchain.Config(), task.block.Number())
   208  
   209  				// Trace all the transactions contained within
   210  				for i, tx := range task.block.Transactions() {
   211  					msg, _ := tx.AsMessage(signer)
   212  					vmctx := core.NewEVMContext(msg, task.block.Header(), api.eth.blockchain, nil)
   213  
   214  					res, err := api.traceTx(ctx, msg, tx, vmctx, task.statedb, task.privateStateDb, config)
   215  					if err != nil {
   216  						task.results[i] = &txTraceResult{Error: err.Error()}
   217  						log.Warn("Tracing failed", "hash", tx.Hash(), "block", task.block.NumberU64(), "err", err)
   218  						break
   219  					}
   220  					// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
   221  					task.statedb.Finalise(api.eth.blockchain.Config().IsEIP158(task.block.Number()))
   222  					task.privateStateDb.Finalise(api.eth.blockchain.Config().IsEIP158(task.block.Number()))
   223  					task.results[i] = &txTraceResult{Result: res}
   224  				}
   225  				// Stream the result back to the user or abort on teardown
   226  				select {
   227  				case results <- task:
   228  				case <-notifier.Closed():
   229  					return
   230  				}
   231  			}
   232  		}()
   233  	}
   234  	// Start a goroutine to feed all the blocks into the tracers
   235  	begin := time.Now()
   236  
   237  	go func() {
   238  		var (
   239  			logged time.Time
   240  			number uint64
   241  			traced uint64
   242  			failed error
   243  			proot  common.Hash
   244  		)
   245  		// Ensure everything is properly cleaned up on any exit path
   246  		defer func() {
   247  			close(tasks)
   248  			pend.Wait()
   249  
   250  			switch {
   251  			case failed != nil:
   252  				log.Warn("Chain tracing failed", "start", start.NumberU64(), "end", end.NumberU64(), "transactions", traced, "elapsed", time.Since(begin), "err", failed)
   253  			case number < end.NumberU64():
   254  				log.Warn("Chain tracing aborted", "start", start.NumberU64(), "end", end.NumberU64(), "abort", number, "transactions", traced, "elapsed", time.Since(begin))
   255  			default:
   256  				log.Info("Chain tracing finished", "start", start.NumberU64(), "end", end.NumberU64(), "transactions", traced, "elapsed", time.Since(begin))
   257  			}
   258  			close(results)
   259  		}()
   260  		// Feed all the blocks both into the tracer, as well as fast process concurrently
   261  		for number = start.NumberU64() + 1; number <= end.NumberU64(); number++ {
   262  			// Stop tracing if interruption was requested
   263  			select {
   264  			case <-notifier.Closed():
   265  				return
   266  			default:
   267  			}
   268  			// Print progress logs if long enough time elapsed
   269  			if time.Since(logged) > 8*time.Second {
   270  				if number > origin {
   271  					nodes, imgs := database.TrieDB().Size()
   272  					log.Info("Tracing chain segment", "start", origin, "end", end.NumberU64(), "current", number, "transactions", traced, "elapsed", time.Since(begin), "memory", nodes+imgs)
   273  				} else {
   274  					log.Info("Preparing state for chain trace", "block", number, "start", origin, "elapsed", time.Since(begin))
   275  				}
   276  				logged = time.Now()
   277  			}
   278  			// Retrieve the next block to trace
   279  			block := api.eth.blockchain.GetBlockByNumber(number)
   280  			if block == nil {
   281  				failed = fmt.Errorf("block #%d not found", number)
   282  				break
   283  			}
   284  			// Send the block over to the concurrent tracers (if not in the fast-forward phase)
   285  			if number > origin {
   286  				txs := block.Transactions()
   287  
   288  				select {
   289  				case tasks <- &blockTraceTask{statedb: statedb.Copy(), privateStateDb: privateStateDb.Copy(), block: block, rootref: proot, results: make([]*txTraceResult, len(txs))}:
   290  				case <-notifier.Closed():
   291  					return
   292  				}
   293  				traced += uint64(len(txs))
   294  			}
   295  			// Generate the next state snapshot fast without tracing
   296  			_, _, _, _, err := api.eth.blockchain.Processor().Process(block, statedb, privateStateDb, vm.Config{})
   297  			if err != nil {
   298  				failed = err
   299  				break
   300  			}
   301  			// Finalize the state so any modifications are written to the trie
   302  			root, err := statedb.Commit(api.eth.blockchain.Config().IsEIP158(block.Number()))
   303  			if err != nil {
   304  				failed = err
   305  				break
   306  			}
   307  			if err := statedb.Reset(root); err != nil {
   308  				failed = err
   309  				break
   310  			}
   311  
   312  			privateStateRoot, err := privateStateDb.Commit(true)
   313  			if err != nil {
   314  				failed = err
   315  				break
   316  			}
   317  			if err := privateStateDb.Reset(privateStateRoot); err != nil {
   318  				failed = err
   319  				break
   320  			}
   321  			// Reference the trie twice, once for us, once for the tracer
   322  			database.TrieDB().Reference(root, common.Hash{})
   323  			if number >= origin {
   324  				database.TrieDB().Reference(root, common.Hash{})
   325  			}
   326  			// Dereference all past tries we ourselves are done working with
   327  			if proot != (common.Hash{}) {
   328  				database.TrieDB().Dereference(proot)
   329  			}
   330  			proot = root
   331  
   332  			// TODO(karalabe): Do we need the preimages? Won't they accumulate too much?
   333  		}
   334  	}()
   335  
   336  	// Keep reading the trace results and stream the to the user
   337  	go func() {
   338  		var (
   339  			done = make(map[uint64]*blockTraceResult)
   340  			next = origin + 1
   341  		)
   342  		for res := range results {
   343  			// Queue up next received result
   344  			result := &blockTraceResult{
   345  				Block:  hexutil.Uint64(res.block.NumberU64()),
   346  				Hash:   res.block.Hash(),
   347  				Traces: res.results,
   348  			}
   349  			done[uint64(result.Block)] = result
   350  
   351  			// Dereference any paret tries held in memory by this task
   352  			database.TrieDB().Dereference(res.rootref)
   353  
   354  			// Stream completed traces to the user, aborting on the first error
   355  			for result, ok := done[next]; ok; result, ok = done[next] {
   356  				if len(result.Traces) > 0 || next == end.NumberU64() {
   357  					notifier.Notify(sub.ID, result)
   358  				}
   359  				delete(done, next)
   360  				next++
   361  			}
   362  		}
   363  	}()
   364  	return sub, nil
   365  }
   366  
   367  // TraceBlockByNumber returns the structured logs created during the execution of
   368  // EVM and returns them as a JSON object.
   369  func (api *PrivateDebugAPI) TraceBlockByNumber(ctx context.Context, number rpc.BlockNumber, config *TraceConfig) ([]*txTraceResult, error) {
   370  	// Fetch the block that we want to trace
   371  	var block *types.Block
   372  
   373  	switch number {
   374  	case rpc.PendingBlockNumber:
   375  		block = api.eth.miner.PendingBlock()
   376  	case rpc.LatestBlockNumber:
   377  		block = api.eth.blockchain.CurrentBlock()
   378  	default:
   379  		block = api.eth.blockchain.GetBlockByNumber(uint64(number))
   380  	}
   381  	// Trace the block if it was found
   382  	if block == nil {
   383  		return nil, fmt.Errorf("block #%d not found", number)
   384  	}
   385  	return api.traceBlock(ctx, block, config)
   386  }
   387  
   388  // TraceBlockByHash returns the structured logs created during the execution of
   389  // EVM and returns them as a JSON object.
   390  func (api *PrivateDebugAPI) TraceBlockByHash(ctx context.Context, hash common.Hash, config *TraceConfig) ([]*txTraceResult, error) {
   391  	block := api.eth.blockchain.GetBlockByHash(hash)
   392  	if block == nil {
   393  		return nil, fmt.Errorf("block %#x not found", hash)
   394  	}
   395  	return api.traceBlock(ctx, block, config)
   396  }
   397  
   398  // TraceBlock returns the structured logs created during the execution of EVM
   399  // and returns them as a JSON object.
   400  func (api *PrivateDebugAPI) TraceBlock(ctx context.Context, blob []byte, config *TraceConfig) ([]*txTraceResult, error) {
   401  	block := new(types.Block)
   402  	if err := rlp.Decode(bytes.NewReader(blob), block); err != nil {
   403  		return nil, fmt.Errorf("could not decode block: %v", err)
   404  	}
   405  	return api.traceBlock(ctx, block, config)
   406  }
   407  
   408  // TraceBlockFromFile returns the structured logs created during the execution of
   409  // EVM and returns them as a JSON object.
   410  func (api *PrivateDebugAPI) TraceBlockFromFile(ctx context.Context, file string, config *TraceConfig) ([]*txTraceResult, error) {
   411  	blob, err := ioutil.ReadFile(file)
   412  	if err != nil {
   413  		return nil, fmt.Errorf("could not read file: %v", err)
   414  	}
   415  	return api.TraceBlock(ctx, blob, config)
   416  }
   417  
   418  // TraceBadBlockByHash returns the structured logs created during the execution of
   419  // EVM against a block pulled from the pool of bad ones and returns them as a JSON
   420  // object.
   421  func (api *PrivateDebugAPI) TraceBadBlock(ctx context.Context, hash common.Hash, config *TraceConfig) ([]*txTraceResult, error) {
   422  	blocks := api.eth.blockchain.BadBlocks()
   423  	for _, block := range blocks {
   424  		if block.Hash() == hash {
   425  			return api.traceBlock(ctx, block, config)
   426  		}
   427  	}
   428  	return nil, fmt.Errorf("bad block %#x not found", hash)
   429  }
   430  
   431  // StandardTraceBlockToFile dumps the structured logs created during the
   432  // execution of EVM to the local file system and returns a list of files
   433  // to the caller.
   434  func (api *PrivateDebugAPI) StandardTraceBlockToFile(ctx context.Context, hash common.Hash, config *StdTraceConfig) ([]string, error) {
   435  	block := api.eth.blockchain.GetBlockByHash(hash)
   436  	if block == nil {
   437  		return nil, fmt.Errorf("block %#x not found", hash)
   438  	}
   439  	return api.standardTraceBlockToFile(ctx, block, config)
   440  }
   441  
   442  // StandardTraceBadBlockToFile dumps the structured logs created during the
   443  // execution of EVM against a block pulled from the pool of bad ones to the
   444  // local file system and returns a list of files to the caller.
   445  func (api *PrivateDebugAPI) StandardTraceBadBlockToFile(ctx context.Context, hash common.Hash, config *StdTraceConfig) ([]string, error) {
   446  	blocks := api.eth.blockchain.BadBlocks()
   447  	for _, block := range blocks {
   448  		if block.Hash() == hash {
   449  			return api.standardTraceBlockToFile(ctx, block, config)
   450  		}
   451  	}
   452  	return nil, fmt.Errorf("bad block %#x not found", hash)
   453  }
   454  
   455  // traceBlock configures a new tracer according to the provided configuration, and
   456  // executes all the transactions contained within. The return value will be one item
   457  // per transaction, dependent on the requestd tracer.
   458  func (api *PrivateDebugAPI) traceBlock(ctx context.Context, block *types.Block, config *TraceConfig) ([]*txTraceResult, error) {
   459  	// Create the parent state database
   460  	if err := api.eth.engine.VerifyHeader(api.eth.blockchain, block.Header(), true); err != nil {
   461  		return nil, err
   462  	}
   463  	parent := api.eth.blockchain.GetBlock(block.ParentHash(), block.NumberU64()-1)
   464  	if parent == nil {
   465  		return nil, fmt.Errorf("parent %#x not found", block.ParentHash())
   466  	}
   467  	reexec := defaultTraceReexec
   468  	if config != nil && config.Reexec != nil {
   469  		reexec = *config.Reexec
   470  	}
   471  	statedb, privateStateDb, err := api.computeStateDB(parent, reexec)
   472  	if err != nil {
   473  		return nil, err
   474  	}
   475  	// Execute all the transaction contained within the block concurrently
   476  	var (
   477  		signer = types.MakeSigner(api.eth.blockchain.Config(), block.Number())
   478  
   479  		txs     = block.Transactions()
   480  		results = make([]*txTraceResult, len(txs))
   481  
   482  		pend = new(sync.WaitGroup)
   483  		jobs = make(chan *txTraceTask, len(txs))
   484  	)
   485  	threads := runtime.NumCPU()
   486  	if threads > len(txs) {
   487  		threads = len(txs)
   488  	}
   489  	for th := 0; th < threads; th++ {
   490  		pend.Add(1)
   491  		go func() {
   492  			defer pend.Done()
   493  
   494  			// Fetch and execute the next transaction trace tasks
   495  			for task := range jobs {
   496  				txn := txs[task.index]
   497  				msg, _ := txn.AsMessage(signer)
   498  				vmctx := core.NewEVMContext(msg, block.Header(), api.eth.blockchain, nil)
   499  
   500  				res, err := api.traceTx(ctx, msg, txn, vmctx, task.statedb, task.privateStateDb, config)
   501  				if err != nil {
   502  					results[task.index] = &txTraceResult{Error: err.Error()}
   503  					continue
   504  				}
   505  				results[task.index] = &txTraceResult{Result: res}
   506  			}
   507  		}()
   508  	}
   509  	// Feed the transactions into the tracers and return
   510  	var failed error
   511  	for i, tx := range txs {
   512  		// Send the trace task over for execution
   513  		jobs <- &txTraceTask{
   514  			statedb:        statedb.Copy(),
   515  			privateStateDb: privateStateDb.Copy(),
   516  			index:          i,
   517  		}
   518  
   519  		// Generate the next state snapshot fast without tracing
   520  		msg, _ := tx.AsMessage(signer)
   521  		vmctx := core.NewEVMContext(msg, block.Header(), api.eth.blockchain, nil)
   522  
   523  		// Quorum
   524  		privateStateDbToUse := core.PrivateStateDBForTxn(api.eth.blockchain.Config().IsQuorum, tx.IsPrivate(), statedb, privateStateDb)
   525  		vmenv := vm.NewEVM(vmctx, statedb, privateStateDbToUse, api.eth.blockchain.Config(), vm.Config{})
   526  		vmenv.SetCurrentTX(tx)
   527  		// /Quorum
   528  
   529  		if _, _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil {
   530  			failed = err
   531  			break
   532  		}
   533  		// Finalize the state so any modifications are written to the trie
   534  		// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
   535  		statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number()))
   536  		privateStateDb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number()))
   537  
   538  	}
   539  	close(jobs)
   540  	pend.Wait()
   541  
   542  	// If execution failed in between, abort
   543  	if failed != nil {
   544  		return nil, failed
   545  	}
   546  	return results, nil
   547  }
   548  
   549  // standardTraceBlockToFile configures a new tracer which uses standard JSON output,
   550  // and traces either a full block or an individual transaction. The return value will
   551  // be one filename per transaction traced.
   552  func (api *PrivateDebugAPI) standardTraceBlockToFile(ctx context.Context, block *types.Block, config *StdTraceConfig) ([]string, error) {
   553  	// If we're tracing a single transaction, make sure it's present
   554  	if config != nil && config.TxHash != (common.Hash{}) {
   555  		if !containsTx(block, config.TxHash) {
   556  			return nil, fmt.Errorf("transaction %#x not found in block", config.TxHash)
   557  		}
   558  	}
   559  	// Create the parent state database
   560  	if err := api.eth.engine.VerifyHeader(api.eth.blockchain, block.Header(), true); err != nil {
   561  		return nil, err
   562  	}
   563  	parent := api.eth.blockchain.GetBlock(block.ParentHash(), block.NumberU64()-1)
   564  	if parent == nil {
   565  		return nil, fmt.Errorf("parent %#x not found", block.ParentHash())
   566  	}
   567  	reexec := defaultTraceReexec
   568  	if config != nil && config.Reexec != nil {
   569  		reexec = *config.Reexec
   570  	}
   571  	statedb, privateStateDb, err := api.computeStateDB(parent, reexec)
   572  	if err != nil {
   573  		return nil, err
   574  	}
   575  	// Retrieve the tracing configurations, or use default values
   576  	var (
   577  		logConfig vm.LogConfig
   578  		txHash    common.Hash
   579  	)
   580  	if config != nil {
   581  		if config.LogConfig != nil {
   582  			logConfig = *config.LogConfig
   583  		}
   584  		txHash = config.TxHash
   585  	}
   586  	logConfig.Debug = true
   587  
   588  	// Execute transaction, either tracing all or just the requested one
   589  	var (
   590  		signer = types.MakeSigner(api.eth.blockchain.Config(), block.Number())
   591  		dumps  []string
   592  	)
   593  	for i, tx := range block.Transactions() {
   594  		// Prepare the trasaction for un-traced execution
   595  		var (
   596  			msg, _ = tx.AsMessage(signer)
   597  			vmctx  = core.NewEVMContext(msg, block.Header(), api.eth.blockchain, nil)
   598  
   599  			vmConf vm.Config
   600  			dump   *os.File
   601  			writer *bufio.Writer
   602  			err    error
   603  		)
   604  		// If the transaction needs tracing, swap out the configs
   605  		if tx.Hash() == txHash || txHash == (common.Hash{}) {
   606  			// Generate a unique temporary file to dump it into
   607  			prefix := fmt.Sprintf("block_%#x-%d-%#x-", block.Hash().Bytes()[:4], i, tx.Hash().Bytes()[:4])
   608  
   609  			dump, err = ioutil.TempFile(os.TempDir(), prefix)
   610  			if err != nil {
   611  				return nil, err
   612  			}
   613  			dumps = append(dumps, dump.Name())
   614  
   615  			// Swap out the noop logger to the standard tracer
   616  			writer = bufio.NewWriter(dump)
   617  			vmConf = vm.Config{
   618  				Debug:                   true,
   619  				Tracer:                  vm.NewJSONLogger(&logConfig, writer),
   620  				EnablePreimageRecording: true,
   621  			}
   622  		}
   623  		// Execute the transaction and flush any traces to disk
   624  		// Quorum
   625  		privateStateDbToUse := core.PrivateStateDBForTxn(api.eth.blockchain.Config().IsQuorum, tx.IsPrivate(), statedb, privateStateDb)
   626  		vmenv := vm.NewEVM(vmctx, statedb, privateStateDbToUse, api.eth.blockchain.Config(), vmConf)
   627  		vmenv.SetCurrentTX(tx)
   628  		// /Quorum
   629  
   630  		_, _, _, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()))
   631  		if writer != nil {
   632  			writer.Flush()
   633  		}
   634  		if dump != nil {
   635  			dump.Close()
   636  			log.Info("Wrote standard trace", "file", dump.Name())
   637  		}
   638  		if err != nil {
   639  			return dumps, err
   640  		}
   641  		// Finalize the state so any modifications are written to the trie
   642  		// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
   643  		statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number()))
   644  
   645  		// If we've traced the transaction we were looking for, abort
   646  		if tx.Hash() == txHash {
   647  			break
   648  		}
   649  	}
   650  	return dumps, nil
   651  }
   652  
   653  // containsTx reports whether the transaction with a certain hash
   654  // is contained within the specified block.
   655  func containsTx(block *types.Block, hash common.Hash) bool {
   656  	for _, tx := range block.Transactions() {
   657  		if tx.Hash() == hash {
   658  			return true
   659  		}
   660  	}
   661  	return false
   662  }
   663  
   664  // computeStateDB retrieves the state database associated with a certain block.
   665  // If no state is locally available for the given block, a number of blocks are
   666  // attempted to be reexecuted to generate the desired state.
   667  func (api *PrivateDebugAPI) computeStateDB(block *types.Block, reexec uint64) (*state.StateDB, *state.StateDB, error) {
   668  	// If we have the state fully available, use that
   669  	statedb, privateStateDb, err := api.eth.blockchain.StateAt(block.Root())
   670  	if err == nil {
   671  		return statedb, privateStateDb, nil
   672  	}
   673  	// Otherwise try to reexec blocks until we find a state or reach our limit
   674  	origin := block.NumberU64()
   675  	database := state.NewDatabaseWithCache(api.eth.ChainDb(), 16)
   676  
   677  	for i := uint64(0); i < reexec; i++ {
   678  		block = api.eth.blockchain.GetBlock(block.ParentHash(), block.NumberU64()-1)
   679  		if block == nil {
   680  			break
   681  		}
   682  		statedb, privateStateDb, err = api.eth.blockchain.StateAt(block.Root())
   683  		if err == nil {
   684  			break
   685  		}
   686  	}
   687  	if err != nil {
   688  		switch err.(type) {
   689  		case *trie.MissingNodeError:
   690  			return nil, nil, fmt.Errorf("required historical state unavailable (reexec=%d)", reexec)
   691  		default:
   692  			return nil, nil, err
   693  		}
   694  	}
   695  	// State was available at historical point, regenerate
   696  	var (
   697  		start  = time.Now()
   698  		logged time.Time
   699  		proot  common.Hash
   700  	)
   701  	for block.NumberU64() < origin {
   702  		// Print progress logs if long enough time elapsed
   703  		if time.Since(logged) > 8*time.Second {
   704  			log.Info("Regenerating historical state", "block", block.NumberU64()+1, "target", origin, "remaining", origin-block.NumberU64()-1, "elapsed", time.Since(start))
   705  			logged = time.Now()
   706  		}
   707  		// Retrieve the next block to regenerate and process it
   708  		if block = api.eth.blockchain.GetBlockByNumber(block.NumberU64() + 1); block == nil {
   709  			return nil, nil, fmt.Errorf("block #%d not found", block.NumberU64()+1)
   710  		}
   711  		_, _, _, _, err := api.eth.blockchain.Processor().Process(block, statedb, privateStateDb, vm.Config{})
   712  		if err != nil {
   713  			return nil, nil, fmt.Errorf("processing block %d failed: %v", block.NumberU64(), err)
   714  		}
   715  		// Finalize the state so any modifications are written to the trie
   716  		root, err := statedb.Commit(api.eth.blockchain.Config().IsEIP158(block.Number()))
   717  		if err != nil {
   718  			return nil, nil, err
   719  		}
   720  		if err := statedb.Reset(root); err != nil {
   721  			return nil, nil, fmt.Errorf("state reset after block %d failed: %v", block.NumberU64(), err)
   722  		}
   723  		privateStateRoot, err := privateStateDb.Commit(api.eth.blockchain.Config().IsEIP158(block.Number()))
   724  		if err != nil {
   725  			return nil, nil, err
   726  		}
   727  		if err := privateStateDb.Reset(privateStateRoot); err != nil {
   728  			return nil, nil, fmt.Errorf("state reset after block %d failed: %v", block.NumberU64(), err)
   729  		}
   730  		database.TrieDB().Reference(root, common.Hash{})
   731  		if proot != (common.Hash{}) {
   732  			database.TrieDB().Dereference(proot)
   733  		}
   734  		proot = root
   735  	}
   736  	nodes, imgs := database.TrieDB().Size()
   737  	log.Info("Historical state regenerated", "block", block.NumberU64(), "elapsed", time.Since(start), "nodes", nodes, "preimages", imgs)
   738  	return statedb, privateStateDb, nil
   739  }
   740  
   741  // TraceTransaction returns the structured logs created during the execution of EVM
   742  // and returns them as a JSON object.
   743  func (api *PrivateDebugAPI) TraceTransaction(ctx context.Context, hash common.Hash, config *TraceConfig) (interface{}, error) {
   744  	// Retrieve the transaction and assemble its EVM context
   745  	tx, blockHash, _, index := rawdb.ReadTransaction(api.eth.ChainDb(), hash)
   746  	if tx == nil {
   747  		return nil, fmt.Errorf("transaction %#x not found", hash)
   748  	}
   749  	reexec := defaultTraceReexec
   750  	if config != nil && config.Reexec != nil {
   751  		reexec = *config.Reexec
   752  	}
   753  	msg, vmctx, statedb, privateStateDb, err := api.computeTxEnv(blockHash, int(index), reexec)
   754  	if err != nil {
   755  		return nil, err
   756  	}
   757  	// Trace the transaction and return
   758  	return api.traceTx(ctx, msg, tx, vmctx, statedb, privateStateDb, config)
   759  }
   760  
   761  // traceTx configures a new tracer according to the provided configuration, and
   762  // executes the given message in the provided environment. The return value will
   763  // be tracer dependent.
   764  func (api *PrivateDebugAPI) traceTx(ctx context.Context, message core.Message, tx *types.Transaction, vmctx vm.Context, statedb *state.StateDB, privateStateDb *state.StateDB, config *TraceConfig) (interface{}, error) {
   765  	// Assemble the structured logger or the JavaScript tracer
   766  	var (
   767  		tracer vm.Tracer
   768  		err    error
   769  	)
   770  	switch {
   771  	case config != nil && config.Tracer != nil:
   772  		// Define a meaningful timeout of a single transaction trace
   773  		timeout := defaultTraceTimeout
   774  		if config.Timeout != nil {
   775  			if timeout, err = time.ParseDuration(*config.Timeout); err != nil {
   776  				return nil, err
   777  			}
   778  		}
   779  		// Constuct the JavaScript tracer to execute with
   780  		if tracer, err = tracers.New(*config.Tracer); err != nil {
   781  			return nil, err
   782  		}
   783  		// Handle timeouts and RPC cancellations
   784  		deadlineCtx, cancel := context.WithTimeout(ctx, timeout)
   785  		go func() {
   786  			<-deadlineCtx.Done()
   787  			tracer.(*tracers.Tracer).Stop(errors.New("execution timeout"))
   788  		}()
   789  		defer cancel()
   790  
   791  	case config == nil:
   792  		tracer = vm.NewStructLogger(nil)
   793  
   794  	default:
   795  		tracer = vm.NewStructLogger(config.LogConfig)
   796  	}
   797  
   798  	// Quorum
   799  	// Set the private state to public state if it is not a private message
   800  	isPrivate := false
   801  	if msg, ok := message.(core.PrivateMessage); ok && msg.IsPrivate() {
   802  		isPrivate = true
   803  	}
   804  	privateStateDbToUse := core.PrivateStateDBForTxn(api.eth.blockchain.Config().IsQuorum, isPrivate, statedb, privateStateDb)
   805  
   806  	// Run the transaction with tracing enabled.
   807  	vmenv := vm.NewEVM(vmctx, statedb, privateStateDbToUse, api.eth.blockchain.Config(), vm.Config{Debug: true, Tracer: tracer})
   808  	vmenv.SetCurrentTX(tx)
   809  	// /Quorum
   810  
   811  	ret, gas, failed, err := core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas()))
   812  	if err != nil {
   813  		return nil, fmt.Errorf("tracing failed: %v", err)
   814  	}
   815  	// Depending on the tracer type, format and return the output
   816  	switch tracer := tracer.(type) {
   817  	case *vm.StructLogger:
   818  		return &ethapi.ExecutionResult{
   819  			Gas:         gas,
   820  			Failed:      failed,
   821  			ReturnValue: fmt.Sprintf("%x", ret),
   822  			StructLogs:  ethapi.FormatLogs(tracer.StructLogs()),
   823  		}, nil
   824  
   825  	case *tracers.Tracer:
   826  		return tracer.GetResult()
   827  
   828  	default:
   829  		panic(fmt.Sprintf("bad tracer type %T", tracer))
   830  	}
   831  }
   832  
   833  // computeTxEnv returns the execution environment of a certain transaction.
   834  func (api *PrivateDebugAPI) computeTxEnv(blockHash common.Hash, txIndex int, reexec uint64) (core.Message, vm.Context, *state.StateDB, *state.StateDB, error) {
   835  	// Create the parent state database
   836  	block := api.eth.blockchain.GetBlockByHash(blockHash)
   837  	if block == nil {
   838  		return nil, vm.Context{}, nil, nil, fmt.Errorf("block %#x not found", blockHash)
   839  	}
   840  	parent := api.eth.blockchain.GetBlock(block.ParentHash(), block.NumberU64()-1)
   841  	if parent == nil {
   842  		return nil, vm.Context{}, nil, nil, fmt.Errorf("parent %#x not found", block.ParentHash())
   843  	}
   844  	statedb, privateStateDb, err := api.computeStateDB(parent, reexec)
   845  	if err != nil {
   846  		return nil, vm.Context{}, nil, nil, err
   847  	}
   848  
   849  	if txIndex == 0 && len(block.Transactions()) == 0 {
   850  		return nil, vm.Context{}, statedb, privateStateDb, nil
   851  	}
   852  
   853  	// Recompute transactions up to the target index.
   854  	signer := types.MakeSigner(api.eth.blockchain.Config(), block.Number())
   855  
   856  	for idx, tx := range block.Transactions() {
   857  		// Quorum
   858  		privateStateDbToUse := core.PrivateStateDBForTxn(api.eth.blockchain.Config().IsQuorum, tx.IsPrivate(), statedb, privateStateDb)
   859  		// /Quorum
   860  		// Assemble the transaction call message and return if the requested offset
   861  		msg, _ := tx.AsMessage(signer)
   862  		context := core.NewEVMContext(msg, block.Header(), api.eth.blockchain, nil)
   863  		if idx == txIndex {
   864  			return msg, context, statedb, privateStateDb, nil
   865  		}
   866  		// Not yet the searched for transaction, execute on top of the current state
   867  		vmenv := vm.NewEVM(context, statedb, privateStateDbToUse, api.eth.blockchain.Config(), vm.Config{})
   868  		vmenv.SetCurrentTX(tx)
   869  		if _, _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil {
   870  			return nil, vm.Context{}, nil, nil, fmt.Errorf("tx %#x failed: %v", tx.Hash(), err)
   871  		}
   872  		// Ensure any modifications are committed to the state
   873  		// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
   874  		statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number()))
   875  	}
   876  	return nil, vm.Context{}, nil, nil, fmt.Errorf("tx index %d out of range for block %#x", txIndex, blockHash)
   877  }