github.com/dominant-strategies/go-quai@v0.28.2/core/state_processor.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 core
    18  
    19  import (
    20  	"errors"
    21  	"fmt"
    22  	"math/big"
    23  	"sync"
    24  	"time"
    25  
    26  	"github.com/dominant-strategies/go-quai/common"
    27  	"github.com/dominant-strategies/go-quai/common/prque"
    28  	"github.com/dominant-strategies/go-quai/consensus"
    29  	"github.com/dominant-strategies/go-quai/core/rawdb"
    30  	"github.com/dominant-strategies/go-quai/core/state"
    31  	"github.com/dominant-strategies/go-quai/core/state/snapshot"
    32  	"github.com/dominant-strategies/go-quai/core/types"
    33  	"github.com/dominant-strategies/go-quai/core/vm"
    34  	"github.com/dominant-strategies/go-quai/crypto"
    35  	"github.com/dominant-strategies/go-quai/ethdb"
    36  	"github.com/dominant-strategies/go-quai/event"
    37  	"github.com/dominant-strategies/go-quai/log"
    38  	"github.com/dominant-strategies/go-quai/metrics"
    39  	"github.com/dominant-strategies/go-quai/params"
    40  	"github.com/dominant-strategies/go-quai/trie"
    41  	lru "github.com/hashicorp/golang-lru"
    42  )
    43  
    44  var (
    45  	accountReadTimer   = metrics.NewRegisteredTimer("chain/account/reads", nil)
    46  	accountHashTimer   = metrics.NewRegisteredTimer("chain/account/hashes", nil)
    47  	accountUpdateTimer = metrics.NewRegisteredTimer("chain/account/updates", nil)
    48  	accountCommitTimer = metrics.NewRegisteredTimer("chain/account/commits", nil)
    49  
    50  	storageReadTimer   = metrics.NewRegisteredTimer("chain/storage/reads", nil)
    51  	storageHashTimer   = metrics.NewRegisteredTimer("chain/storage/hashes", nil)
    52  	storageUpdateTimer = metrics.NewRegisteredTimer("chain/storage/updates", nil)
    53  	storageCommitTimer = metrics.NewRegisteredTimer("chain/storage/commits", nil)
    54  
    55  	snapshotAccountReadTimer = metrics.NewRegisteredTimer("chain/snapshot/account/reads", nil)
    56  	snapshotStorageReadTimer = metrics.NewRegisteredTimer("chain/snapshot/storage/reads", nil)
    57  	snapshotCommitTimer      = metrics.NewRegisteredTimer("chain/snapshot/commits", nil)
    58  )
    59  
    60  const (
    61  	receiptsCacheLimit = 32
    62  	txLookupCacheLimit = 1024
    63  	TriesInMemory      = 128
    64  
    65  	// BlockChainVersion ensures that an incompatible database forces a resync from scratch.
    66  	//
    67  	// Changelog:
    68  	//
    69  	// - Version 4
    70  	//   The following incompatible database changes were added:
    71  	//   * the `BlockNumber`, `TxHash`, `TxIndex`, `BlockHash` and `Index` fields of log are deleted
    72  	//   * the `Bloom` field of receipt is deleted
    73  	//   * the `BlockIndex` and `TxIndex` fields of txlookup are deleted
    74  	// - Version 5
    75  	//  The following incompatible database changes were added:
    76  	//    * the `TxHash`, `GasCost`, and `ContractAddress` fields are no longer stored for a receipt
    77  	//    * the `TxHash`, `GasCost`, and `ContractAddress` fields are computed by looking up the
    78  	//      receipts' corresponding block
    79  	// - Version 6
    80  	//  The following incompatible database changes were added:
    81  	//    * Transaction lookup information stores the corresponding block number instead of block hash
    82  	// - Version 7
    83  	//  The following incompatible database changes were added:
    84  	//    * Use freezer as the ancient database to maintain all ancient data
    85  	// - Version 8
    86  	//  The following incompatible database changes were added:
    87  	//    * New scheme for contract code in order to separate the codes and trie nodes
    88  	BlockChainVersion uint64 = 8
    89  )
    90  
    91  // CacheConfig contains the configuration values for the trie caching/pruning
    92  // that's resident in a blockchain.
    93  type CacheConfig struct {
    94  	TrieCleanLimit      int           // Memory allowance (MB) to use for caching trie nodes in memory
    95  	TrieCleanJournal    string        // Disk journal for saving clean cache entries.
    96  	TrieCleanRejournal  time.Duration // Time interval to dump clean cache to disk periodically
    97  	TrieCleanNoPrefetch bool          // Whether to disable heuristic state prefetching for followup blocks
    98  	TrieDirtyLimit      int           // Memory limit (MB) at which to start flushing dirty trie nodes to disk
    99  	TrieTimeLimit       time.Duration // Time limit after which to flush the current in-memory trie to disk
   100  	SnapshotLimit       int           // Memory allowance (MB) to use for caching snapshot entries in memory
   101  	Preimages           bool          // Whether to store preimage of trie key to the disk
   102  }
   103  
   104  // defaultCacheConfig are the default caching values if none are specified by the
   105  // user (also used during testing).
   106  var defaultCacheConfig = &CacheConfig{
   107  	TrieCleanLimit: 256,
   108  	TrieDirtyLimit: 256,
   109  	TrieTimeLimit:  5 * time.Minute,
   110  	SnapshotLimit:  256,
   111  }
   112  
   113  // StateProcessor is a basic Processor, which takes care of transitioning
   114  // state from one point to another.
   115  //
   116  // StateProcessor implements Processor.
   117  type StateProcessor struct {
   118  	config        *params.ChainConfig // Chain configuration options
   119  	hc            *HeaderChain        // Canonical block chain
   120  	engine        consensus.Engine    // Consensus engine used for block rewards
   121  	logsFeed      event.Feed
   122  	rmLogsFeed    event.Feed
   123  	cacheConfig   *CacheConfig   // CacheConfig for StateProcessor
   124  	stateCache    state.Database // State database to reuse between imports (contains state cache)
   125  	receiptsCache *lru.Cache     // Cache for the most recent receipts per block
   126  	txLookupCache *lru.Cache
   127  	validator     Validator // Block and state validator interface
   128  	prefetcher    Prefetcher
   129  	vmConfig      vm.Config
   130  
   131  	scope         event.SubscriptionScope
   132  	wg            sync.WaitGroup // chain processing wait group for shutting down
   133  	quit          chan struct{}  // state processor quit channel
   134  	txLookupLimit uint64
   135  
   136  	snaps  *snapshot.Tree
   137  	triegc *prque.Prque  // Priority queue mapping block numbers to tries to gc
   138  	gcproc time.Duration // Accumulates canonical block processing for trie dumping
   139  }
   140  
   141  // NewStateProcessor initialises a new StateProcessor.
   142  func NewStateProcessor(config *params.ChainConfig, hc *HeaderChain, engine consensus.Engine, vmConfig vm.Config, cacheConfig *CacheConfig, txLookupLimit *uint64) *StateProcessor {
   143  	receiptsCache, _ := lru.New(receiptsCacheLimit)
   144  	txLookupCache, _ := lru.New(txLookupCacheLimit)
   145  
   146  	if cacheConfig == nil {
   147  		cacheConfig = defaultCacheConfig
   148  	}
   149  
   150  	sp := &StateProcessor{
   151  		config:        config,
   152  		hc:            hc,
   153  		receiptsCache: receiptsCache,
   154  		txLookupCache: txLookupCache,
   155  		vmConfig:      vmConfig,
   156  		cacheConfig:   cacheConfig,
   157  		stateCache: state.NewDatabaseWithConfig(hc.headerDb, &trie.Config{
   158  			Cache:     cacheConfig.TrieCleanLimit,
   159  			Journal:   cacheConfig.TrieCleanJournal,
   160  			Preimages: cacheConfig.Preimages,
   161  		}),
   162  		engine: engine,
   163  		triegc: prque.New(nil),
   164  		quit:   make(chan struct{}),
   165  	}
   166  	sp.validator = NewBlockValidator(config, hc, engine)
   167  
   168  	// Load any existing snapshot, regenerating it if loading failed
   169  	if sp.cacheConfig.SnapshotLimit > 0 {
   170  		// TODO: If the state is not available, enable snapshot recovery
   171  		head := hc.CurrentHeader()
   172  		sp.snaps, _ = snapshot.New(hc.headerDb, sp.stateCache.TrieDB(), sp.cacheConfig.SnapshotLimit, head.Root(), true, false)
   173  	}
   174  	if txLookupLimit != nil {
   175  		sp.txLookupLimit = *txLookupLimit
   176  	}
   177  	// If periodic cache journal is required, spin it up.
   178  	if sp.cacheConfig.TrieCleanRejournal > 0 {
   179  		if sp.cacheConfig.TrieCleanRejournal < time.Minute {
   180  			log.Warn("Sanitizing invalid trie cache journal time", "provided", sp.cacheConfig.TrieCleanRejournal, "updated", time.Minute)
   181  			sp.cacheConfig.TrieCleanRejournal = time.Minute
   182  		}
   183  		triedb := sp.stateCache.TrieDB()
   184  		sp.wg.Add(1)
   185  		go func() {
   186  			defer sp.wg.Done()
   187  			triedb.SaveCachePeriodically(sp.cacheConfig.TrieCleanJournal, sp.cacheConfig.TrieCleanRejournal, sp.quit)
   188  		}()
   189  	}
   190  	return sp
   191  }
   192  
   193  // Process processes the state changes according to the Quai rules by running
   194  // the transaction messages using the statedb and applying any rewards to both
   195  // the processor (coinbase) and any included uncles.
   196  //
   197  // Process returns the receipts and logs accumulated during the process and
   198  // returns the amount of gas that was used in the process. If any of the
   199  // transactions failed to execute due to insufficient gas it will return an error.
   200  func (p *StateProcessor) Process(block *types.Block, etxSet types.EtxSet) (types.Receipts, []*types.Log, *state.StateDB, uint64, error) {
   201  	var (
   202  		receipts    types.Receipts
   203  		usedGas     = new(uint64)
   204  		header      = types.CopyHeader(block.Header())
   205  		blockHash   = block.Hash()
   206  		blockNumber = block.Number()
   207  		allLogs     []*types.Log
   208  		gp          = new(GasPool).AddGas(block.GasLimit())
   209  	)
   210  
   211  	start := time.Now()
   212  	parent := p.hc.GetBlock(block.Header().ParentHash(), block.NumberU64()-1)
   213  	if parent == nil {
   214  		return types.Receipts{}, []*types.Log{}, nil, 0, errors.New("parent block is nil for the block given to process")
   215  	}
   216  	time1 := common.PrettyDuration(time.Since(start))
   217  
   218  	// Initialize a statedb
   219  	statedb, err := state.New(parent.Header().Root(), p.stateCache, p.snaps)
   220  	if err != nil {
   221  		return types.Receipts{}, []*types.Log{}, nil, 0, err
   222  	}
   223  	time2 := common.PrettyDuration(time.Since(start))
   224  
   225  	var timeSenders, timeSign, timePrepare, timeEtx, timeTx time.Duration
   226  	startTimeSenders := time.Now()
   227  	senders := make(map[common.Hash]*common.InternalAddress) // temporary cache for senders of internal txs
   228  	numInternalTxs := 0
   229  	p.hc.pool.SendersMutex.RLock()
   230  	for _, tx := range block.Transactions() { // get all senders of internal txs from cache - easier on the SendersMutex to do it all at once here
   231  		if tx.Type() == types.InternalTxType || tx.Type() == types.InternalToExternalTxType {
   232  			numInternalTxs++
   233  			if sender, ok := p.hc.pool.GetSenderThreadUnsafe(tx.Hash()); ok {
   234  				senders[tx.Hash()] = &sender // This pointer must never be modified
   235  			} else {
   236  				// TODO: calcuate the sender and add it to the pool senders cache in case of reorg (not necessary for now)
   237  			}
   238  		}
   239  	}
   240  	p.hc.pool.SendersMutex.RUnlock()
   241  	timeSenders = time.Since(startTimeSenders)
   242  	blockContext := NewEVMBlockContext(header, p.hc, nil)
   243  	vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, p.vmConfig)
   244  	time3 := common.PrettyDuration(time.Since(start))
   245  
   246  	// Iterate over and process the individual transactions.
   247  	etxRLimit := len(parent.Transactions()) / params.ETXRegionMaxFraction
   248  	if etxRLimit < params.ETXRLimitMin {
   249  		etxRLimit = params.ETXRLimitMin
   250  	}
   251  	etxPLimit := len(parent.Transactions()) / params.ETXPrimeMaxFraction
   252  	if etxPLimit < params.ETXPLimitMin {
   253  		etxPLimit = params.ETXPLimitMin
   254  	}
   255  
   256  	for i, tx := range block.Transactions() {
   257  		startProcess := time.Now()
   258  		msg, err := tx.AsMessageWithSender(types.MakeSigner(p.config, header.Number()), header.BaseFee(), senders[tx.Hash()])
   259  		if err != nil {
   260  			return nil, nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
   261  		}
   262  		timeSignDelta := time.Since(startProcess)
   263  		timeSign += timeSignDelta
   264  
   265  		startTimePrepare := time.Now()
   266  		statedb.Prepare(tx.Hash(), i)
   267  		timePrepareDelta := time.Since(startTimePrepare)
   268  		timePrepare += timePrepareDelta
   269  
   270  		var receipt *types.Receipt
   271  		if tx.Type() == types.ExternalTxType {
   272  			startTimeEtx := time.Now()
   273  			etxEntry, exists := etxSet[tx.Hash()]
   274  			if !exists { // Verify that the ETX exists in the set
   275  				return nil, nil, nil, 0, fmt.Errorf("invalid external transaction: etx %x not found in unspent etx set", tx.Hash())
   276  			}
   277  			prevZeroBal := prepareApplyETX(statedb, &etxEntry.ETX)
   278  			receipt, err = applyTransaction(msg, p.config, p.hc, nil, gp, statedb, blockNumber, blockHash, &etxEntry.ETX, usedGas, vmenv, &etxRLimit, &etxPLimit)
   279  			statedb.SetBalance(common.ZeroInternal, prevZeroBal) // Reset the balance to what it previously was. Residual balance will be lost
   280  
   281  			if err != nil {
   282  				return nil, nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, etxEntry.ETX.Hash().Hex(), err)
   283  			}
   284  
   285  			delete(etxSet, etxEntry.ETX.Hash()) // This ETX has been spent so remove it from the unspent set
   286  			timeEtxDelta := time.Since(startTimeEtx)
   287  			timeEtx += timeEtxDelta
   288  
   289  		} else if tx.Type() == types.InternalTxType || tx.Type() == types.InternalToExternalTxType {
   290  			startTimeTx := time.Now()
   291  
   292  			receipt, err = applyTransaction(msg, p.config, p.hc, nil, gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv, &etxRLimit, &etxPLimit)
   293  			if err != nil {
   294  				return nil, nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
   295  			}
   296  			timeTxDelta := time.Since(startTimeTx)
   297  			timeTx += timeTxDelta
   298  		} else {
   299  			return nil, nil, nil, 0, ErrTxTypeNotSupported
   300  		}
   301  		receipts = append(receipts, receipt)
   302  		allLogs = append(allLogs, receipt.Logs...)
   303  		i++
   304  	}
   305  
   306  	time4 := common.PrettyDuration(time.Since(start))
   307  	// Finalize the block, applying any consensus engine specific extras (e.g. block rewards)
   308  	p.engine.Finalize(p.hc, header, statedb, block.Transactions(), block.Uncles())
   309  	time5 := common.PrettyDuration(time.Since(start))
   310  
   311  	log.Debug("Total Tx Processing Time", "signing time", common.PrettyDuration(timeSign), "prepare state time", common.PrettyDuration(timePrepare), "etx time", common.PrettyDuration(timeEtx), "tx time", common.PrettyDuration(timeTx))
   312  	log.Debug("Time taken in Process", "time1", time1, "time2", time2, "time3", time3, "time4", time4, "time5", time5)
   313  
   314  	log.Debug("Total Tx Processing Time", "signing time", common.PrettyDuration(timeSign), "senders cache time", common.PrettyDuration(timeSenders), "percent cached internal txs", fmt.Sprintf("%.2f", float64(len(senders))/float64(numInternalTxs)*100), "prepare state time", common.PrettyDuration(timePrepare), "etx time", common.PrettyDuration(timeEtx), "tx time", common.PrettyDuration(timeTx))
   315  
   316  	return receipts, allLogs, statedb, *usedGas, nil
   317  }
   318  
   319  func applyTransaction(msg types.Message, config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM, etxRLimit, etxPLimit *int) (*types.Receipt, error) {
   320  	// Create a new context to be used in the EVM environment.
   321  	txContext := NewEVMTxContext(msg)
   322  	evm.Reset(txContext, statedb)
   323  
   324  	// Apply the transaction to the current state (included in the env).
   325  	result, err := ApplyMessage(evm, msg, gp)
   326  	if err != nil {
   327  		return nil, err
   328  	}
   329  	var ETXRCount int
   330  	var ETXPCount int
   331  	for _, tx := range result.Etxs {
   332  		// Count which ETXs are cross-region
   333  		if tx.To().Location().CommonDom(common.NodeLocation).Context() == common.REGION_CTX {
   334  			ETXRCount++
   335  		}
   336  		// Count which ETXs are cross-prime
   337  		if tx.To().Location().CommonDom(common.NodeLocation).Context() == common.PRIME_CTX {
   338  			ETXPCount++
   339  		}
   340  	}
   341  	if ETXRCount > *etxRLimit {
   342  		return nil, fmt.Errorf("tx %032x emits too many cross-region ETXs for block. emitted: %d, limit: %d", tx.Hash(), ETXRCount, *etxRLimit)
   343  	}
   344  	if ETXPCount > *etxPLimit {
   345  		return nil, fmt.Errorf("tx %032x emits too many cross-prime ETXs for block. emitted: %d, limit: %d", tx.Hash(), ETXPCount, *etxPLimit)
   346  	}
   347  	*etxRLimit -= ETXRCount
   348  	*etxPLimit -= ETXPCount
   349  
   350  	// Update the state with pending changes.
   351  	var root []byte
   352  	statedb.Finalise(true)
   353  
   354  	*usedGas += result.UsedGas
   355  
   356  	// Create a new receipt for the transaction, storing the intermediate root and gas used
   357  	// by the tx.
   358  	receipt := &types.Receipt{Type: tx.Type(), PostState: root, CumulativeGasUsed: *usedGas, Etxs: result.Etxs}
   359  	if result.Failed() {
   360  		receipt.Status = types.ReceiptStatusFailed
   361  		log.Debug(result.Err.Error())
   362  	} else {
   363  		receipt.Status = types.ReceiptStatusSuccessful
   364  	}
   365  	receipt.TxHash = tx.Hash()
   366  	receipt.GasUsed = result.UsedGas
   367  
   368  	// If the transaction created a contract, store the creation address in the receipt.
   369  	if msg.To() == nil {
   370  		receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce(), tx.Data())
   371  	}
   372  
   373  	// Set the receipt logs and create the bloom filter.
   374  	receipt.Logs = statedb.GetLogs(tx.Hash(), blockHash)
   375  	receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
   376  	receipt.BlockHash = blockHash
   377  	receipt.BlockNumber = blockNumber
   378  	receipt.TransactionIndex = uint(statedb.TxIndex())
   379  	return receipt, err
   380  }
   381  
   382  var lastWrite uint64
   383  
   384  // Apply State
   385  func (p *StateProcessor) Apply(batch ethdb.Batch, block *types.Block, newInboundEtxs types.Transactions) ([]*types.Log, error) {
   386  	// Update the set of inbound ETXs which may be mined. This adds new inbound
   387  	// ETXs to the set and removes expired ETXs so they are no longer available
   388  	start := time.Now()
   389  	blockHash := block.Hash()
   390  	header := types.CopyHeader(block.Header())
   391  	etxSet := rawdb.ReadEtxSet(p.hc.bc.db, block.ParentHash(), block.NumberU64()-1)
   392  	time1 := common.PrettyDuration(time.Since(start))
   393  	if etxSet == nil {
   394  		return nil, errors.New("failed to load etx set")
   395  	}
   396  	etxSet.Update(newInboundEtxs, block.NumberU64())
   397  	time2 := common.PrettyDuration(time.Since(start))
   398  	// Process our block
   399  	receipts, logs, statedb, usedGas, err := p.Process(block, etxSet)
   400  	if err != nil {
   401  		return nil, err
   402  	}
   403  	if block.Hash() != blockHash {
   404  		log.Warn("Block hash changed after Processing the block", "old hash", blockHash, "new hash", block.Hash())
   405  	}
   406  	time3 := common.PrettyDuration(time.Since(start))
   407  	err = p.validator.ValidateState(block, statedb, receipts, usedGas)
   408  	if err != nil {
   409  		return nil, err
   410  	}
   411  	time4 := common.PrettyDuration(time.Since(start))
   412  	rawdb.WriteReceipts(batch, block.Hash(), block.NumberU64(), receipts)
   413  	time4_5 := common.PrettyDuration(time.Since(start))
   414  	// Create bloom filter and write it to cache/db
   415  	bloom := types.CreateBloom(receipts)
   416  	p.hc.AddBloom(bloom, block.Hash())
   417  	time5 := common.PrettyDuration(time.Since(start))
   418  	rawdb.WritePreimages(batch, statedb.Preimages())
   419  	time6 := common.PrettyDuration(time.Since(start))
   420  	// Commit all cached state changes into underlying memory database.
   421  	root, err := statedb.Commit(true)
   422  	if err != nil {
   423  		return nil, err
   424  	}
   425  	triedb := p.stateCache.TrieDB()
   426  	time7 := common.PrettyDuration(time.Since(start))
   427  	var time8 common.PrettyDuration
   428  	var time9 common.PrettyDuration
   429  	var time10 common.PrettyDuration
   430  	var time11 common.PrettyDuration
   431  	if err := triedb.Commit(root, false, nil); err != nil {
   432  		return nil, err
   433  	}
   434  	time8 = common.PrettyDuration(time.Since(start))
   435  	rawdb.WriteEtxSet(batch, header.Hash(), header.NumberU64(), etxSet)
   436  	time12 := common.PrettyDuration(time.Since(start))
   437  
   438  	log.Debug("times during state processor apply:", "t1:", time1, "t2:", time2, "t3:", time3, "t4:", time4, "t4.5:", time4_5, "t5:", time5, "t6:", time6, "t7:", time7, "t8:", time8, "t9:", time9, "t10:", time10, "t11:", time11, "t12:", time12)
   439  	return logs, nil
   440  }
   441  
   442  // ApplyTransaction attempts to apply a transaction to the given state database
   443  // and uses the input parameters for its environment. It returns the receipt
   444  // for the transaction, gas used and an error if the transaction failed,
   445  // indicating the block was invalid.
   446  func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config, etxRLimit, etxPLimit *int) (*types.Receipt, error) {
   447  	msg, err := tx.AsMessage(types.MakeSigner(config, header.Number()), header.BaseFee())
   448  	if err != nil {
   449  		return nil, err
   450  	}
   451  	// Create a new context to be used in the EVM environment
   452  	blockContext := NewEVMBlockContext(header, bc, author)
   453  	vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, config, cfg)
   454  	if tx.Type() == types.ExternalTxType {
   455  		prevZeroBal := prepareApplyETX(statedb, tx)
   456  		receipt, err := applyTransaction(msg, config, bc, author, gp, statedb, header.Number(), header.Hash(), tx, usedGas, vmenv, etxRLimit, etxPLimit)
   457  		statedb.SetBalance(common.ZeroInternal, prevZeroBal) // Reset the balance to what it previously was (currently a failed external transaction removes all the sent coins from the supply and any residual balance is gone as well)
   458  		return receipt, err
   459  	}
   460  	return applyTransaction(msg, config, bc, author, gp, statedb, header.Number(), header.Hash(), tx, usedGas, vmenv, etxRLimit, etxPLimit)
   461  }
   462  
   463  // GetVMConfig returns the block chain VM config.
   464  func (p *StateProcessor) GetVMConfig() *vm.Config {
   465  	return &p.vmConfig
   466  }
   467  
   468  // State returns a new mutable state based on the current HEAD block.
   469  func (p *StateProcessor) State() (*state.StateDB, error) {
   470  	return p.StateAt(p.hc.GetBlockByHash(p.hc.CurrentHeader().Hash()).Root())
   471  }
   472  
   473  // StateAt returns a new mutable state based on a particular point in time.
   474  func (p *StateProcessor) StateAt(root common.Hash) (*state.StateDB, error) {
   475  	return state.New(root, p.stateCache, p.snaps)
   476  }
   477  
   478  // StateCache returns the caching database underpinning the blockchain instance.
   479  func (p *StateProcessor) StateCache() state.Database {
   480  	return p.stateCache
   481  }
   482  
   483  // HasState checks if state trie is fully present in the database or not.
   484  func (p *StateProcessor) HasState(hash common.Hash) bool {
   485  	_, err := p.stateCache.OpenTrie(hash)
   486  	return err == nil
   487  }
   488  
   489  // HasBlockAndState checks if a block and associated state trie is fully present
   490  // in the database or not, caching it if present.
   491  func (p *StateProcessor) HasBlockAndState(hash common.Hash, number uint64) bool {
   492  	// Check first that the block itself is known
   493  	block := p.hc.GetBlock(hash, number)
   494  	if block == nil {
   495  		return false
   496  	}
   497  	return p.HasState(block.Root())
   498  }
   499  
   500  // GetReceiptsByHash retrieves the receipts for all transactions in a given block.
   501  func (p *StateProcessor) GetReceiptsByHash(hash common.Hash) types.Receipts {
   502  	if receipts, ok := p.receiptsCache.Get(hash); ok {
   503  		return receipts.(types.Receipts)
   504  	}
   505  	number := rawdb.ReadHeaderNumber(p.hc.headerDb, hash)
   506  	if number == nil {
   507  		return nil
   508  	}
   509  	receipts := rawdb.ReadReceipts(p.hc.headerDb, hash, *number, p.hc.config)
   510  	if receipts == nil {
   511  		return nil
   512  	}
   513  	p.receiptsCache.Add(hash, receipts)
   514  	return receipts
   515  }
   516  
   517  // GetTransactionLookup retrieves the lookup associate with the given transaction
   518  // hash from the cache or database.
   519  func (p *StateProcessor) GetTransactionLookup(hash common.Hash) *rawdb.LegacyTxLookupEntry {
   520  	// Short circuit if the txlookup already in the cache, retrieve otherwise
   521  	if lookup, exist := p.txLookupCache.Get(hash); exist {
   522  		return lookup.(*rawdb.LegacyTxLookupEntry)
   523  	}
   524  	tx, blockHash, blockNumber, txIndex := rawdb.ReadTransaction(p.hc.headerDb, hash)
   525  	if tx == nil {
   526  		return nil
   527  	}
   528  	lookup := &rawdb.LegacyTxLookupEntry{BlockHash: blockHash, BlockIndex: blockNumber, Index: txIndex}
   529  	p.txLookupCache.Add(hash, lookup)
   530  	return lookup
   531  }
   532  
   533  // ContractCode retrieves a blob of data associated with a contract hash
   534  // either from ephemeral in-memory cache, or from persistent storage.
   535  func (p *StateProcessor) ContractCode(hash common.Hash) ([]byte, error) {
   536  	return p.stateCache.ContractCode(common.Hash{}, hash)
   537  }
   538  
   539  // either from ephemeral in-memory cache, or from persistent storage.
   540  func (p *StateProcessor) TrieNode(hash common.Hash) ([]byte, error) {
   541  	return p.stateCache.TrieDB().Node(hash)
   542  }
   543  
   544  // ContractCodeWithPrefix retrieves a blob of data associated with a contract
   545  // hash either from ephemeral in-memory cache, or from persistent storage.
   546  //
   547  // If the code doesn't exist in the in-memory cache, check the storage with
   548  // new code scheme.
   549  func (p *StateProcessor) ContractCodeWithPrefix(hash common.Hash) ([]byte, error) {
   550  	type codeReader interface {
   551  		ContractCodeWithPrefix(addrHash, codeHash common.Hash) ([]byte, error)
   552  	}
   553  	return p.stateCache.(codeReader).ContractCodeWithPrefix(common.Hash{}, hash)
   554  }
   555  
   556  // StateAtBlock retrieves the state database associated with a certain block.
   557  // If no state is locally available for the given block, a number of blocks
   558  // are attempted to be reexecuted to generate the desired state. The optional
   559  // base layer statedb can be passed then it's regarded as the statedb of the
   560  // parent block.
   561  // Parameters:
   562  //   - block: The block for which we want the state (== state at the stateRoot of the parent)
   563  //   - reexec: The maximum number of blocks to reprocess trying to obtain the desired state
   564  //   - base: If the caller is tracing multiple blocks, the caller can provide the parent state
   565  //     continuously from the callsite.
   566  //   - checklive: if true, then the live 'blockchain' state database is used. If the caller want to
   567  //     perform Commit or other 'save-to-disk' changes, this should be set to false to avoid
   568  //     storing trash persistently
   569  func (p *StateProcessor) StateAtBlock(block *types.Block, reexec uint64, base *state.StateDB, checkLive bool) (statedb *state.StateDB, err error) {
   570  	var (
   571  		current  *types.Header
   572  		database state.Database
   573  		report   = true
   574  		origin   = block.NumberU64()
   575  	)
   576  	// Check the live database first if we have the state fully available, use that.
   577  	if checkLive {
   578  		statedb, err = p.StateAt(block.Root())
   579  		if err == nil {
   580  			return statedb, nil
   581  		}
   582  	}
   583  
   584  	var newHeads []*types.Header
   585  	if base != nil {
   586  		// The optional base statedb is given, mark the start point as parent block
   587  		statedb, database, report = base, base.Database(), false
   588  		current = p.hc.GetHeaderOrCandidate(block.ParentHash(), block.NumberU64()-1)
   589  	} else {
   590  		// Otherwise try to reexec blocks until we find a state or reach our limit
   591  		current = types.CopyHeader(block.Header())
   592  
   593  		// Create an ephemeral trie.Database for isolating the live one. Otherwise
   594  		// the internal junks created by tracing will be persisted into the disk.
   595  		database = state.NewDatabaseWithConfig(p.hc.headerDb, &trie.Config{Cache: 16})
   596  
   597  		// If we didn't check the dirty database, do check the clean one, otherwise
   598  		// we would rewind past a persisted block (specific corner case is chain
   599  		// tracing from the genesis).
   600  		if !checkLive {
   601  			statedb, err = state.New(current.Root(), database, nil)
   602  			if err == nil {
   603  				return statedb, nil
   604  			}
   605  		}
   606  		newHeads = append(newHeads, current)
   607  		// Database does not have the state for the given block, try to regenerate
   608  		for i := uint64(0); i < reexec; i++ {
   609  			if current.NumberU64() == 0 {
   610  				return nil, errors.New("genesis state is missing")
   611  			}
   612  			parent := p.hc.GetHeaderOrCandidate(current.ParentHash(), current.NumberU64()-1)
   613  			if parent == nil {
   614  				return nil, fmt.Errorf("missing block %v %d", current.ParentHash(), current.NumberU64()-1)
   615  			}
   616  			current = types.CopyHeader(parent)
   617  
   618  			statedb, err = state.New(current.Root(), database, nil)
   619  			if err == nil {
   620  				break
   621  			}
   622  			newHeads = append(newHeads, current)
   623  		}
   624  		if err != nil {
   625  			switch err.(type) {
   626  			case *trie.MissingNodeError:
   627  				return nil, fmt.Errorf("required historical state unavailable (reexec=%d)", reexec)
   628  			default:
   629  				return nil, err
   630  			}
   631  		}
   632  	}
   633  	// State was available at historical point, regenerate
   634  	var (
   635  		start  = time.Now()
   636  		logged time.Time
   637  		parent common.Hash
   638  	)
   639  	for i := len(newHeads) - 1; i >= 0; i-- {
   640  		current := newHeads[i]
   641  		// Print progress logs if long enough time elapsed
   642  		if time.Since(logged) > 8*time.Second && report {
   643  			log.Info("Regenerating historical state", "block", current.NumberU64()+1, "target", origin, "remaining", origin-current.NumberU64()-1, "elapsed", time.Since(start))
   644  			logged = time.Now()
   645  		}
   646  
   647  		etxSet := rawdb.ReadEtxSet(p.hc.bc.db, current.ParentHash(), current.NumberU64()-1)
   648  		if etxSet == nil {
   649  			return nil, errors.New("etxSet set is nil in StateProcessor")
   650  		}
   651  		inboundEtxs := rawdb.ReadInboundEtxs(p.hc.bc.db, current.Hash())
   652  		etxSet.Update(inboundEtxs, current.NumberU64())
   653  
   654  		currentBlock := rawdb.ReadBlock(p.hc.bc.db, current.Hash(), current.NumberU64())
   655  		if currentBlock == nil {
   656  			return nil, errors.New("detached block found trying to regenerate state")
   657  		}
   658  		_, _, _, _, err := p.Process(currentBlock, etxSet)
   659  		if err != nil {
   660  			return nil, fmt.Errorf("processing block %d failed: %v", current.NumberU64(), err)
   661  		}
   662  		// Finalize the state so any modifications are written to the trie
   663  		root, err := statedb.Commit(true)
   664  		if err != nil {
   665  			return nil, fmt.Errorf("stateAtBlock commit failed, number %d root %v: %w",
   666  				current.NumberU64(), current.Root().Hex(), err)
   667  		}
   668  		statedb, err = state.New(root, database, nil)
   669  		if err != nil {
   670  			return nil, fmt.Errorf("state reset after block %d failed: %v", current.NumberU64(), err)
   671  		}
   672  		database.TrieDB().Reference(root, common.Hash{})
   673  		if parent != (common.Hash{}) {
   674  			database.TrieDB().Dereference(parent)
   675  		}
   676  		parent = root
   677  	}
   678  	if report {
   679  		nodes, imgs := database.TrieDB().Size()
   680  		log.Info("Historical state regenerated", "block", current.NumberU64(), "elapsed", time.Since(start), "nodes", nodes, "preimages", imgs)
   681  	}
   682  	return statedb, nil
   683  }
   684  
   685  // stateAtTransaction returns the execution environment of a certain transaction.
   686  func (p *StateProcessor) StateAtTransaction(block *types.Block, txIndex int, reexec uint64) (Message, vm.BlockContext, *state.StateDB, error) {
   687  	// Short circuit if it's genesis block.
   688  	if block.NumberU64() == 0 {
   689  		return nil, vm.BlockContext{}, nil, errors.New("no transaction in genesis")
   690  	}
   691  	// Create the parent state database
   692  	parent := p.hc.GetBlock(block.ParentHash(), block.NumberU64()-1)
   693  	if parent == nil {
   694  		return nil, vm.BlockContext{}, nil, fmt.Errorf("parent %#x not found", block.ParentHash())
   695  	}
   696  	// Lookup the statedb of parent block from the live database,
   697  	// otherwise regenerate it on the flight.
   698  	statedb, err := p.StateAtBlock(parent, reexec, nil, true)
   699  	if err != nil {
   700  		return nil, vm.BlockContext{}, nil, err
   701  	}
   702  	if txIndex == 0 && len(block.Transactions()) == 0 {
   703  		return nil, vm.BlockContext{}, statedb, nil
   704  	}
   705  	// Recompute transactions up to the target index.
   706  	signer := types.MakeSigner(p.hc.Config(), block.Number())
   707  	for idx, tx := range block.Transactions() {
   708  		// Assemble the transaction call message and return if the requested offset
   709  		msg, _ := tx.AsMessage(signer, block.BaseFee())
   710  		txContext := NewEVMTxContext(msg)
   711  		context := NewEVMBlockContext(block.Header(), p.hc, nil)
   712  		if idx == txIndex {
   713  			return msg, context, statedb, nil
   714  		}
   715  		// Not yet the searched for transaction, execute on top of the current state
   716  		vmenv := vm.NewEVM(context, txContext, statedb, p.hc.Config(), vm.Config{})
   717  		statedb.Prepare(tx.Hash(), idx)
   718  		if _, err := ApplyMessage(vmenv, msg, new(GasPool).AddGas(tx.Gas())); err != nil {
   719  			return nil, vm.BlockContext{}, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err)
   720  		}
   721  		// Ensure any modifications are committed to the state
   722  		statedb.Finalise(true)
   723  	}
   724  	return nil, vm.BlockContext{}, nil, fmt.Errorf("transaction index %d out of range for block %#x", txIndex, block.Hash())
   725  }
   726  
   727  func (p *StateProcessor) Stop() {
   728  	// Ensure all live cached entries be saved into disk, so that we can skip
   729  	// cache warmup when node restarts.
   730  	if p.cacheConfig.TrieCleanJournal != "" {
   731  		triedb := p.stateCache.TrieDB()
   732  		triedb.SaveCache(p.cacheConfig.TrieCleanJournal)
   733  	}
   734  	close(p.quit)
   735  	log.Info("State Processor stopped")
   736  }
   737  
   738  func prepareApplyETX(statedb *state.StateDB, tx *types.Transaction) *big.Int {
   739  	prevZeroBal := statedb.GetBalance(common.ZeroInternal)   // Get current zero address balance
   740  	fee := big.NewInt(0).Add(tx.GasFeeCap(), tx.GasTipCap()) // Add gas price cap to miner tip cap
   741  	fee.Mul(fee, big.NewInt(int64(tx.Gas())))                // Multiply gas price by gas limit (may need to check for int64 overflow)
   742  	total := big.NewInt(0).Add(fee, tx.Value())              // Add gas fee to value
   743  	statedb.SetBalance(common.ZeroInternal, total)           // Use zero address at temp placeholder and set it to gas fee plus value
   744  	return prevZeroBal
   745  }