github.com/ebakus/go-ebakus@v1.0.5-0.20200520105415-dbccef9ec421/eth/api_tracer.go (about)

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