github.com/decred/dcrd/blockchain@v1.2.1/utxoviewpoint.go (about)

     1  // Copyright (c) 2015-2016 The btcsuite developers
     2  // Copyright (c) 2015-2019 The Decred developers
     3  // Use of this source code is governed by an ISC
     4  // license that can be found in the LICENSE file.
     5  
     6  package blockchain
     7  
     8  import (
     9  	"fmt"
    10  
    11  	"github.com/decred/dcrd/blockchain/stake"
    12  	"github.com/decred/dcrd/blockchain/standalone"
    13  	"github.com/decred/dcrd/chaincfg/chainhash"
    14  	"github.com/decred/dcrd/database"
    15  	"github.com/decred/dcrd/dcrutil"
    16  	"github.com/decred/dcrd/txscript"
    17  )
    18  
    19  // utxoOutput houses details about an individual unspent transaction output such
    20  // as whether or not it is spent, its public key script, and how much it pays.
    21  //
    22  // Standard public key scripts are stored in the database using a compressed
    23  // format. Since the vast majority of scripts are of the standard form, a fairly
    24  // significant savings is achieved by discarding the portions of the standard
    25  // scripts that can be reconstructed.
    26  //
    27  // Also, since it is common for only a specific output in a given utxo entry to
    28  // be referenced from a redeeming transaction, the script and amount for a given
    29  // output is not uncompressed until the first time it is accessed.  This
    30  // provides a mechanism to avoid the overhead of needlessly uncompressing all
    31  // outputs for a given utxo entry at the time of load.
    32  //
    33  // The struct is aligned for memory efficiency.
    34  type utxoOutput struct {
    35  	pkScript      []byte // The public key script for the output.
    36  	amount        int64  // The amount of the output.
    37  	scriptVersion uint16 // The script version
    38  	compressed    bool   // The public key script is compressed.
    39  	spent         bool   // Output is spent.
    40  }
    41  
    42  // maybeDecompress decompresses the amount and public key script fields of the
    43  // utxo and marks it decompressed if needed.
    44  func (o *utxoOutput) maybeDecompress(compressionVersion uint32) {
    45  	// Nothing to do if it's not compressed.
    46  	if !o.compressed {
    47  		return
    48  	}
    49  
    50  	o.pkScript = decompressScript(o.pkScript, compressionVersion)
    51  	o.compressed = false
    52  }
    53  
    54  // UtxoEntry contains contextual information about an unspent transaction such
    55  // as whether or not it is a coinbase transaction, which block it was found in,
    56  // and the spent status of its outputs.
    57  //
    58  // The struct is aligned for memory efficiency.
    59  type UtxoEntry struct {
    60  	sparseOutputs map[uint32]*utxoOutput // Sparse map of unspent outputs.
    61  	stakeExtra    []byte                 // Extra data for the staking system.
    62  
    63  	txType    stake.TxType // The stake type of the transaction.
    64  	height    uint32       // Height of block containing tx.
    65  	index     uint32       // Index of containing tx in block.
    66  	txVersion uint16       // The tx version of this tx.
    67  
    68  	isCoinBase bool // Whether entry is a coinbase tx.
    69  	hasExpiry  bool // Whether entry has an expiry.
    70  	modified   bool // Entry changed since load.
    71  }
    72  
    73  // TxVersion returns the transaction version of the transaction the
    74  // utxo represents.
    75  func (entry *UtxoEntry) TxVersion() uint16 {
    76  	return entry.txVersion
    77  }
    78  
    79  // HasExpiry returns the transaction expiry for the transaction that the utxo
    80  // entry represents.
    81  func (entry *UtxoEntry) HasExpiry() bool {
    82  	return entry.hasExpiry
    83  }
    84  
    85  // IsCoinBase returns whether or not the transaction the utxo entry represents
    86  // is a coinbase.
    87  func (entry *UtxoEntry) IsCoinBase() bool {
    88  	return entry.isCoinBase
    89  }
    90  
    91  // BlockHeight returns the height of the block containing the transaction the
    92  // utxo entry represents.
    93  func (entry *UtxoEntry) BlockHeight() int64 {
    94  	return int64(entry.height)
    95  }
    96  
    97  // BlockIndex returns the height of the block containing the transaction the
    98  // utxo entry represents.
    99  func (entry *UtxoEntry) BlockIndex() uint32 {
   100  	return entry.index
   101  }
   102  
   103  // TransactionType returns the transaction type of the transaction the utxo entry
   104  // represents.
   105  func (entry *UtxoEntry) TransactionType() stake.TxType {
   106  	return entry.txType
   107  }
   108  
   109  // IsOutputSpent returns whether or not the provided output index has been
   110  // spent based upon the current state of the unspent transaction output view
   111  // the entry was obtained from.
   112  //
   113  // Returns true if the output index references an output that does not exist
   114  // either due to it being invalid or because the output is not part of the view
   115  // due to previously being spent/pruned.
   116  func (entry *UtxoEntry) IsOutputSpent(outputIndex uint32) bool {
   117  	output, ok := entry.sparseOutputs[outputIndex]
   118  	if !ok {
   119  		return true
   120  	}
   121  
   122  	return output.spent
   123  }
   124  
   125  // SpendOutput marks the output at the provided index as spent.  Specifying an
   126  // output index that does not exist will not have any effect.
   127  func (entry *UtxoEntry) SpendOutput(outputIndex uint32) {
   128  	output, ok := entry.sparseOutputs[outputIndex]
   129  	if !ok {
   130  		return
   131  	}
   132  
   133  	// Nothing to do if the output is already spent.
   134  	if output.spent {
   135  		return
   136  	}
   137  
   138  	entry.modified = true
   139  	output.spent = true
   140  }
   141  
   142  // IsFullySpent returns whether or not the transaction the utxo entry represents
   143  // is fully spent.
   144  func (entry *UtxoEntry) IsFullySpent() bool {
   145  	// The entry is not fully spent if any of the outputs are unspent.
   146  	for _, output := range entry.sparseOutputs {
   147  		if !output.spent {
   148  			return false
   149  		}
   150  	}
   151  
   152  	return true
   153  }
   154  
   155  // AmountByIndex returns the amount of the provided output index.
   156  //
   157  // Returns 0 if the output index references an output that does not exist
   158  // either due to it being invalid or because the output is not part of the view
   159  // due to previously being spent/pruned.
   160  func (entry *UtxoEntry) AmountByIndex(outputIndex uint32) int64 {
   161  	output, ok := entry.sparseOutputs[outputIndex]
   162  	if !ok {
   163  		return 0
   164  	}
   165  
   166  	return output.amount
   167  }
   168  
   169  // ScriptVersionByIndex returns the public key script for the provided output
   170  // index.
   171  //
   172  // Returns 0 if the output index references an output that does not exist
   173  // either due to it being invalid or because the output is not part of the view
   174  // due to previously being spent/pruned.
   175  func (entry *UtxoEntry) ScriptVersionByIndex(outputIndex uint32) uint16 {
   176  	output, ok := entry.sparseOutputs[outputIndex]
   177  	if !ok {
   178  		return 0
   179  	}
   180  
   181  	return output.scriptVersion
   182  }
   183  
   184  // PkScriptByIndex returns the public key script for the provided output index.
   185  //
   186  // Returns nil if the output index references an output that does not exist
   187  // either due to it being invalid or because the output is not part of the view
   188  // due to previously being spent/pruned.
   189  func (entry *UtxoEntry) PkScriptByIndex(outputIndex uint32) []byte {
   190  	output, ok := entry.sparseOutputs[outputIndex]
   191  	if !ok {
   192  		return nil
   193  	}
   194  
   195  	// Ensure the output is decompressed before returning the script.
   196  	output.maybeDecompress(currentCompressionVersion)
   197  	return output.pkScript
   198  }
   199  
   200  // Clone returns a deep copy of the utxo entry.
   201  func (entry *UtxoEntry) Clone() *UtxoEntry {
   202  	if entry == nil {
   203  		return nil
   204  	}
   205  
   206  	newEntry := &UtxoEntry{
   207  		stakeExtra:    make([]byte, len(entry.stakeExtra)),
   208  		txVersion:     entry.txVersion,
   209  		height:        entry.height,
   210  		index:         entry.index,
   211  		txType:        entry.txType,
   212  		isCoinBase:    entry.isCoinBase,
   213  		hasExpiry:     entry.hasExpiry,
   214  		sparseOutputs: make(map[uint32]*utxoOutput),
   215  	}
   216  	copy(newEntry.stakeExtra, entry.stakeExtra)
   217  	for outputIndex, output := range entry.sparseOutputs {
   218  		newEntry.sparseOutputs[outputIndex] = &utxoOutput{
   219  			pkScript:      output.pkScript,
   220  			amount:        output.amount,
   221  			scriptVersion: output.scriptVersion,
   222  			compressed:    output.compressed,
   223  			spent:         output.spent,
   224  		}
   225  	}
   226  	return newEntry
   227  }
   228  
   229  // newUtxoEntry returns a new unspent transaction output entry with the provided
   230  // coinbase flag and block height ready to have unspent outputs added.
   231  func newUtxoEntry(txVersion uint16, height uint32, index uint32, isCoinBase bool, hasExpiry bool, txType stake.TxType) *UtxoEntry {
   232  	return &UtxoEntry{
   233  		sparseOutputs: make(map[uint32]*utxoOutput),
   234  		txVersion:     txVersion,
   235  		height:        height,
   236  		index:         index,
   237  		isCoinBase:    isCoinBase,
   238  		hasExpiry:     hasExpiry,
   239  		txType:        txType,
   240  	}
   241  }
   242  
   243  // UtxoViewpoint represents a view into the set of unspent transaction outputs
   244  // from a specific point of view in the chain.  For example, it could be for
   245  // the end of the main chain, some point in the history of the main chain, or
   246  // down a side chain.
   247  //
   248  // The unspent outputs are needed by other transactions for things such as
   249  // script validation and double spend prevention.
   250  type UtxoViewpoint struct {
   251  	entries  map[chainhash.Hash]*UtxoEntry
   252  	bestHash chainhash.Hash
   253  }
   254  
   255  // BestHash returns the hash of the best block in the chain the view currently
   256  // respresents.
   257  func (view *UtxoViewpoint) BestHash() *chainhash.Hash {
   258  	return &view.bestHash
   259  }
   260  
   261  // SetBestHash sets the hash of the best block in the chain the view currently
   262  // respresents.
   263  func (view *UtxoViewpoint) SetBestHash(hash *chainhash.Hash) {
   264  	view.bestHash = *hash
   265  }
   266  
   267  // LookupEntry returns information about a given transaction according to the
   268  // current state of the view.  It will return nil if the passed transaction
   269  // hash does not exist in the view or is otherwise not available such as when
   270  // it has been disconnected during a reorg.
   271  func (view *UtxoViewpoint) LookupEntry(txHash *chainhash.Hash) *UtxoEntry {
   272  	entry, ok := view.entries[*txHash]
   273  	if !ok {
   274  		return nil
   275  	}
   276  
   277  	return entry
   278  }
   279  
   280  // AddTxOuts adds all outputs in the passed transaction which are not provably
   281  // unspendable to the view.  When the view already has entries for any of the
   282  // outputs, they are simply marked unspent.  All fields will be updated for
   283  // existing entries since it's possible it has changed during a reorg.
   284  func (view *UtxoViewpoint) AddTxOuts(tx *dcrutil.Tx, blockHeight int64, blockIndex uint32) {
   285  	// When there are not already any utxos associated with the transaction,
   286  	// add a new entry for it to the view.
   287  	entry := view.LookupEntry(tx.Hash())
   288  	if entry == nil {
   289  		msgTx := tx.MsgTx()
   290  		txType := stake.DetermineTxType(msgTx)
   291  		entry = newUtxoEntry(msgTx.Version, uint32(blockHeight),
   292  			blockIndex, standalone.IsCoinBaseTx(msgTx), msgTx.Expiry != 0,
   293  			txType)
   294  		if txType == stake.TxTypeSStx {
   295  			stakeExtra := make([]byte, serializeSizeForMinimalOutputs(tx))
   296  			putTxToMinimalOutputs(stakeExtra, tx)
   297  			entry.stakeExtra = stakeExtra
   298  		}
   299  		view.entries[*tx.Hash()] = entry
   300  	} else {
   301  		entry.height = uint32(blockHeight)
   302  		entry.index = blockIndex
   303  	}
   304  	entry.modified = true
   305  
   306  	// Loop all of the transaction outputs and add those which are not
   307  	// provably unspendable.
   308  	for txOutIdx, txOut := range tx.MsgTx().TxOut {
   309  		// TODO allow pruning of stake utxs after all other outputs are spent
   310  		if txscript.IsUnspendable(txOut.Value, txOut.PkScript) {
   311  			continue
   312  		}
   313  
   314  		// Update existing entries.  All fields are updated because it's
   315  		// possible (although extremely unlikely) that the existing
   316  		// entry is being replaced by a different transaction with the
   317  		// same hash.  This is allowed so long as the previous
   318  		// transaction is fully spent.
   319  		if output, ok := entry.sparseOutputs[uint32(txOutIdx)]; ok {
   320  			output.spent = false
   321  			output.amount = txOut.Value
   322  			output.scriptVersion = txOut.Version
   323  			output.pkScript = txOut.PkScript
   324  			output.compressed = false
   325  			continue
   326  		}
   327  
   328  		// Add the unspent transaction output.
   329  		entry.sparseOutputs[uint32(txOutIdx)] = &utxoOutput{
   330  			spent:         false,
   331  			amount:        txOut.Value,
   332  			scriptVersion: txOut.Version,
   333  			pkScript:      txOut.PkScript,
   334  			compressed:    false,
   335  		}
   336  	}
   337  }
   338  
   339  // connectTransaction updates the view by adding all new utxos created by the
   340  // passed transaction and marking all utxos that the transactions spend as
   341  // spent.  In addition, when the 'stxos' argument is not nil, it will be updated
   342  // to append an entry for each spent txout.  An error will be returned if the
   343  // view does not contain the required utxos.
   344  func (view *UtxoViewpoint) connectTransaction(tx *dcrutil.Tx, blockHeight int64, blockIndex uint32, stxos *[]spentTxOut) error {
   345  	// Coinbase transactions don't have any inputs to spend.
   346  	msgTx := tx.MsgTx()
   347  	if standalone.IsCoinBaseTx(msgTx) {
   348  		// Add the transaction's outputs as available utxos.
   349  		view.AddTxOuts(tx, blockHeight, blockIndex)
   350  		return nil
   351  	}
   352  
   353  	// Spend the referenced utxos by marking them spent in the view and,
   354  	// if a slice was provided for the spent txout details, append an entry
   355  	// to it.
   356  	isVote := stake.IsSSGen(msgTx)
   357  	for txInIdx, txIn := range msgTx.TxIn {
   358  		// Ignore stakebase since it has no input.
   359  		if isVote && txInIdx == 0 {
   360  			continue
   361  		}
   362  
   363  		// Ensure the referenced utxo exists in the view.  This should
   364  		// never happen unless there is a bug is introduced in the code.
   365  		originIndex := txIn.PreviousOutPoint.Index
   366  		entry := view.entries[txIn.PreviousOutPoint.Hash]
   367  		if entry == nil {
   368  			return AssertError(fmt.Sprintf("view missing input %v",
   369  				txIn.PreviousOutPoint))
   370  		}
   371  		entry.SpendOutput(originIndex)
   372  
   373  		// Don't create the stxo details if not requested.
   374  		if stxos == nil {
   375  			continue
   376  		}
   377  
   378  		// Populate the stxo details using the utxo entry.  When the
   379  		// transaction is fully spent, set the additional stxo fields
   380  		// accordingly since those details will no longer be available
   381  		// in the utxo set.
   382  		var stxo = spentTxOut{
   383  			compressed:    false,
   384  			amount:        txIn.ValueIn,
   385  			scriptVersion: entry.ScriptVersionByIndex(originIndex),
   386  			pkScript:      entry.PkScriptByIndex(originIndex),
   387  		}
   388  		if entry.IsFullySpent() {
   389  			stxo.txVersion = entry.TxVersion()
   390  			stxo.height = uint32(entry.BlockHeight())
   391  			stxo.index = entry.BlockIndex()
   392  			stxo.isCoinBase = entry.IsCoinBase()
   393  			stxo.hasExpiry = entry.HasExpiry()
   394  			stxo.txType = entry.TransactionType()
   395  			stxo.txFullySpent = true
   396  
   397  			if entry.txType == stake.TxTypeSStx {
   398  				stxo.stakeExtra = entry.stakeExtra
   399  			}
   400  		}
   401  
   402  		// Append the entry to the provided spent txouts slice.
   403  		*stxos = append(*stxos, stxo)
   404  	}
   405  
   406  	// Add the transaction's outputs as available utxos.
   407  	view.AddTxOuts(tx, blockHeight, blockIndex)
   408  
   409  	return nil
   410  }
   411  
   412  // disconnectTransactions updates the view by removing all utxos created by
   413  // the transactions in either the regular or stake tree of the block, depending
   414  // on the flag, and unspending all of the txos spent by those same transactions
   415  // by using the provided spent txo information.
   416  func (view *UtxoViewpoint) disconnectTransactions(block *dcrutil.Block, stxos []spentTxOut, stakeTree bool) error {
   417  	// Choose which transaction tree to use and the appropriate offset into the
   418  	// spent transaction outputs that corresponds to them depending on the flag.
   419  	// Transactions in the stake tree are spent before transactions in the
   420  	// regular tree, thus skip all of the outputs spent by the regular tree when
   421  	// disconnecting stake transactions.
   422  	stxoIdx := len(stxos) - 1
   423  	transactions := block.Transactions()
   424  	if stakeTree {
   425  		stxoIdx = len(stxos) - countSpentRegularOutputs(block) - 1
   426  		transactions = block.STransactions()
   427  	}
   428  
   429  	for txIdx := len(transactions) - 1; txIdx > -1; txIdx-- {
   430  		tx := transactions[txIdx]
   431  		msgTx := tx.MsgTx()
   432  		txType := stake.TxTypeRegular
   433  		if stakeTree {
   434  			txType = stake.DetermineTxType(msgTx)
   435  		}
   436  		isVote := txType == stake.TxTypeSSGen
   437  
   438  		// Clear this transaction from the view if it already exists or create a
   439  		// new empty entry for when it does not.  This is done because the code
   440  		// relies on its existence in the view in order to signal modifications
   441  		// have happened.
   442  		isCoinbase := !stakeTree && txIdx == 0
   443  		entry := view.entries[*tx.Hash()]
   444  		if entry == nil {
   445  			entry = newUtxoEntry(msgTx.Version, uint32(block.Height()),
   446  				uint32(txIdx), isCoinbase, msgTx.Expiry != 0, txType)
   447  			view.entries[*tx.Hash()] = entry
   448  		}
   449  		entry.modified = true
   450  		entry.sparseOutputs = make(map[uint32]*utxoOutput)
   451  
   452  		// Loop backwards through all of the transaction inputs (except for the
   453  		// coinbase which has no inputs) and unspend the referenced txos.  This
   454  		// is necessary to match the order of the spent txout entries.
   455  		if isCoinbase {
   456  			continue
   457  		}
   458  		for txInIdx := len(msgTx.TxIn) - 1; txInIdx > -1; txInIdx-- {
   459  			// Ignore stakebase since it has no input.
   460  			if isVote && txInIdx == 0 {
   461  				continue
   462  			}
   463  
   464  			// Ensure the spent txout index is decremented to stay in sync with
   465  			// the transaction input.
   466  			stxo := &stxos[stxoIdx]
   467  			stxoIdx--
   468  
   469  			// When there is not already an entry for the referenced transaction
   470  			// in the view, it means it was fully spent, so create a new utxo
   471  			// entry in order to resurrect it.
   472  			txIn := msgTx.TxIn[txInIdx]
   473  			originHash := &txIn.PreviousOutPoint.Hash
   474  			originIndex := txIn.PreviousOutPoint.Index
   475  			entry := view.entries[*originHash]
   476  			if entry == nil {
   477  				if !stxo.txFullySpent {
   478  					return AssertError(fmt.Sprintf("tried to revive unspent "+
   479  						"tx %v from non-fully spent stx entry", originHash))
   480  				}
   481  				entry = newUtxoEntry(msgTx.Version, stxo.height, stxo.index,
   482  					stxo.isCoinBase, stxo.hasExpiry, stxo.txType)
   483  				if stxo.txType == stake.TxTypeSStx {
   484  					entry.stakeExtra = stxo.stakeExtra
   485  				}
   486  				view.entries[*originHash] = entry
   487  			}
   488  
   489  			// Mark the entry as modified since it is either new or will be
   490  			// changed below.
   491  			entry.modified = true
   492  
   493  			// Restore the specific utxo using the stxo data from the spend
   494  			// journal if it doesn't already exist in the view.
   495  			output, ok := entry.sparseOutputs[originIndex]
   496  			if !ok {
   497  				// Add the unspent transaction output.
   498  				entry.sparseOutputs[originIndex] = &utxoOutput{
   499  					compressed:    stxo.compressed,
   500  					spent:         false,
   501  					amount:        txIn.ValueIn,
   502  					scriptVersion: stxo.scriptVersion,
   503  					pkScript:      stxo.pkScript,
   504  				}
   505  				continue
   506  			}
   507  
   508  			// Mark the existing referenced transaction output as unspent.
   509  			output.spent = false
   510  		}
   511  	}
   512  
   513  	return nil
   514  }
   515  
   516  // disconnectRegularTransactions updates the view by removing all utxos created
   517  // by the transactions in regular tree of the provided block and unspending all
   518  // of the txos spent by those same transactions by using the provided spent txo
   519  // information.
   520  func (view *UtxoViewpoint) disconnectRegularTransactions(block *dcrutil.Block, stxos []spentTxOut) error {
   521  	return view.disconnectTransactions(block, stxos, false)
   522  }
   523  
   524  // disconnectStakeTransactions updates the view by removing all utxos created
   525  // by the transactions in stake tree of the provided block and unspending all
   526  // of the txos spent by those same transactions by using the provided spent txo
   527  // information.
   528  func (view *UtxoViewpoint) disconnectStakeTransactions(block *dcrutil.Block, stxos []spentTxOut) error {
   529  	return view.disconnectTransactions(block, stxos, true)
   530  }
   531  
   532  // disconnectDisapprovedBlock updates the view by disconnecting all of the
   533  // transactions in the regular tree of the passed block.
   534  //
   535  // Disconnecting a transaction entails removing the utxos created by it and
   536  // restoring the outputs spent by it with the help of the provided spent txo
   537  // information.
   538  //func (view *UtxoViewpoint) disconnectDisapprovedBlock(db database.DB, block *dcrutil.Block, stxos []spentTxOut) error {
   539  func (view *UtxoViewpoint) disconnectDisapprovedBlock(db database.DB, block *dcrutil.Block) error {
   540  	// Load all of the spent txos for the block from the database spend journal.
   541  	var stxos []spentTxOut
   542  	err := db.View(func(dbTx database.Tx) error {
   543  		var err error
   544  		stxos, err = dbFetchSpendJournalEntry(dbTx, block)
   545  		return err
   546  	})
   547  	if err != nil {
   548  		return err
   549  	}
   550  
   551  	// Load all of the utxos referenced by the inputs for all transactions in
   552  	// the block that don't already exist in the utxo view from the database.
   553  	err = view.fetchRegularInputUtxos(db, block)
   554  	if err != nil {
   555  		return err
   556  	}
   557  
   558  	// Sanity check the correct number of stxos are provided.
   559  	if len(stxos) != countSpentOutputs(block) {
   560  		panicf("provided %v stxos for block %v (height %v) which spends %v "+
   561  			"outputs", len(stxos), block.Hash(), block.MsgBlock().Header.Height,
   562  			countSpentOutputs(block))
   563  	}
   564  
   565  	return view.disconnectRegularTransactions(block, stxos)
   566  }
   567  
   568  // connectBlock updates the view by potentially disconnecting all of the
   569  // transactions in the regular tree of the parent block of the passed block in
   570  // the case the passed block disapproves the parent block, connecting all of
   571  // transactions in both the regular and stake trees of the passed block, and
   572  // setting the best hash for the view to the passed block.
   573  //
   574  // Connecting a transaction entails marking all utxos it spends as spent, and
   575  // adding all of the new utxos created by it.
   576  //
   577  // Disconnecting a transaction entails removing the utxos created by it and
   578  // restoring the outputs spent by it with the help of the provided spent txo
   579  // information.
   580  //
   581  // In addition, when the 'stxos' argument is not nil, it will be updated to
   582  // append an entry for each spent txout.
   583  func (view *UtxoViewpoint) connectBlock(db database.DB, block, parent *dcrutil.Block, stxos *[]spentTxOut) error {
   584  	// Disconnect the transactions in the regular tree of the parent block if
   585  	// the passed block disapproves it.
   586  	if !headerApprovesParent(&block.MsgBlock().Header) {
   587  		err := view.disconnectDisapprovedBlock(db, parent)
   588  		if err != nil {
   589  			return err
   590  		}
   591  	}
   592  
   593  	// Load all of the utxos referenced by the inputs for all transactions in
   594  	// the block that don't already exist in the utxo view from the database.
   595  	err := view.fetchInputUtxos(db, block)
   596  	if err != nil {
   597  		return err
   598  	}
   599  
   600  	// Connect all of the transactions in both the regular and stake trees of
   601  	// the block.  Notice that the stake tree is connected before the regular
   602  	// tree.  This means that stake transactions are not able to redeem outputs
   603  	// of transactions created in the regular tree of the same block, which is
   604  	// important since the regular tree may be disapproved by the subsequent
   605  	// block while the stake tree must remain valid.
   606  	for i, stx := range block.STransactions() {
   607  		err := view.connectTransaction(stx, block.Height(), uint32(i), stxos)
   608  		if err != nil {
   609  			return err
   610  		}
   611  	}
   612  	for i, tx := range block.Transactions() {
   613  		err := view.connectTransaction(tx, block.Height(), uint32(i), stxos)
   614  		if err != nil {
   615  			return err
   616  		}
   617  	}
   618  
   619  	// Update the best hash for view to include this block since all of its
   620  	// transactions have been connected.
   621  	view.SetBestHash(block.Hash())
   622  	return nil
   623  }
   624  
   625  // disconnectBlock updates the view by disconnecting all transactions in both
   626  // the regular and stake trees of the passed block, in the case the block
   627  // disapproves the parent block, reconnecting all of the transactions in the
   628  // regular tree of the previous block, and setting the best hash for the view to
   629  // the parent block.
   630  //
   631  // Connecting a transaction entails marking all utxos it spends as spent, and
   632  // adding all of the new utxos created by it.
   633  //
   634  // Disconnecting a transaction entails removing the utxos created by it and
   635  // restoring the outputs spent by it with the help of the provided spent txo
   636  // information.
   637  //
   638  // Note that, unlike block connection, the spent transaction output (stxo)
   639  // information is required and failure to provide it will result in an assertion
   640  // panic.
   641  func (view *UtxoViewpoint) disconnectBlock(db database.DB, block, parent *dcrutil.Block, stxos []spentTxOut) error {
   642  	// Sanity check the correct number of stxos are provided.
   643  	if len(stxos) != countSpentOutputs(block) {
   644  		panicf("provided %v stxos for block %v (height %v) which spends %v "+
   645  			"outputs", len(stxos), block.Hash(), block.MsgBlock().Header.Height,
   646  			countSpentOutputs(block))
   647  	}
   648  
   649  	// Load all of the utxos referenced by the inputs for all transactions in
   650  	// the block don't already exist in the utxo view from the database.
   651  	err := view.fetchInputUtxos(db, block)
   652  	if err != nil {
   653  		return err
   654  	}
   655  
   656  	// Disconnect all of the transactions in both the regular and stake trees of
   657  	// the block.  Notice that the regular tree is disconnected before the stake
   658  	// tree since that is the reverse of how they are connected.
   659  	err = view.disconnectRegularTransactions(block, stxos)
   660  	if err != nil {
   661  		return err
   662  	}
   663  	err = view.disconnectStakeTransactions(block, stxos)
   664  	if err != nil {
   665  		return err
   666  	}
   667  
   668  	// Reconnect the transactions in the regular tree of the parent block if the
   669  	// block that is being disconnected disapproves it.
   670  	if !headerApprovesParent(&block.MsgBlock().Header) {
   671  		// Load all of the utxos referenced by the inputs for all transactions
   672  		// in the regular tree of the parent block that don't already exist in
   673  		// the utxo view from the database.
   674  		err := view.fetchRegularInputUtxos(db, parent)
   675  		if err != nil {
   676  			return err
   677  		}
   678  
   679  		for i, tx := range parent.Transactions() {
   680  			err := view.connectTransaction(tx, parent.Height(), uint32(i), nil)
   681  			if err != nil {
   682  				return err
   683  			}
   684  		}
   685  	}
   686  
   687  	// Update the best hash for view to include this block since all of its
   688  	// transactions have been connected.
   689  	view.SetBestHash(&block.MsgBlock().Header.PrevBlock)
   690  	return nil
   691  }
   692  
   693  // Entries returns the underlying map that stores of all the utxo entries.
   694  func (view *UtxoViewpoint) Entries() map[chainhash.Hash]*UtxoEntry {
   695  	return view.entries
   696  }
   697  
   698  // commit prunes all entries marked modified that are now fully spent and marks
   699  // all entries as unmodified.
   700  func (view *UtxoViewpoint) commit() {
   701  	for txHash, entry := range view.entries {
   702  		if entry == nil || (entry.modified && entry.IsFullySpent()) {
   703  			delete(view.entries, txHash)
   704  			continue
   705  		}
   706  
   707  		entry.modified = false
   708  	}
   709  }
   710  
   711  // viewFilteredSet represents a set of utxos to fetch from the database that are
   712  // not already in a view.
   713  type viewFilteredSet map[chainhash.Hash]struct{}
   714  
   715  // add conditionally adds the provided utxo hash to the set if it does not
   716  // already exist in the provided view.
   717  func (set viewFilteredSet) add(view *UtxoViewpoint, hash *chainhash.Hash) {
   718  	if _, ok := view.entries[*hash]; !ok {
   719  		set[*hash] = struct{}{}
   720  	}
   721  }
   722  
   723  // fetchUtxosMain fetches unspent transaction output data about the provided
   724  // set of transactions from the point of view of the end of the main chain at
   725  // the time of the call.
   726  //
   727  // Upon completion of this function, the view will contain an entry for each
   728  // requested transaction.  Fully spent transactions, or those which otherwise
   729  // don't exist, will result in a nil entry in the view.
   730  func (view *UtxoViewpoint) fetchUtxosMain(db database.DB, filteredSet viewFilteredSet) error {
   731  	// Nothing to do if there are no requested hashes.
   732  	if len(filteredSet) == 0 {
   733  		return nil
   734  	}
   735  
   736  	// Load the unspent transaction output information for the requested set
   737  	// of transactions from the point of view of the end of the main chain.
   738  	//
   739  	// NOTE: Missing entries are not considered an error here and instead
   740  	// will result in nil entries in the view.  This is intentionally done
   741  	// since other code uses the presence of an entry in the store as a way
   742  	// to optimize spend and unspend updates to apply only to the specific
   743  	// utxos that the caller needs access to.
   744  	return db.View(func(dbTx database.Tx) error {
   745  		for hash := range filteredSet {
   746  			hashCopy := hash
   747  			entry, err := dbFetchUtxoEntry(dbTx, &hashCopy)
   748  			if err != nil {
   749  				return err
   750  			}
   751  
   752  			view.entries[hash] = entry
   753  		}
   754  
   755  		return nil
   756  	})
   757  }
   758  
   759  // addRegularInputUtxos adds any outputs of transactions in the regular tree of
   760  // the provided block that are referenced by inputs of transactions that are
   761  // located later in the regular tree of the block and returns a set of the
   762  // referenced outputs that are not already in the view and thus need to be
   763  // fetched from the database.
   764  func (view *UtxoViewpoint) addRegularInputUtxos(block *dcrutil.Block) viewFilteredSet {
   765  	// Build a map of in-flight transactions because some of the inputs in the
   766  	// regular transaction tree of this block could be referencing other
   767  	// transactions earlier in the block which are not yet in the chain.
   768  	txInFlight := map[chainhash.Hash]int{}
   769  	regularTxns := block.Transactions()
   770  	for i, tx := range regularTxns {
   771  		txInFlight[*tx.Hash()] = i
   772  	}
   773  
   774  	// Loop through all of the inputs of the transactions in the regular
   775  	// transaction tree (except for the coinbase which has no inputs) collecting
   776  	// them into sets of what is needed and what is already known (in-flight).
   777  	filteredSet := make(viewFilteredSet)
   778  	for i, tx := range regularTxns[1:] {
   779  		for _, txIn := range tx.MsgTx().TxIn {
   780  			// It is acceptable for a transaction input in the regular tree to
   781  			// reference the output of another transaction in the regular tree
   782  			// of this block only if the referenced transaction comes before the
   783  			// current one in this block.  Add the outputs of the referenced
   784  			// transaction as available utxos when this is the case.  Otherwise,
   785  			// the utxo details are still needed.
   786  			//
   787  			// NOTE: The >= is correct here because i is one less than the
   788  			// actual position of the transaction within the block due to
   789  			// skipping the coinbase.
   790  			originHash := &txIn.PreviousOutPoint.Hash
   791  			if inFlightIndex, ok := txInFlight[*originHash]; ok &&
   792  				i >= inFlightIndex {
   793  
   794  				originTx := regularTxns[inFlightIndex]
   795  				view.AddTxOuts(originTx, block.Height(), uint32(inFlightIndex))
   796  				continue
   797  			}
   798  
   799  			// Only request entries that are not already in the view from the
   800  			// database.
   801  			filteredSet.add(view, originHash)
   802  		}
   803  	}
   804  
   805  	return filteredSet
   806  }
   807  
   808  // fetchRegularInputUtxos loads utxo details about the input transactions
   809  // referenced by the transactions in the regular tree of the given block into
   810  // the view from the database as needed.  In particular, referenced entries that
   811  // are earlier in the block are added to the view and entries that are already
   812  // in the view are not modified.
   813  func (view *UtxoViewpoint) fetchRegularInputUtxos(db database.DB, block *dcrutil.Block) error {
   814  	// Add any outputs of transactions in the regular tree of the block that are
   815  	// referenced by inputs of transactions that are located later in the tree
   816  	// and fetch any inputs that are not already in the view from the database.
   817  	filteredSet := view.addRegularInputUtxos(block)
   818  	return view.fetchUtxosMain(db, filteredSet)
   819  }
   820  
   821  // fetchInputUtxos loads utxo details about the input transactions referenced
   822  // by the transactions in both the regular and stake trees of the given block
   823  // into the view from the database as needed.  In the case of regular tree,
   824  // referenced entries that are earlier in the regular tree of the block are
   825  // added to the view.  In all cases, entries that are already in the view are
   826  // not modified.
   827  func (view *UtxoViewpoint) fetchInputUtxos(db database.DB, block *dcrutil.Block) error {
   828  	// Add any outputs of transactions in the regular tree of the block that are
   829  	// referenced by inputs of transactions that are located later in the tree
   830  	// and, while doing so, determine which inputs are not already in the view
   831  	// and thus need to be fetched from the database.
   832  	filteredSet := view.addRegularInputUtxos(block)
   833  
   834  	// Loop through all of the inputs of the transaction in the stake tree and
   835  	// add those that aren't already known to the set of what is needed.
   836  	//
   837  	// Note that, unlike in the regular transaction tree, transactions in the
   838  	// stake tree are not allowed to access outputs of transactions earlier in
   839  	// the block.  This applies to both transactions earlier in the stake tree
   840  	// as well as those in the regular tree.
   841  	for _, stx := range block.STransactions() {
   842  		isVote := stake.IsSSGen(stx.MsgTx())
   843  		for txInIdx, txIn := range stx.MsgTx().TxIn {
   844  			// Ignore stakebase since it has no input.
   845  			if isVote && txInIdx == 0 {
   846  				continue
   847  			}
   848  
   849  			// Only request entries that are not already in the view
   850  			// from the database.
   851  			originHash := &txIn.PreviousOutPoint.Hash
   852  			filteredSet.add(view, originHash)
   853  		}
   854  	}
   855  
   856  	// Request the input utxos from the database.
   857  	return view.fetchUtxosMain(db, filteredSet)
   858  }
   859  
   860  // clone returns a deep copy of the view.
   861  func (view *UtxoViewpoint) clone() *UtxoViewpoint {
   862  	clonedView := &UtxoViewpoint{
   863  		entries:  make(map[chainhash.Hash]*UtxoEntry),
   864  		bestHash: view.bestHash,
   865  	}
   866  
   867  	for txHash, entry := range view.entries {
   868  		clonedView.entries[txHash] = entry.Clone()
   869  	}
   870  
   871  	return clonedView
   872  }
   873  
   874  // NewUtxoViewpoint returns a new empty unspent transaction output view.
   875  func NewUtxoViewpoint() *UtxoViewpoint {
   876  	return &UtxoViewpoint{
   877  		entries: make(map[chainhash.Hash]*UtxoEntry),
   878  	}
   879  }
   880  
   881  // FetchUtxoView loads utxo details about the input transactions referenced by
   882  // the passed transaction from the point of view of the end of the main chain
   883  // while taking into account whether or not the transactions in the regular tree
   884  // of the block just prior should be included or not depending on the provided
   885  // flag.  It also attempts to fetch the utxo details for the transaction itself
   886  // so the returned view can be examined for duplicate unspent transaction
   887  // outputs.
   888  //
   889  // This function is safe for concurrent access however the returned view is NOT.
   890  func (b *BlockChain) FetchUtxoView(tx *dcrutil.Tx, includePrevRegularTxns bool) (*UtxoViewpoint, error) {
   891  	b.chainLock.RLock()
   892  	defer b.chainLock.RUnlock()
   893  
   894  	// The genesis block does not have any spendable transactions, so there
   895  	// can't possibly be any details about it.  This is also necessary
   896  	// because the code below requires the parent block and the genesis
   897  	// block doesn't have one.
   898  	tip := b.bestChain.Tip()
   899  	view := NewUtxoViewpoint()
   900  	view.SetBestHash(&tip.hash)
   901  	if tip.height == 0 {
   902  		return view, nil
   903  	}
   904  
   905  	// Disconnect the transactions in the regular tree of the parent block if
   906  	// the caller requests it.  In order to avoid the overhead of repeated
   907  	// lookups, only create a view with the changes once and cache it.
   908  	if !includePrevRegularTxns {
   909  		b.disapprovedViewLock.Lock()
   910  		if b.disapprovedView == nil || *b.disapprovedView.BestHash() !=
   911  			tip.hash {
   912  
   913  			// Grab the parent of the current block.
   914  			parent, err := b.fetchMainChainBlockByNode(tip.parent)
   915  			if err != nil {
   916  				b.disapprovedViewLock.Unlock()
   917  				return nil, err
   918  			}
   919  
   920  			// Disconnect the transactions in the regular tree of the parent
   921  			// block.
   922  			err = view.disconnectDisapprovedBlock(b.db, parent)
   923  			if err != nil {
   924  				b.disapprovedViewLock.Unlock()
   925  				return nil, err
   926  			}
   927  
   928  			// Clone the view so the caller can safely mutate it.
   929  			b.disapprovedView = view.clone()
   930  		} else {
   931  			// Clone the view so the caller can safely mutate it.
   932  			view = b.disapprovedView.clone()
   933  		}
   934  		b.disapprovedViewLock.Unlock()
   935  	}
   936  
   937  	// Create a set of needed transactions based on those referenced by the
   938  	// inputs of the passed transaction.  Also, add the passed transaction
   939  	// itself as a way for the caller to detect duplicates that are not fully
   940  	// spent.
   941  	filteredSet := make(viewFilteredSet)
   942  	filteredSet.add(view, tx.Hash())
   943  	msgTx := tx.MsgTx()
   944  	if !standalone.IsCoinBaseTx(msgTx) {
   945  		isVote := stake.IsSSGen(msgTx)
   946  		for txInIdx, txIn := range msgTx.TxIn {
   947  			// Ignore stakebase since it has no input.
   948  			if isVote && txInIdx == 0 {
   949  				continue
   950  			}
   951  
   952  			filteredSet.add(view, &txIn.PreviousOutPoint.Hash)
   953  		}
   954  	}
   955  
   956  	err := view.fetchUtxosMain(b.db, filteredSet)
   957  	return view, err
   958  }
   959  
   960  // FetchUtxoEntry loads and returns the unspent transaction output entry for the
   961  // passed hash from the point of view of the end of the main chain.
   962  //
   963  // NOTE: Requesting a hash for which there is no data will NOT return an error.
   964  // Instead both the entry and the error will be nil.  This is done to allow
   965  // pruning of fully spent transactions.  In practice this means the caller must
   966  // check if the returned entry is nil before invoking methods on it.
   967  //
   968  // This function is safe for concurrent access however the returned entry (if
   969  // any) is NOT.
   970  func (b *BlockChain) FetchUtxoEntry(txHash *chainhash.Hash) (*UtxoEntry, error) {
   971  	b.chainLock.RLock()
   972  	defer b.chainLock.RUnlock()
   973  
   974  	var entry *UtxoEntry
   975  	err := b.db.View(func(dbTx database.Tx) error {
   976  		var err error
   977  		entry, err = dbFetchUtxoEntry(dbTx, txHash)
   978  		return err
   979  	})
   980  	if err != nil {
   981  		return nil, err
   982  	}
   983  
   984  	return entry, nil
   985  }