decred.org/dcrwallet/v3@v3.1.0/wallet/udb/txmined.go (about)

     1  // Copyright (c) 2013-2015 The btcsuite developers
     2  // Copyright (c) 2015-2021 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 udb
     7  
     8  import (
     9  	"bytes"
    10  	"crypto/rand"
    11  	"encoding/binary"
    12  	"fmt"
    13  	"math/bits"
    14  	"time"
    15  
    16  	"decred.org/dcrwallet/v3/errors"
    17  	"decred.org/dcrwallet/v3/internal/compat"
    18  	"decred.org/dcrwallet/v3/wallet/txauthor"
    19  	"decred.org/dcrwallet/v3/wallet/txrules"
    20  	"decred.org/dcrwallet/v3/wallet/txsizes"
    21  	"decred.org/dcrwallet/v3/wallet/walletdb"
    22  	"github.com/decred/dcrd/blockchain/stake/v5"
    23  	"github.com/decred/dcrd/chaincfg/chainhash"
    24  	"github.com/decred/dcrd/chaincfg/v3"
    25  	"github.com/decred/dcrd/crypto/ripemd160"
    26  	"github.com/decred/dcrd/dcrutil/v4"
    27  	gcs2 "github.com/decred/dcrd/gcs/v4"
    28  	"github.com/decred/dcrd/gcs/v4/blockcf2"
    29  	"github.com/decred/dcrd/txscript/v4"
    30  	"github.com/decred/dcrd/txscript/v4/stdaddr"
    31  	"github.com/decred/dcrd/txscript/v4/stdscript"
    32  	"github.com/decred/dcrd/wire"
    33  )
    34  
    35  const (
    36  	opNonstake = txscript.OP_NOP10
    37  
    38  	// The assumed output script version is defined to assist with refactoring
    39  	// to use actual script versions.
    40  	scriptVersionAssumed = 0
    41  )
    42  
    43  // Block contains the minimum amount of data to uniquely identify any block on
    44  // either the best or side chain.
    45  type Block struct {
    46  	Hash   chainhash.Hash
    47  	Height int32
    48  }
    49  
    50  // BlockMeta contains the unique identification for a block and any metadata
    51  // pertaining to the block.  At the moment, this additional metadata only
    52  // includes the block time from the block header.
    53  type BlockMeta struct {
    54  	Block
    55  	Time     time.Time
    56  	VoteBits uint16
    57  }
    58  
    59  // blockRecord is an in-memory representation of the block record saved in the
    60  // database.
    61  type blockRecord struct {
    62  	Block
    63  	Time         time.Time
    64  	VoteBits     uint16
    65  	transactions []chainhash.Hash
    66  }
    67  
    68  // incidence records the block hash and blockchain height of a mined transaction.
    69  // Since a transaction hash alone is not enough to uniquely identify a mined
    70  // transaction (duplicate transaction hashes are allowed), the incidence is used
    71  // instead.
    72  type incidence struct {
    73  	txHash chainhash.Hash
    74  	block  Block
    75  }
    76  
    77  // indexedIncidence records the transaction incidence and an input or output
    78  // index.
    79  type indexedIncidence struct {
    80  	incidence
    81  	index uint32
    82  }
    83  
    84  // credit describes a transaction output which was or is spendable by wallet.
    85  type credit struct {
    86  	outPoint   wire.OutPoint
    87  	block      Block
    88  	amount     dcrutil.Amount
    89  	change     bool
    90  	spentBy    indexedIncidence // Index == ^uint32(0) if unspent
    91  	opCode     uint8
    92  	isCoinbase bool
    93  	hasExpiry  bool
    94  }
    95  
    96  // TxRecord represents a transaction managed by the Store.
    97  type TxRecord struct {
    98  	MsgTx        wire.MsgTx
    99  	Hash         chainhash.Hash
   100  	Received     time.Time
   101  	SerializedTx []byte // Optional: may be nil
   102  	TxType       stake.TxType
   103  	Unpublished  bool
   104  }
   105  
   106  // NewTxRecord creates a new transaction record that may be inserted into the
   107  // store.  It uses memoization to save the transaction hash and the serialized
   108  // transaction.
   109  func NewTxRecord(serializedTx []byte, received time.Time) (*TxRecord, error) {
   110  	rec := &TxRecord{
   111  		Received:     received,
   112  		SerializedTx: serializedTx,
   113  	}
   114  	err := rec.MsgTx.Deserialize(bytes.NewReader(serializedTx))
   115  	if err != nil {
   116  		return nil, err
   117  	}
   118  	rec.TxType = stake.DetermineTxType(&rec.MsgTx)
   119  	hash := rec.MsgTx.TxHash()
   120  	copy(rec.Hash[:], hash[:])
   121  	return rec, nil
   122  }
   123  
   124  // NewTxRecordFromMsgTx creates a new transaction record that may be inserted
   125  // into the store.
   126  func NewTxRecordFromMsgTx(msgTx *wire.MsgTx, received time.Time) (*TxRecord, error) {
   127  	var buf bytes.Buffer
   128  	buf.Grow(msgTx.SerializeSize())
   129  	err := msgTx.Serialize(&buf)
   130  	if err != nil {
   131  		return nil, err
   132  	}
   133  	rec := &TxRecord{
   134  		MsgTx:        *msgTx,
   135  		Received:     received,
   136  		SerializedTx: buf.Bytes(),
   137  	}
   138  	rec.TxType = stake.DetermineTxType(&rec.MsgTx)
   139  	hash := rec.MsgTx.TxHash()
   140  	copy(rec.Hash[:], hash[:])
   141  	return rec, nil
   142  }
   143  
   144  // MultisigOut represents a spendable multisignature outpoint contain
   145  // a script hash.
   146  type MultisigOut struct {
   147  	OutPoint     *wire.OutPoint
   148  	Tree         int8
   149  	ScriptHash   [ripemd160.Size]byte
   150  	M            uint8
   151  	N            uint8
   152  	TxHash       chainhash.Hash
   153  	BlockHash    chainhash.Hash
   154  	BlockHeight  uint32
   155  	Amount       dcrutil.Amount
   156  	Spent        bool
   157  	SpentBy      chainhash.Hash
   158  	SpentByIndex uint32
   159  }
   160  
   161  // Credit is the type representing a transaction output which was spent or
   162  // is still spendable by wallet.  A UTXO is an unspent Credit, but not all
   163  // Credits are UTXOs.
   164  type Credit struct {
   165  	wire.OutPoint
   166  	BlockMeta
   167  	Amount       dcrutil.Amount
   168  	PkScript     []byte // TODO: script version
   169  	Received     time.Time
   170  	FromCoinBase bool
   171  	HasExpiry    bool
   172  }
   173  
   174  // Store implements a transaction store for storing and managing wallet
   175  // transactions.
   176  type Store struct {
   177  	chainParams    *chaincfg.Params
   178  	acctLookupFunc func(walletdb.ReadBucket, stdaddr.Address) (uint32, error)
   179  	manager        *Manager
   180  }
   181  
   182  // MainChainTip returns the hash and height of the currently marked tip-most
   183  // block of the main chain.
   184  func (s *Store) MainChainTip(dbtx walletdb.ReadTx) (chainhash.Hash, int32) {
   185  	ns := dbtx.ReadBucket(wtxmgrBucketKey)
   186  	var hash chainhash.Hash
   187  	tipHash := ns.Get(rootTipBlock)
   188  	copy(hash[:], tipHash)
   189  
   190  	header := ns.NestedReadBucket(bucketHeaders).Get(hash[:])
   191  	height := extractBlockHeaderHeight(header)
   192  
   193  	return hash, height
   194  }
   195  
   196  // ExtendMainChain inserts a block header and compact filter into the database.
   197  // It must connect to the existing tip block.
   198  //
   199  // If the block is already inserted and part of the main chain, an errors.Exist
   200  // error is returned.
   201  //
   202  // The main chain tip may not be extended unless compact filters have been saved
   203  // for all existing main chain blocks.
   204  func (s *Store) ExtendMainChain(ns walletdb.ReadWriteBucket, header *wire.BlockHeader, f *gcs2.FilterV2) error {
   205  	height := int32(header.Height)
   206  	if height < 1 {
   207  		return errors.E(errors.Invalid, "block 0 cannot be added")
   208  	}
   209  	v := ns.Get(rootHaveCFilters)
   210  	if len(v) != 1 || v[0] != 1 {
   211  		return errors.E(errors.Invalid, "main chain may not be extended without first saving all previous cfilters")
   212  	}
   213  
   214  	headerBucket := ns.NestedReadWriteBucket(bucketHeaders)
   215  
   216  	blockHash := header.BlockHash()
   217  
   218  	currentTipHash := ns.Get(rootTipBlock)
   219  	if !bytes.Equal(header.PrevBlock[:], currentTipHash) {
   220  		// Return a special error if it is a duplicate of an existing block in
   221  		// the main chain (NOT the headers bucket, since headers are never
   222  		// pruned).
   223  		_, v := existsBlockRecord(ns, height)
   224  		if v != nil && bytes.Equal(extractRawBlockRecordHash(v), blockHash[:]) {
   225  			return errors.E(errors.Exist, "block already recorded in main chain")
   226  		}
   227  		return errors.E(errors.Invalid, "not direct child of current tip")
   228  	}
   229  	// Also check that the height is one more than the current height
   230  	// recorded by the current tip.
   231  	currentTipHeader := headerBucket.Get(currentTipHash)
   232  	currentTipHeight := extractBlockHeaderHeight(currentTipHeader)
   233  	if currentTipHeight+1 != height {
   234  		return errors.E(errors.Invalid, "invalid height for next block")
   235  	}
   236  
   237  	var err error
   238  	if approvesParent(header.VoteBits) {
   239  		err = stakeValidate(ns, currentTipHeight)
   240  	} else {
   241  		err = stakeInvalidate(ns, currentTipHeight)
   242  	}
   243  	if err != nil {
   244  		return err
   245  	}
   246  
   247  	// Add the header
   248  	var headerBuffer bytes.Buffer
   249  	err = header.Serialize(&headerBuffer)
   250  	if err != nil {
   251  		return err
   252  	}
   253  	err = headerBucket.Put(blockHash[:], headerBuffer.Bytes())
   254  	if err != nil {
   255  		return errors.E(errors.IO, err)
   256  	}
   257  
   258  	// Update the tip block
   259  	err = ns.Put(rootTipBlock, blockHash[:])
   260  	if err != nil {
   261  		return errors.E(errors.IO, err)
   262  	}
   263  
   264  	// Add an empty block record
   265  	blockKey := keyBlockRecord(height)
   266  	blockVal := valueBlockRecordEmptyFromHeader(blockHash[:], headerBuffer.Bytes())
   267  	err = putRawBlockRecord(ns, blockKey, blockVal)
   268  	if err != nil {
   269  		return err
   270  	}
   271  
   272  	// Save the compact filter.
   273  	bcf2Key := blockcf2.Key(&header.MerkleRoot)
   274  	return putRawCFilter(ns, blockHash[:], valueRawCFilter2(bcf2Key, f.Bytes()))
   275  }
   276  
   277  // ProcessedTxsBlockMarker returns the hash of the block which records the last
   278  // block after the genesis block which has been recorded as being processed for
   279  // relevant transactions.
   280  func (s *Store) ProcessedTxsBlockMarker(dbtx walletdb.ReadTx) *chainhash.Hash {
   281  	ns := dbtx.ReadBucket(wtxmgrBucketKey)
   282  	var h chainhash.Hash
   283  	copy(h[:], ns.Get(rootLastTxsBlock))
   284  	return &h
   285  }
   286  
   287  // UpdateProcessedTxsBlockMarker updates the hash of the block recording the
   288  // final block since the genesis block for which all transactions have been
   289  // processed.  Hash must describe a main chain block.  This does not modify the
   290  // database if hash has a lower block height than the main chain fork point of
   291  // the existing marker.
   292  func (s *Store) UpdateProcessedTxsBlockMarker(dbtx walletdb.ReadWriteTx, hash *chainhash.Hash) error {
   293  	ns := dbtx.ReadWriteBucket(wtxmgrBucketKey)
   294  	prev := s.ProcessedTxsBlockMarker(dbtx)
   295  	for {
   296  		mainChain, _ := s.BlockInMainChain(dbtx, prev)
   297  		if mainChain {
   298  			break
   299  		}
   300  		h, err := s.GetBlockHeader(dbtx, prev)
   301  		if err != nil {
   302  			return err
   303  		}
   304  		prev = &h.PrevBlock
   305  	}
   306  	prevHeader, err := s.GetBlockHeader(dbtx, prev)
   307  	if err != nil {
   308  		return err
   309  	}
   310  	if mainChain, _ := s.BlockInMainChain(dbtx, hash); !mainChain {
   311  		return errors.E(errors.Invalid, errors.Errorf("%v is not a main chain block", hash))
   312  	}
   313  	header, err := s.GetBlockHeader(dbtx, hash)
   314  	if err != nil {
   315  		return err
   316  	}
   317  	if header.Height > prevHeader.Height {
   318  		err := ns.Put(rootLastTxsBlock, hash[:])
   319  		if err != nil {
   320  			return errors.E(errors.IO, err)
   321  		}
   322  	}
   323  	return nil
   324  }
   325  
   326  // IsMissingMainChainCFilters returns whether all compact filters for main chain
   327  // blocks have been recorded to the database after the upgrade which began to
   328  // require them to extend the main chain.  If compact filters are missing, they
   329  // must be added using InsertMissingCFilters.
   330  func (s *Store) IsMissingMainChainCFilters(dbtx walletdb.ReadTx) bool {
   331  	v := dbtx.ReadBucket(wtxmgrBucketKey).Get(rootHaveCFilters)
   332  	return len(v) != 1 || v[0] == 0
   333  }
   334  
   335  // MissingCFiltersHeight returns the first main chain block height
   336  // with a missing cfilter.  Errors with NotExist when all main chain
   337  // blocks record cfilters.
   338  func (s *Store) MissingCFiltersHeight(dbtx walletdb.ReadTx) (int32, error) {
   339  	ns := dbtx.ReadBucket(wtxmgrBucketKey)
   340  	c := ns.NestedReadBucket(bucketBlocks).ReadCursor()
   341  	defer c.Close()
   342  	for k, v := c.First(); k != nil; k, v = c.Next() {
   343  		hash := extractRawBlockRecordHash(v)
   344  		_, _, err := fetchRawCFilter2(ns, hash)
   345  		if errors.Is(err, errors.NotExist) {
   346  			height := int32(byteOrder.Uint32(k))
   347  			return height, nil
   348  		}
   349  	}
   350  	return 0, errors.E(errors.NotExist)
   351  }
   352  
   353  // InsertMissingCFilters records compact filters for each main chain block
   354  // specified by blockHashes.  This is used to add the additional required
   355  // cfilters after upgrading a database to version TODO as recording cfilters
   356  // becomes a required part of extending the main chain.  This method may be
   357  // called incrementally to record all main chain block cfilters.  When all
   358  // cfilters of the main chain are recorded, extending the main chain becomes
   359  // possible again.
   360  func (s *Store) InsertMissingCFilters(dbtx walletdb.ReadWriteTx, blockHashes []*chainhash.Hash, filters []*gcs2.FilterV2) error {
   361  	ns := dbtx.ReadWriteBucket(wtxmgrBucketKey)
   362  	v := ns.Get(rootHaveCFilters)
   363  	if len(v) == 1 && v[0] != 0 {
   364  		return errors.E(errors.Invalid, "all cfilters for main chain blocks are already recorded")
   365  	}
   366  
   367  	if len(blockHashes) != len(filters) {
   368  		return errors.E(errors.Invalid, "slices must have equal len")
   369  	}
   370  	if len(blockHashes) == 0 {
   371  		return nil
   372  	}
   373  
   374  	for i, blockHash := range blockHashes {
   375  		// Ensure that blockHashes are ordered and that all previous cfilters in the
   376  		// main chain are known.
   377  		ok := i == 0 && *blockHash == s.chainParams.GenesisHash
   378  		var bcf2Key [gcs2.KeySize]byte
   379  		if !ok {
   380  			header := existsBlockHeader(ns, blockHash[:])
   381  			if header == nil {
   382  				return errors.E(errors.NotExist, errors.Errorf("missing header for block %v", blockHash))
   383  			}
   384  			parentHash := extractBlockHeaderParentHash(header)
   385  			merkleRoot := extractBlockHeaderMerkleRoot(header)
   386  			merkleRootHash, err := chainhash.NewHash(merkleRoot)
   387  			if err != nil {
   388  				return errors.E(errors.Invalid, errors.Errorf("invalid stored header %v", blockHash))
   389  			}
   390  			bcf2Key = blockcf2.Key(merkleRootHash)
   391  			if i == 0 {
   392  				_, _, err := fetchRawCFilter2(ns, parentHash)
   393  				ok = err == nil
   394  			} else {
   395  				ok = bytes.Equal(parentHash, blockHashes[i-1][:])
   396  			}
   397  		}
   398  		if !ok {
   399  			return errors.E(errors.Invalid, "block hashes are not ordered or previous cfilters are missing")
   400  		}
   401  
   402  		// Record cfilter for this block
   403  		err := putRawCFilter(ns, blockHash[:], valueRawCFilter2(bcf2Key, filters[i].Bytes()))
   404  		if err != nil {
   405  			return err
   406  		}
   407  	}
   408  
   409  	// Mark all main chain cfilters as saved if the last block hash is the main
   410  	// chain tip.
   411  	tip, _ := s.MainChainTip(dbtx)
   412  	if bytes.Equal(tip[:], blockHashes[len(blockHashes)-1][:]) {
   413  		err := ns.Put(rootHaveCFilters, []byte{1})
   414  		if err != nil {
   415  			return errors.E(errors.IO, err)
   416  		}
   417  	}
   418  
   419  	return nil
   420  }
   421  
   422  // BlockCFilter is a compact filter for a Decred block.
   423  type BlockCFilter struct {
   424  	BlockHash chainhash.Hash
   425  	FilterV2  *gcs2.FilterV2
   426  	Key       [gcs2.KeySize]byte
   427  }
   428  
   429  // GetMainChainCFilters returns compact filters from the main chain, starting at
   430  // startHash, copying as many as possible into the storage slice and returning a
   431  // subslice for the total number of results.  If the start hash is not in the
   432  // main chain, this function errors.  If inclusive is true, the startHash is
   433  // included in the results, otherwise only blocks after the startHash are
   434  // included.
   435  func (s *Store) GetMainChainCFilters(dbtx walletdb.ReadTx, startHash *chainhash.Hash, inclusive bool, storage []*BlockCFilter) ([]*BlockCFilter, error) {
   436  	ns := dbtx.ReadBucket(wtxmgrBucketKey)
   437  	header := ns.NestedReadBucket(bucketHeaders).Get(startHash[:])
   438  	if header == nil {
   439  		return nil, errors.E(errors.NotExist, errors.Errorf("starting block %v not found", startHash))
   440  	}
   441  	height := extractBlockHeaderHeight(header)
   442  	if !inclusive {
   443  		height++
   444  	}
   445  
   446  	blockRecords := ns.NestedReadBucket(bucketBlocks)
   447  
   448  	storageUsed := 0
   449  	for storageUsed < len(storage) {
   450  		v := blockRecords.Get(keyBlockRecord(height))
   451  		if v == nil {
   452  			break
   453  		}
   454  		blockHash := extractRawBlockRecordHash(v)
   455  		bcf2Key, rawFilter, err := fetchRawCFilter2(ns, blockHash)
   456  		if err != nil {
   457  			return nil, err
   458  		}
   459  		fCopy := make([]byte, len(rawFilter))
   460  		copy(fCopy, rawFilter)
   461  		f, err := gcs2.FromBytesV2(blockcf2.B, blockcf2.M, fCopy)
   462  		if err != nil {
   463  			return nil, err
   464  		}
   465  		bf := &BlockCFilter{FilterV2: f, Key: bcf2Key}
   466  		copy(bf.BlockHash[:], blockHash)
   467  		storage[storageUsed] = bf
   468  
   469  		height++
   470  		storageUsed++
   471  	}
   472  	return storage[:storageUsed], nil
   473  }
   474  
   475  func extractBlockHeaderParentHash(header []byte) []byte {
   476  	const parentOffset = 4
   477  	return header[parentOffset : parentOffset+chainhash.HashSize]
   478  }
   479  
   480  func extractBlockHeaderMerkleRoot(header []byte) []byte {
   481  	const merkleRootOffset = 36
   482  	return header[merkleRootOffset : merkleRootOffset+chainhash.HashSize]
   483  }
   484  
   485  // ExtractBlockHeaderParentHash subslices the header to return the bytes of the
   486  // parent block's hash.  Must only be called on known good input.
   487  //
   488  // TODO: This really should not be exported by this package.
   489  func ExtractBlockHeaderParentHash(header []byte) []byte {
   490  	return extractBlockHeaderParentHash(header)
   491  }
   492  
   493  func extractBlockHeaderVoteBits(header []byte) uint16 {
   494  	const voteBitsOffset = 100
   495  	return binary.LittleEndian.Uint16(header[voteBitsOffset:])
   496  }
   497  
   498  func extractBlockHeaderHeight(header []byte) int32 {
   499  	const heightOffset = 128
   500  	return int32(binary.LittleEndian.Uint32(header[heightOffset:]))
   501  }
   502  
   503  // ExtractBlockHeaderHeight returns the height field that is encoded in the
   504  // header.  Must only be called on known good input.
   505  //
   506  // TODO: This really should not be exported by this package.
   507  func ExtractBlockHeaderHeight(header []byte) int32 {
   508  	return extractBlockHeaderHeight(header)
   509  }
   510  
   511  func extractBlockHeaderUnixTime(header []byte) uint32 {
   512  	const timestampOffset = 136
   513  	return binary.LittleEndian.Uint32(header[timestampOffset:])
   514  }
   515  
   516  // ExtractBlockHeaderTime returns the unix timestamp that is encoded in the
   517  // header.  Must only be called on known good input.  Header timestamps are only
   518  // 4 bytes and this value is actually limited to a maximum unix time of 2^32-1.
   519  //
   520  // TODO: This really should not be exported by this package.
   521  func ExtractBlockHeaderTime(header []byte) int64 {
   522  	return int64(extractBlockHeaderUnixTime(header))
   523  }
   524  
   525  func blockMetaFromHeader(blockHash *chainhash.Hash, header []byte) BlockMeta {
   526  	return BlockMeta{
   527  		Block: Block{
   528  			Hash:   *blockHash,
   529  			Height: extractBlockHeaderHeight(header),
   530  		},
   531  		Time:     time.Unix(int64(extractBlockHeaderUnixTime(header)), 0),
   532  		VoteBits: extractBlockHeaderVoteBits(header),
   533  	}
   534  }
   535  
   536  // RawBlockHeader is a 180 byte block header (always true for version 0 blocks).
   537  type RawBlockHeader [180]byte
   538  
   539  // Height extracts the height encoded in a block header.
   540  func (h *RawBlockHeader) Height() int32 {
   541  	return extractBlockHeaderHeight(h[:])
   542  }
   543  
   544  // BlockHeaderData contains the block hashes and serialized blocks headers that
   545  // are inserted into the database.  At time of writing this only supports wire
   546  // protocol version 0 blocks and changes will need to be made if the block
   547  // header size changes.
   548  type BlockHeaderData struct {
   549  	BlockHash        chainhash.Hash
   550  	SerializedHeader RawBlockHeader
   551  }
   552  
   553  // stakeValidate validates regular tree transactions from the main chain block
   554  // at some height.  This does not perform any changes when the block is not
   555  // marked invalid.  When currently invalidated, the invalidated byte is set to 0
   556  // to mark the block as stake validated and the mined balance is incremented for
   557  // all credits of this block.
   558  //
   559  // Stake validation or invalidation should only occur for the block at height
   560  // tip-1.
   561  func stakeValidate(ns walletdb.ReadWriteBucket, height int32) error {
   562  	k, v := existsBlockRecord(ns, height)
   563  	if v == nil {
   564  		return errors.E(errors.IO, errors.Errorf("missing block record for height %v", height))
   565  	}
   566  	if !extractRawBlockRecordStakeInvalid(v) {
   567  		return nil
   568  	}
   569  
   570  	minedBalance, err := fetchMinedBalance(ns)
   571  	if err != nil {
   572  		return err
   573  	}
   574  
   575  	var blockRec blockRecord
   576  	err = readRawBlockRecord(k, v, &blockRec)
   577  	if err != nil {
   578  		return err
   579  	}
   580  
   581  	// Rewrite the block record, marking the regular tree as stake validated.
   582  	err = putRawBlockRecord(ns, k, valueBlockRecordStakeValidated(v))
   583  	if err != nil {
   584  		return err
   585  	}
   586  
   587  	for i := range blockRec.transactions {
   588  		txHash := &blockRec.transactions[i]
   589  
   590  		_, txv := existsTxRecord(ns, txHash, &blockRec.Block)
   591  		if txv == nil {
   592  			return errors.E(errors.IO, errors.Errorf("missing transaction record for tx %v block %v",
   593  				txHash, &blockRec.Block.Hash))
   594  		}
   595  		var txRec TxRecord
   596  		err = readRawTxRecord(txHash, txv, &txRec)
   597  		if err != nil {
   598  			return err
   599  		}
   600  
   601  		// Only regular tree transactions must be considered.
   602  		if txRec.TxType != stake.TxTypeRegular {
   603  			continue
   604  		}
   605  
   606  		// Move all credits from this tx to the non-invalidated credits bucket.
   607  		// Add an unspent output for each validated credit.
   608  		// The mined balance is incremented for all moved credit outputs.
   609  		creditOutPoint := wire.OutPoint{Hash: txRec.Hash} // Index set in loop
   610  		for i, output := range txRec.MsgTx.TxOut {
   611  			k, v := existsInvalidatedCredit(ns, &txRec.Hash, uint32(i), &blockRec.Block)
   612  			if v == nil {
   613  				continue
   614  			}
   615  
   616  			err = ns.NestedReadWriteBucket(bucketStakeInvalidatedCredits).
   617  				Delete(k)
   618  			if err != nil {
   619  				return errors.E(errors.IO, err)
   620  			}
   621  			err = putRawCredit(ns, k, v)
   622  			if err != nil {
   623  				return err
   624  			}
   625  
   626  			creditOutPoint.Index = uint32(i)
   627  			err = putUnspent(ns, &creditOutPoint, &blockRec.Block)
   628  			if err != nil {
   629  				return err
   630  			}
   631  
   632  			minedBalance += dcrutil.Amount(output.Value)
   633  		}
   634  
   635  		// Move all debits from this tx to the non-invalidated debits bucket,
   636  		// and spend any previous credits spent by the stake validated tx.
   637  		// Remove utxos for all spent previous credits.  The mined balance is
   638  		// decremented for all previous credits that are no longer spendable.
   639  		debitIncidence := indexedIncidence{
   640  			incidence: incidence{txHash: txRec.Hash, block: blockRec.Block},
   641  			// index set for each rec input below.
   642  		}
   643  		for i := range txRec.MsgTx.TxIn {
   644  			debKey, credKey, err := existsInvalidatedDebit(ns, &txRec.Hash, uint32(i),
   645  				&blockRec.Block)
   646  			if err != nil {
   647  				return err
   648  			}
   649  			if debKey == nil {
   650  				continue
   651  			}
   652  			debitIncidence.index = uint32(i)
   653  
   654  			debVal := ns.NestedReadBucket(bucketStakeInvalidatedDebits).
   655  				Get(debKey)
   656  			debitAmount := extractRawDebitAmount(debVal)
   657  
   658  			_, err = spendCredit(ns, credKey, &debitIncidence)
   659  			if err != nil {
   660  				return err
   661  			}
   662  
   663  			prevOut := &txRec.MsgTx.TxIn[i].PreviousOutPoint
   664  			unspentKey := canonicalOutPoint(&prevOut.Hash, prevOut.Index)
   665  			err = deleteRawUnspent(ns, unspentKey)
   666  			if err != nil {
   667  				return err
   668  			}
   669  
   670  			err = ns.NestedReadWriteBucket(bucketStakeInvalidatedDebits).
   671  				Delete(debKey)
   672  			if err != nil {
   673  				return errors.E(errors.IO, err)
   674  			}
   675  			err = putRawDebit(ns, debKey, debVal)
   676  			if err != nil {
   677  				return err
   678  			}
   679  
   680  			minedBalance -= debitAmount
   681  		}
   682  	}
   683  
   684  	return putMinedBalance(ns, minedBalance)
   685  }
   686  
   687  // stakeInvalidate invalidates regular tree transactions from the main chain
   688  // block at some height.  This does not perform any changes when the block is
   689  // not marked invalid.  When not marked invalid, the invalidated byte is set to
   690  // 1 to mark the block as stake invalidated and the mined balance is decremented
   691  // for all credits.
   692  //
   693  // Stake validation or invalidation should only occur for the block at height
   694  // tip-1.
   695  //
   696  // See stakeValidate (which performs the reverse operation) for more details.
   697  func stakeInvalidate(ns walletdb.ReadWriteBucket, height int32) error {
   698  	k, v := existsBlockRecord(ns, height)
   699  	if v == nil {
   700  		return errors.E(errors.IO, errors.Errorf("missing block record for height %v", height))
   701  	}
   702  	if extractRawBlockRecordStakeInvalid(v) {
   703  		return nil
   704  	}
   705  
   706  	minedBalance, err := fetchMinedBalance(ns)
   707  	if err != nil {
   708  		return err
   709  	}
   710  
   711  	var blockRec blockRecord
   712  	err = readRawBlockRecord(k, v, &blockRec)
   713  	if err != nil {
   714  		return err
   715  	}
   716  
   717  	// Rewrite the block record, marking the regular tree as stake invalidated.
   718  	err = putRawBlockRecord(ns, k, valueBlockRecordStakeInvalidated(v))
   719  	if err != nil {
   720  		return err
   721  	}
   722  
   723  	for i := range blockRec.transactions {
   724  		txHash := &blockRec.transactions[i]
   725  
   726  		_, txv := existsTxRecord(ns, txHash, &blockRec.Block)
   727  		if txv == nil {
   728  			return errors.E(errors.IO, errors.Errorf("missing transaction record for tx %v block %v",
   729  				txHash, &blockRec.Block.Hash))
   730  		}
   731  		var txRec TxRecord
   732  		err = readRawTxRecord(txHash, txv, &txRec)
   733  		if err != nil {
   734  			return err
   735  		}
   736  
   737  		// Only regular tree transactions must be considered.
   738  		if txRec.TxType != stake.TxTypeRegular {
   739  			continue
   740  		}
   741  
   742  		// Move all credits from this tx to the invalidated credits bucket.
   743  		// Remove the unspent output for each invalidated credit.
   744  		// The mined balance is decremented for all moved credit outputs.
   745  		for i, output := range txRec.MsgTx.TxOut {
   746  			k, v := existsCredit(ns, &txRec.Hash, uint32(i), &blockRec.Block)
   747  			if v == nil {
   748  				continue
   749  			}
   750  
   751  			err = deleteRawCredit(ns, k)
   752  			if err != nil {
   753  				return err
   754  			}
   755  			err = ns.NestedReadWriteBucket(bucketStakeInvalidatedCredits).
   756  				Put(k, v)
   757  			if err != nil {
   758  				return errors.E(errors.IO, err)
   759  			}
   760  
   761  			unspentKey := canonicalOutPoint(txHash, uint32(i))
   762  			err = deleteRawUnspent(ns, unspentKey)
   763  			if err != nil {
   764  				return err
   765  			}
   766  
   767  			minedBalance -= dcrutil.Amount(output.Value)
   768  		}
   769  
   770  		// Move all debits from this tx to the invalidated debits bucket, and
   771  		// unspend any credit spents by the stake invalidated tx.  The mined
   772  		// balance is incremented for all previous credits that are spendable
   773  		// again.
   774  		for i := range txRec.MsgTx.TxIn {
   775  			debKey, credKey, err := existsDebit(ns, &txRec.Hash, uint32(i),
   776  				&blockRec.Block)
   777  			if err != nil {
   778  				return err
   779  			}
   780  			if debKey == nil {
   781  				continue
   782  			}
   783  
   784  			debVal := ns.NestedReadBucket(bucketDebits).Get(debKey)
   785  			debitAmount := extractRawDebitAmount(debVal)
   786  
   787  			_, err = unspendRawCredit(ns, credKey)
   788  			if err != nil {
   789  				return err
   790  			}
   791  
   792  			err = deleteRawDebit(ns, debKey)
   793  			if err != nil {
   794  				return err
   795  			}
   796  			err = ns.NestedReadWriteBucket(bucketStakeInvalidatedDebits).
   797  				Put(debKey, debVal)
   798  			if err != nil {
   799  				return errors.E(errors.IO, err)
   800  			}
   801  
   802  			prevOut := &txRec.MsgTx.TxIn[i].PreviousOutPoint
   803  			unspentKey := canonicalOutPoint(&prevOut.Hash, prevOut.Index)
   804  			unspentVal := extractRawDebitUnspentValue(debVal)
   805  			err = putRawUnspent(ns, unspentKey, unspentVal)
   806  			if err != nil {
   807  				return err
   808  			}
   809  
   810  			minedBalance += debitAmount
   811  		}
   812  	}
   813  
   814  	return putMinedBalance(ns, minedBalance)
   815  }
   816  
   817  // GetMainChainBlockHashForHeight returns the block hash of the block on the
   818  // main chain at a given height.
   819  func (s *Store) GetMainChainBlockHashForHeight(ns walletdb.ReadBucket, height int32) (chainhash.Hash, error) {
   820  	_, v := existsBlockRecord(ns, height)
   821  	if v == nil {
   822  		err := errors.E(errors.NotExist, errors.Errorf("no block at height %v in main chain", height))
   823  		return chainhash.Hash{}, err
   824  	}
   825  	var hash chainhash.Hash
   826  	copy(hash[:], extractRawBlockRecordHash(v))
   827  	return hash, nil
   828  }
   829  
   830  // GetSerializedBlockHeader returns the bytes of the serialized header for the
   831  // block specified by its hash.  These bytes are a copy of the value returned
   832  // from the DB and are usable outside of the transaction.
   833  func (s *Store) GetSerializedBlockHeader(ns walletdb.ReadBucket, blockHash *chainhash.Hash) ([]byte, error) {
   834  	return fetchRawBlockHeader(ns, keyBlockHeader(blockHash))
   835  }
   836  
   837  // GetBlockHeader returns the block header for the block specified by its hash.
   838  func (s *Store) GetBlockHeader(dbtx walletdb.ReadTx, blockHash *chainhash.Hash) (*wire.BlockHeader, error) {
   839  	ns := dbtx.ReadBucket(wtxmgrBucketKey)
   840  	serialized, err := fetchRawBlockHeader(ns, keyBlockHeader(blockHash))
   841  	if err != nil {
   842  		return nil, err
   843  	}
   844  	header := new(wire.BlockHeader)
   845  	err = header.Deserialize(bytes.NewReader(serialized))
   846  	if err != nil {
   847  		return nil, errors.E(errors.IO, err)
   848  	}
   849  	return header, nil
   850  }
   851  
   852  // BlockInMainChain returns whether a block identified by its hash is in the
   853  // current main chain and if so, whether it has been stake invalidated by the
   854  // next main chain block.
   855  func (s *Store) BlockInMainChain(dbtx walletdb.ReadTx, blockHash *chainhash.Hash) (inMainChain bool, invalidated bool) {
   856  	ns := dbtx.ReadBucket(wtxmgrBucketKey)
   857  	header := existsBlockHeader(ns, keyBlockHeader(blockHash))
   858  	if header == nil {
   859  		return false, false
   860  	}
   861  
   862  	_, v := existsBlockRecord(ns, extractBlockHeaderHeight(header))
   863  	if v == nil {
   864  		return false, false
   865  	}
   866  	if !bytes.Equal(extractRawBlockRecordHash(v), blockHash[:]) {
   867  		return false, false
   868  	}
   869  	return true, extractRawBlockRecordStakeInvalid(v)
   870  }
   871  
   872  // GetBlockMetaForHash returns the BlockMeta for a block specified by its hash.
   873  //
   874  // TODO: This is legacy code now that headers are saved.  BlockMeta can be removed.
   875  func (s *Store) GetBlockMetaForHash(ns walletdb.ReadBucket, blockHash *chainhash.Hash) (BlockMeta, error) {
   876  	header := ns.NestedReadBucket(bucketHeaders).Get(blockHash[:])
   877  	if header == nil {
   878  		err := errors.E(errors.NotExist, errors.Errorf("block %v header not found", blockHash))
   879  		return BlockMeta{}, err
   880  	}
   881  	return BlockMeta{
   882  		Block: Block{
   883  			Hash:   *blockHash,
   884  			Height: extractBlockHeaderHeight(header),
   885  		},
   886  		Time:     time.Unix(int64(extractBlockHeaderUnixTime(header)), 0),
   887  		VoteBits: extractBlockHeaderVoteBits(header),
   888  	}, nil
   889  }
   890  
   891  // GetMainChainBlockHashes returns block hashes from the main chain, starting at
   892  // startHash, copying as many as possible into the storage slice and returning a
   893  // subslice for the total number of results.  If the start hash is not in the
   894  // main chain, this function errors.  If inclusive is true, the startHash is
   895  // included in the results, otherwise only blocks after the startHash are
   896  // included.
   897  func (s *Store) GetMainChainBlockHashes(ns walletdb.ReadBucket, startHash *chainhash.Hash,
   898  	inclusive bool, storage []chainhash.Hash) ([]chainhash.Hash, error) {
   899  
   900  	header := ns.NestedReadBucket(bucketHeaders).Get(startHash[:])
   901  	if header == nil {
   902  		return nil, errors.E(errors.NotExist, errors.Errorf("starting block %v not found", startHash))
   903  	}
   904  	height := extractBlockHeaderHeight(header)
   905  
   906  	// Check that the hash of the recorded main chain block at height is equal
   907  	// to startHash.
   908  	blockRecords := ns.NestedReadBucket(bucketBlocks)
   909  	blockVal := blockRecords.Get(keyBlockRecord(height))
   910  	if !bytes.Equal(extractRawBlockRecordHash(blockVal), startHash[:]) {
   911  		return nil, errors.E(errors.Invalid, errors.Errorf("block %v not in main chain", startHash))
   912  	}
   913  
   914  	if !inclusive {
   915  		height++
   916  	}
   917  
   918  	i := 0
   919  	for i < len(storage) {
   920  		v := blockRecords.Get(keyBlockRecord(height))
   921  		if v == nil {
   922  			break
   923  		}
   924  		copy(storage[i][:], extractRawBlockRecordHash(v))
   925  		height++
   926  		i++
   927  	}
   928  	return storage[:i], nil
   929  }
   930  
   931  // fetchAccountForPkScript fetches an account for a given pkScript given a
   932  // credit value, the script, and an account lookup function. It does this
   933  // to maintain compatibility with older versions of the database.
   934  func (s *Store) fetchAccountForPkScript(addrmgrNs walletdb.ReadBucket,
   935  	credVal []byte, unminedCredVal []byte, pkScript []byte) (uint32, error) {
   936  
   937  	// Attempt to get the account from the mined credit. If the account was
   938  	// never stored, we can ignore the error and fall through to do the lookup
   939  	// with the acctLookupFunc.
   940  	//
   941  	// TODO: upgrade the database to actually store the account for every credit
   942  	// to avoid this nonsensical error handling.  The upgrade was not done
   943  	// correctly in the past and only began recording accounts for newly
   944  	// inserted credits without modifying existing ones.
   945  	if credVal != nil {
   946  		acct, err := fetchRawCreditAccount(credVal)
   947  		if err == nil {
   948  			return acct, nil
   949  		}
   950  	}
   951  	if unminedCredVal != nil {
   952  		acct, err := fetchRawUnminedCreditAccount(unminedCredVal)
   953  		if err == nil {
   954  			return acct, nil
   955  		}
   956  	}
   957  
   958  	// Neither credVal or unminedCredVal were passed, or if they were, they
   959  	// didn't have the account set. Figure out the account from the pkScript the
   960  	// expensive way.
   961  	_, addrs := stdscript.ExtractAddrs(scriptVersionAssumed, pkScript, s.chainParams)
   962  	if len(addrs) == 0 {
   963  		return 0, errors.New("no addresses decoded from pkScript")
   964  	}
   965  
   966  	// Only look at the first address returned. This does not handle
   967  	// multisignature or other custom pkScripts in the correct way, which
   968  	// requires multiple account tracking.
   969  	return s.acctLookupFunc(addrmgrNs, addrs[0])
   970  }
   971  
   972  // moveMinedTx moves a transaction record from the unmined buckets to block
   973  // buckets.
   974  func (s *Store) moveMinedTx(ns walletdb.ReadWriteBucket, addrmgrNs walletdb.ReadBucket, rec *TxRecord, recKey, recVal []byte, block *BlockMeta) error {
   975  	log.Debugf("Marking unconfirmed transaction %v mined in block %d",
   976  		&rec.Hash, block.Height)
   977  
   978  	// Add transaction to block record.
   979  	blockKey, blockVal := existsBlockRecord(ns, block.Height)
   980  	blockVal, err := appendRawBlockRecord(blockVal, &rec.Hash)
   981  	if err != nil {
   982  		return err
   983  	}
   984  	err = putRawBlockRecord(ns, blockKey, blockVal)
   985  	if err != nil {
   986  		return err
   987  	}
   988  
   989  	err = putRawTxRecord(ns, recKey, recVal)
   990  	if err != nil {
   991  		return err
   992  	}
   993  	minedBalance, err := fetchMinedBalance(ns)
   994  	if err != nil {
   995  		return err
   996  	}
   997  
   998  	// For all transaction inputs, remove the previous output marker from the
   999  	// unmined inputs bucket.  For any mined transactions with unspent credits
  1000  	// spent by this transaction, mark each spent, remove from the unspents map,
  1001  	// and insert a debit record for the spent credit.
  1002  	debitIncidence := indexedIncidence{
  1003  		incidence: incidence{txHash: rec.Hash, block: block.Block},
  1004  		// index set for each rec input below.
  1005  	}
  1006  	for i, input := range rec.MsgTx.TxIn {
  1007  		unspentKey, credKey := existsUnspent(ns, &input.PreviousOutPoint)
  1008  
  1009  		err = deleteRawUnminedInput(ns, unspentKey)
  1010  		if err != nil {
  1011  			return err
  1012  		}
  1013  
  1014  		if credKey == nil {
  1015  			continue
  1016  		}
  1017  
  1018  		debitIncidence.index = uint32(i)
  1019  		amt, err := spendCredit(ns, credKey, &debitIncidence)
  1020  		if err != nil {
  1021  			return err
  1022  		}
  1023  
  1024  		credVal := existsRawCredit(ns, credKey)
  1025  		if credVal == nil {
  1026  			return errors.E(errors.IO, errors.Errorf("missing credit "+
  1027  				"%v, key %x, spent by %v", &input.PreviousOutPoint, credKey, &rec.Hash))
  1028  		}
  1029  		creditOpCode := fetchRawCreditTagOpCode(credVal)
  1030  
  1031  		// Do not decrement ticket amounts.
  1032  		if !(creditOpCode == txscript.OP_SSTX) {
  1033  			minedBalance -= amt
  1034  		}
  1035  		err = deleteRawUnspent(ns, unspentKey)
  1036  		if err != nil {
  1037  			return err
  1038  		}
  1039  
  1040  		err = putDebit(ns, &rec.Hash, uint32(i), amt, &block.Block, credKey)
  1041  		if err != nil {
  1042  			return err
  1043  		}
  1044  	}
  1045  
  1046  	// For each output of the record that is marked as a credit, if the
  1047  	// output is marked as a credit by the unconfirmed store, remove the
  1048  	// marker and mark the output as a mined credit in the db.
  1049  	//
  1050  	// Moved credits are added as unspents, even if there is another
  1051  	// unconfirmed transaction which spends them.
  1052  	cred := credit{
  1053  		outPoint: wire.OutPoint{Hash: rec.Hash},
  1054  		block:    block.Block,
  1055  		spentBy:  indexedIncidence{index: ^uint32(0)},
  1056  	}
  1057  	for i := uint32(0); i < uint32(len(rec.MsgTx.TxOut)); i++ {
  1058  		k := canonicalOutPoint(&rec.Hash, i)
  1059  		v := existsRawUnminedCredit(ns, k)
  1060  		if v == nil {
  1061  			continue
  1062  		}
  1063  
  1064  		// TODO: This should use the raw apis.  The credit value (it.cv)
  1065  		// can be moved from unmined directly to the credits bucket.
  1066  		// The key needs a modification to include the block
  1067  		// height/hash.
  1068  		amount, change, err := fetchRawUnminedCreditAmountChange(v)
  1069  		if err != nil {
  1070  			return err
  1071  		}
  1072  		cred.outPoint.Index = i
  1073  		cred.amount = amount
  1074  		cred.change = change
  1075  		cred.opCode = fetchRawUnminedCreditTagOpCode(v)
  1076  		cred.isCoinbase = fetchRawUnminedCreditTagIsCoinbase(v)
  1077  
  1078  		// Legacy credit output values may be of the wrong
  1079  		// size.
  1080  		scrType := fetchRawUnminedCreditScriptType(v)
  1081  		scrPos := fetchRawUnminedCreditScriptOffset(v)
  1082  		scrLen := fetchRawUnminedCreditScriptLength(v)
  1083  
  1084  		// Grab the pkScript quickly.
  1085  		pkScript, err := fetchRawTxRecordPkScript(recKey, recVal,
  1086  			cred.outPoint.Index, scrPos, scrLen)
  1087  		if err != nil {
  1088  			return err
  1089  		}
  1090  
  1091  		acct, err := s.fetchAccountForPkScript(addrmgrNs, nil, v, pkScript)
  1092  		if err != nil {
  1093  			return err
  1094  		}
  1095  
  1096  		err = deleteRawUnminedCredit(ns, k)
  1097  		if err != nil {
  1098  			return err
  1099  		}
  1100  		err = putUnspentCredit(ns, &cred, scrType, scrPos, scrLen, acct, DBVersion)
  1101  		if err != nil {
  1102  			return err
  1103  		}
  1104  		err = putUnspent(ns, &cred.outPoint, &block.Block)
  1105  		if err != nil {
  1106  			return err
  1107  		}
  1108  
  1109  		// Do not increment ticket credits.
  1110  		if !(cred.opCode == txscript.OP_SSTX) {
  1111  			minedBalance += amount
  1112  		}
  1113  	}
  1114  
  1115  	err = putMinedBalance(ns, minedBalance)
  1116  	if err != nil {
  1117  		return err
  1118  	}
  1119  
  1120  	err = deleteUnpublished(ns, rec.Hash[:])
  1121  	if err != nil {
  1122  		return err
  1123  	}
  1124  
  1125  	return deleteRawUnmined(ns, rec.Hash[:])
  1126  }
  1127  
  1128  // InsertMinedTx inserts a new transaction record for a mined transaction into
  1129  // the database.  The block header must have been previously saved.  If the
  1130  // exact transaction is already saved as an unmined transaction, it is moved to
  1131  // a block.  Other unmined transactions which become double spends are removed.
  1132  func (s *Store) InsertMinedTx(dbtx walletdb.ReadWriteTx, rec *TxRecord, blockHash *chainhash.Hash) error {
  1133  	ns := dbtx.ReadWriteBucket(wtxmgrBucketKey)
  1134  	addrmgrNs := dbtx.ReadWriteBucket(waddrmgrBucketKey)
  1135  
  1136  	// Ensure block is in the main chain before proceeding.
  1137  	blockHeader := existsBlockHeader(ns, blockHash[:])
  1138  	if blockHeader == nil {
  1139  		return errors.E(errors.Invalid, "block header must be recorded")
  1140  	}
  1141  	height := extractBlockHeaderHeight(blockHeader)
  1142  	blockVal := ns.NestedReadBucket(bucketBlocks).Get(keyBlockRecord(height))
  1143  	if !bytes.Equal(extractRawBlockRecordHash(blockVal), blockHash[:]) {
  1144  		return errors.E(errors.Invalid, "mined transactions must be added to main chain blocks")
  1145  	}
  1146  
  1147  	// Fetch the mined balance in case we need to update it.
  1148  	minedBalance, err := fetchMinedBalance(ns)
  1149  	if err != nil {
  1150  		return err
  1151  	}
  1152  
  1153  	// Add a debit record for each unspent credit spent by this tx.
  1154  	block := blockMetaFromHeader(blockHash, blockHeader)
  1155  	spender := indexedIncidence{
  1156  		incidence: incidence{
  1157  			txHash: rec.Hash,
  1158  			block:  block.Block,
  1159  		},
  1160  		// index set for each iteration below
  1161  	}
  1162  	txType := stake.DetermineTxType(&rec.MsgTx)
  1163  
  1164  	invalidated := false
  1165  	if txType == stake.TxTypeRegular {
  1166  		height := extractBlockHeaderHeight(blockHeader)
  1167  		_, rawBlockRecVal := existsBlockRecord(ns, height)
  1168  		invalidated = extractRawBlockRecordStakeInvalid(rawBlockRecVal)
  1169  	}
  1170  
  1171  	for i, input := range rec.MsgTx.TxIn {
  1172  		unspentKey, credKey := existsUnspent(ns, &input.PreviousOutPoint)
  1173  		if credKey == nil {
  1174  			// Debits for unmined transactions are not explicitly
  1175  			// tracked.  Instead, all previous outputs spent by any
  1176  			// unmined transaction are added to a map for quick
  1177  			// lookups when it must be checked whether a mined
  1178  			// output is unspent or not.
  1179  			//
  1180  			// Tracking individual debits for unmined transactions
  1181  			// could be added later to simplify (and increase
  1182  			// performance of) determining some details that need
  1183  			// the previous outputs (e.g. determining a fee), but at
  1184  			// the moment that is not done (and a db lookup is used
  1185  			// for those cases instead).  There is also a good
  1186  			// chance that all unmined transaction handling will
  1187  			// move entirely to the db rather than being handled in
  1188  			// memory for atomicity reasons, so the simplist
  1189  			// implementation is currently used.
  1190  			continue
  1191  		}
  1192  
  1193  		if invalidated {
  1194  			// Add an invalidated debit but do not spend the previous credit,
  1195  			// remove it from the utxo set, or decrement the mined balance.
  1196  			debKey := keyDebit(&rec.Hash, uint32(i), &block.Block)
  1197  			credVal := existsRawCredit(ns, credKey)
  1198  			credAmt, err := fetchRawCreditAmount(credVal)
  1199  			if err != nil {
  1200  				return err
  1201  			}
  1202  			debVal := valueDebit(credAmt, credKey)
  1203  			err = ns.NestedReadWriteBucket(bucketStakeInvalidatedDebits).
  1204  				Put(debKey, debVal)
  1205  			if err != nil {
  1206  				return errors.E(errors.IO, err)
  1207  			}
  1208  		} else {
  1209  			spender.index = uint32(i)
  1210  			amt, err := spendCredit(ns, credKey, &spender)
  1211  			if err != nil {
  1212  				return err
  1213  			}
  1214  			err = putDebit(ns, &rec.Hash, uint32(i), amt, &block.Block,
  1215  				credKey)
  1216  			if err != nil {
  1217  				return err
  1218  			}
  1219  
  1220  			// Don't decrement spent ticket amounts.
  1221  			isTicketInput := (txType == stake.TxTypeSSGen && i == 1) ||
  1222  				(txType == stake.TxTypeSSRtx && i == 0)
  1223  			if !isTicketInput {
  1224  				minedBalance -= amt
  1225  			}
  1226  
  1227  			err = deleteRawUnspent(ns, unspentKey)
  1228  			if err != nil {
  1229  				return err
  1230  			}
  1231  		}
  1232  	}
  1233  
  1234  	// TODO only update if we actually modified the
  1235  	// mined balance.
  1236  	err = putMinedBalance(ns, minedBalance)
  1237  	if err != nil {
  1238  		return err
  1239  	}
  1240  
  1241  	// If a transaction record for this tx hash and block already exist,
  1242  	// there is nothing left to do.
  1243  	k, v := existsTxRecord(ns, &rec.Hash, &block.Block)
  1244  	if v != nil {
  1245  		return nil
  1246  	}
  1247  
  1248  	// If the transaction is a ticket purchase, record it in the ticket
  1249  	// purchases bucket.
  1250  	if txType == stake.TxTypeSStx {
  1251  		tk := rec.Hash[:]
  1252  		tv := existsRawTicketRecord(ns, tk)
  1253  		if tv == nil {
  1254  			tv = valueTicketRecord(-1)
  1255  			err := putRawTicketRecord(ns, tk, tv)
  1256  			if err != nil {
  1257  				return err
  1258  			}
  1259  		}
  1260  	}
  1261  
  1262  	// If the exact tx (not a double spend) is already included but
  1263  	// unconfirmed, move it to a block.
  1264  	v = existsRawUnmined(ns, rec.Hash[:])
  1265  	if v != nil {
  1266  		if invalidated {
  1267  			panic(fmt.Sprintf("unimplemented: moveMinedTx called on a stake-invalidated tx: block %v height %v tx %v", &block.Hash, block.Height, &rec.Hash))
  1268  		}
  1269  		return s.moveMinedTx(ns, addrmgrNs, rec, k, v, &block)
  1270  	}
  1271  
  1272  	// As there may be unconfirmed transactions that are invalidated by this
  1273  	// transaction (either being duplicates, or double spends), remove them
  1274  	// from the unconfirmed set.  This also handles removing unconfirmed
  1275  	// transaction spend chains if any other unconfirmed transactions spend
  1276  	// outputs of the removed double spend.
  1277  	err = s.removeDoubleSpends(ns, rec)
  1278  	if err != nil {
  1279  		return err
  1280  	}
  1281  
  1282  	// Adding this transaction hash to the set of transactions from this block.
  1283  	blockKey, blockValue := existsBlockRecord(ns, block.Height)
  1284  	blockValue, err = appendRawBlockRecord(blockValue, &rec.Hash)
  1285  	if err != nil {
  1286  		return err
  1287  	}
  1288  	err = putRawBlockRecord(ns, blockKey, blockValue)
  1289  	if err != nil {
  1290  		return err
  1291  	}
  1292  
  1293  	return putTxRecord(ns, rec, &block.Block)
  1294  }
  1295  
  1296  // AddCredit marks a transaction record as containing a transaction output
  1297  // spendable by wallet.  The output is added unspent, and is marked spent
  1298  // when a new transaction spending the output is inserted into the store.
  1299  //
  1300  // TODO(jrick): This should not be necessary.  Instead, pass the indexes
  1301  // that are known to contain credits when a transaction or merkleblock is
  1302  // inserted into the store.
  1303  func (s *Store) AddCredit(dbtx walletdb.ReadWriteTx, rec *TxRecord, block *BlockMeta,
  1304  	index uint32, change bool, account uint32) error {
  1305  
  1306  	ns := dbtx.ReadWriteBucket(wtxmgrBucketKey)
  1307  
  1308  	if int(index) >= len(rec.MsgTx.TxOut) {
  1309  		return errors.E(errors.Invalid, "transaction output index for credit does not exist")
  1310  	}
  1311  
  1312  	invalidated := false
  1313  	if rec.TxType == stake.TxTypeRegular && block != nil {
  1314  		blockHeader := existsBlockHeader(ns, block.Hash[:])
  1315  		height := extractBlockHeaderHeight(blockHeader)
  1316  		_, rawBlockRecVal := existsBlockRecord(ns, height)
  1317  		invalidated = extractRawBlockRecordStakeInvalid(rawBlockRecVal)
  1318  	}
  1319  	if invalidated {
  1320  		// Write an invalidated credit.  Do not create a utxo for the output,
  1321  		// and do not increment the mined balance.
  1322  		version := rec.MsgTx.TxOut[index].Version
  1323  		pkScript := rec.MsgTx.TxOut[index].PkScript
  1324  		k := keyCredit(&rec.Hash, index, &block.Block)
  1325  		cred := credit{
  1326  			outPoint: wire.OutPoint{
  1327  				Hash:  rec.Hash,
  1328  				Index: index,
  1329  			},
  1330  			block:      block.Block,
  1331  			amount:     dcrutil.Amount(rec.MsgTx.TxOut[index].Value),
  1332  			change:     change,
  1333  			spentBy:    indexedIncidence{index: ^uint32(0)},
  1334  			opCode:     getStakeOpCode(version, pkScript),
  1335  			isCoinbase: compat.IsEitherCoinBaseTx(&rec.MsgTx),
  1336  			hasExpiry:  rec.MsgTx.Expiry != 0,
  1337  		}
  1338  		scTy := pkScriptType(version, pkScript)
  1339  		scLoc := uint32(rec.MsgTx.PkScriptLocs()[index])
  1340  		v := valueUnspentCredit(&cred, scTy, scLoc, uint32(len(pkScript)),
  1341  			account, DBVersion)
  1342  		err := ns.NestedReadWriteBucket(bucketStakeInvalidatedCredits).Put(k, v)
  1343  		if err != nil {
  1344  			return errors.E(errors.IO, err)
  1345  		}
  1346  		return nil
  1347  	}
  1348  
  1349  	_, err := s.addCredit(ns, rec, block, index, change, account)
  1350  	return err
  1351  }
  1352  
  1353  // getStakeOpCode returns opNonstake for non-stake transactions, or the stake op
  1354  // code tag for stake transactions. This excludes TADD.
  1355  func getStakeOpCode(version uint16, pkScript []byte) uint8 {
  1356  	class := stdscript.DetermineScriptType(version, pkScript)
  1357  	switch class {
  1358  	case stdscript.STStakeSubmissionPubKeyHash, stdscript.STStakeSubmissionScriptHash:
  1359  		return txscript.OP_SSTX
  1360  	case stdscript.STStakeGenPubKeyHash, stdscript.STStakeGenScriptHash:
  1361  		return txscript.OP_SSGEN
  1362  	case stdscript.STStakeRevocationPubKeyHash, stdscript.STStakeRevocationScriptHash:
  1363  		return txscript.OP_SSRTX
  1364  	case stdscript.STStakeChangePubKeyHash, stdscript.STStakeChangeScriptHash:
  1365  		return txscript.OP_SSTXCHANGE
  1366  	case stdscript.STTreasuryGenPubKeyHash, stdscript.STTreasuryGenScriptHash:
  1367  		return txscript.OP_TGEN
  1368  	}
  1369  
  1370  	return opNonstake
  1371  }
  1372  
  1373  // pkScriptType determines the general type of pkScript for the purposes of
  1374  // fast extraction of pkScript data from a raw transaction record.
  1375  func pkScriptType(ver uint16, pkScript []byte) scriptType {
  1376  	class := stdscript.DetermineScriptType(ver, pkScript)
  1377  	switch class {
  1378  	case stdscript.STPubKeyHashEcdsaSecp256k1:
  1379  		return scriptTypeP2PKH
  1380  	case stdscript.STPubKeyEcdsaSecp256k1:
  1381  		return scriptTypeP2PK
  1382  	case stdscript.STScriptHash:
  1383  		return scriptTypeP2SH
  1384  	case stdscript.STPubKeyHashEd25519, stdscript.STPubKeyHashSchnorrSecp256k1:
  1385  		return scriptTypeP2PKHAlt
  1386  	case stdscript.STPubKeyEd25519, stdscript.STPubKeySchnorrSecp256k1:
  1387  		return scriptTypeP2PKAlt
  1388  	case stdscript.STStakeSubmissionPubKeyHash, stdscript.STStakeGenPubKeyHash,
  1389  		stdscript.STStakeRevocationPubKeyHash, stdscript.STStakeChangePubKeyHash,
  1390  		stdscript.STTreasuryGenPubKeyHash:
  1391  		return scriptTypeSP2PKH
  1392  	case stdscript.STStakeSubmissionScriptHash, stdscript.STStakeGenScriptHash,
  1393  		stdscript.STStakeRevocationScriptHash, stdscript.STStakeChangeScriptHash,
  1394  		stdscript.STTreasuryGenScriptHash:
  1395  		return scriptTypeSP2SH
  1396  	}
  1397  
  1398  	return scriptTypeUnspecified
  1399  }
  1400  
  1401  func (s *Store) addCredit(ns walletdb.ReadWriteBucket, rec *TxRecord, block *BlockMeta,
  1402  	index uint32, change bool, account uint32) (bool, error) {
  1403  
  1404  	scriptVersion, pkScript := rec.MsgTx.TxOut[index].Version, rec.MsgTx.TxOut[index].PkScript
  1405  	opCode := getStakeOpCode(scriptVersion, pkScript)
  1406  	isCoinbase := compat.IsEitherCoinBaseTx(&rec.MsgTx)
  1407  	hasExpiry := rec.MsgTx.Expiry != wire.NoExpiryValue
  1408  
  1409  	if block == nil {
  1410  		// Unmined tx must have been already added for the credit to be added.
  1411  		if existsRawUnmined(ns, rec.Hash[:]) == nil {
  1412  			panic("attempted to add credit for unmined tx, but unmined tx with same hash does not exist")
  1413  		}
  1414  
  1415  		k := canonicalOutPoint(&rec.Hash, index)
  1416  		if existsRawUnminedCredit(ns, k) != nil {
  1417  			return false, nil
  1418  		}
  1419  		scrType := pkScriptType(scriptVersion, pkScript)
  1420  		pkScrLocs := rec.MsgTx.PkScriptLocs()
  1421  		scrLoc := pkScrLocs[index]
  1422  		scrLen := len(pkScript)
  1423  
  1424  		v := valueUnminedCredit(dcrutil.Amount(rec.MsgTx.TxOut[index].Value),
  1425  			change, opCode, isCoinbase, hasExpiry, scrType, uint32(scrLoc),
  1426  			uint32(scrLen), account, DBVersion)
  1427  		return true, putRawUnminedCredit(ns, k, v)
  1428  	}
  1429  
  1430  	k, v := existsCredit(ns, &rec.Hash, index, &block.Block)
  1431  	if v != nil {
  1432  		return false, nil
  1433  	}
  1434  
  1435  	txOutAmt := dcrutil.Amount(rec.MsgTx.TxOut[index].Value)
  1436  	log.Debugf("Marking transaction %v output %d (%v) spendable",
  1437  		rec.Hash, index, txOutAmt)
  1438  
  1439  	cred := credit{
  1440  		outPoint: wire.OutPoint{
  1441  			Hash:  rec.Hash,
  1442  			Index: index,
  1443  		},
  1444  		block:      block.Block,
  1445  		amount:     txOutAmt,
  1446  		change:     change,
  1447  		spentBy:    indexedIncidence{index: ^uint32(0)},
  1448  		opCode:     opCode,
  1449  		isCoinbase: isCoinbase,
  1450  		hasExpiry:  rec.MsgTx.Expiry != wire.NoExpiryValue,
  1451  	}
  1452  	scrType := pkScriptType(scriptVersion, pkScript)
  1453  	pkScrLocs := rec.MsgTx.PkScriptLocs()
  1454  	scrLoc := pkScrLocs[index]
  1455  	scrLen := len(pkScript)
  1456  
  1457  	v = valueUnspentCredit(&cred, scrType, uint32(scrLoc), uint32(scrLen),
  1458  		account, DBVersion)
  1459  	err := putRawCredit(ns, k, v)
  1460  	if err != nil {
  1461  		return false, err
  1462  	}
  1463  
  1464  	minedBalance, err := fetchMinedBalance(ns)
  1465  	if err != nil {
  1466  		return false, err
  1467  	}
  1468  	// Update the balance so long as it's not a ticket output.
  1469  	if !(opCode == txscript.OP_SSTX) {
  1470  		err = putMinedBalance(ns, minedBalance+txOutAmt)
  1471  		if err != nil {
  1472  			return false, err
  1473  		}
  1474  	}
  1475  
  1476  	return true, putUnspent(ns, &cred.outPoint, &block.Block)
  1477  }
  1478  
  1479  // AddTicketCommitment adds the given output of a transaction as a ticket
  1480  // commitment originating from a wallet account.
  1481  //
  1482  // The transaction record MUST correspond to a ticket (sstx) transaction, the
  1483  // index MUST be from a commitment output and the account MUST be from a
  1484  // wallet-controlled account, otherwise the database will be put in an undefined
  1485  // state.
  1486  func (s *Store) AddTicketCommitment(ns walletdb.ReadWriteBucket, rec *TxRecord,
  1487  	index, account uint32) error {
  1488  
  1489  	k := keyTicketCommitment(rec.Hash, index)
  1490  	v := existsRawTicketCommitment(ns, k)
  1491  	if v != nil {
  1492  		// If we have already recorded this ticket commitment, there's nothing
  1493  		// else to do. Note that this means unspent ticket commitment entries
  1494  		// are added to the index only once, at the very first time the ticket
  1495  		// commitment is seen.
  1496  		return nil
  1497  	}
  1498  
  1499  	if index >= uint32(len(rec.MsgTx.TxOut)) {
  1500  		return errors.E(errors.Invalid, "index should be of an existing output")
  1501  	}
  1502  
  1503  	if index%2 != 1 {
  1504  		return errors.E(errors.Invalid, "index should be of a ticket commitment")
  1505  	}
  1506  
  1507  	if rec.TxType != stake.TxTypeSStx {
  1508  		return errors.E(errors.Invalid, "transaction record should be of a ticket")
  1509  	}
  1510  
  1511  	txOut := rec.MsgTx.TxOut[index]
  1512  	txOutAmt, err := stake.AmountFromSStxPkScrCommitment(txOut.PkScript)
  1513  	if err != nil {
  1514  		return err
  1515  	}
  1516  
  1517  	log.Debugf("Accounting for ticket commitment %v:%d (%v) from the wallet",
  1518  		rec.Hash, index, txOutAmt)
  1519  
  1520  	v = valueTicketCommitment(txOutAmt, account)
  1521  	err = putRawTicketCommitment(ns, k, v)
  1522  	if err != nil {
  1523  		return err
  1524  	}
  1525  
  1526  	v = valueUnspentTicketCommitment(false)
  1527  	return putRawUnspentTicketCommitment(ns, k, v)
  1528  }
  1529  
  1530  // originalTicketInfo returns the transaction hash and output count for the
  1531  // ticket spent by the given transaction.
  1532  //
  1533  // spenderType MUST be either TxTypeSSGen or TxTypeSSRtx and MUST by the type of
  1534  // the provided spenderTx, otherwise the result is undefined.
  1535  func originalTicketInfo(spenderType stake.TxType, spenderTx *wire.MsgTx) (chainhash.Hash, uint32) {
  1536  	if spenderType == stake.TxTypeSSGen {
  1537  		// Votes have an additional input (stakebase) and two additional outputs
  1538  		// (previous block hash and vote bits) so account for those.
  1539  		return spenderTx.TxIn[1].PreviousOutPoint.Hash,
  1540  			uint32((len(spenderTx.TxOut)-2)*2 + 1)
  1541  	}
  1542  
  1543  	return spenderTx.TxIn[0].PreviousOutPoint.Hash,
  1544  		uint32(len(spenderTx.TxOut)*2 + 1)
  1545  }
  1546  
  1547  // removeUnspentTicketCommitments deletes any outstanding commitments that are
  1548  // controlled by this wallet and have been redeemed by the given transaction.
  1549  //
  1550  // rec MUST be either a vote or revocation transaction, otherwise the results
  1551  // are undefined.
  1552  func (s *Store) removeUnspentTicketCommitments(ns walletdb.ReadWriteBucket,
  1553  	txType stake.TxType, tx *wire.MsgTx) error {
  1554  
  1555  	ticketHash, ticketOutCount := originalTicketInfo(txType, tx)
  1556  	for i := uint32(1); i < ticketOutCount; i += 2 {
  1557  		k := keyTicketCommitment(ticketHash, i)
  1558  		if existsRawTicketCommitment(ns, k) == nil {
  1559  			// This commitment was not tracked by the wallet, so ignore it.
  1560  			continue
  1561  		}
  1562  
  1563  		log.Debugf("Removing unspent ticket commitment %v:%d from the wallet",
  1564  			ticketHash, i)
  1565  
  1566  		err := deleteRawUnspentTicketCommitment(ns, k)
  1567  		if err != nil {
  1568  			return err
  1569  		}
  1570  	}
  1571  
  1572  	return nil
  1573  }
  1574  
  1575  // replaceTicketCommitmentUnminedSpent replaces the unminedSpent flag of all
  1576  // unspent commitments spent by the given transaction to the given value.
  1577  //
  1578  // txType MUST be either a TxTypeSSGen or TxTypeSSRtx and MUST be the type for
  1579  // the corresponding tx parameter, otherwise the result is undefined.
  1580  func (s *Store) replaceTicketCommitmentUnminedSpent(ns walletdb.ReadWriteBucket,
  1581  	txType stake.TxType, tx *wire.MsgTx, value bool) error {
  1582  
  1583  	ticketHash, ticketOutCount := originalTicketInfo(txType, tx)
  1584  
  1585  	// Loop over the indices of possible ticket commitments, checking if they
  1586  	// are controlled by the wallet. If they are, replace the corresponding
  1587  	// unminedSpent flag.
  1588  	for i := uint32(1); i < ticketOutCount; i += 2 {
  1589  		k := keyTicketCommitment(ticketHash, i)
  1590  		if existsRawTicketCommitment(ns, k) == nil {
  1591  			// This commitment was not tracked by the wallet, so ignore it.
  1592  			continue
  1593  		}
  1594  
  1595  		log.Debugf("Marking ticket commitment %v:%d unmined spent as %v",
  1596  			ticketHash, i, value)
  1597  		v := valueUnspentTicketCommitment(value)
  1598  		err := putRawUnspentTicketCommitment(ns, k, v)
  1599  		if err != nil {
  1600  			return err
  1601  		}
  1602  	}
  1603  
  1604  	return nil
  1605  }
  1606  
  1607  // RedeemTicketCommitments redeems the commitments of the given vote or
  1608  // revocation transaction by marking the commitments unminedSpent or removing
  1609  // them altogether.
  1610  //
  1611  // rec MUST be either a vote (ssgen) or revocation (ssrtx) or this method fails.
  1612  func (s *Store) RedeemTicketCommitments(ns walletdb.ReadWriteBucket, rec *TxRecord,
  1613  	block *BlockMeta) error {
  1614  
  1615  	if (rec.TxType != stake.TxTypeSSGen) && (rec.TxType != stake.TxTypeSSRtx) {
  1616  		return errors.E(errors.Invalid, "rec must be a vote or revocation tx")
  1617  	}
  1618  
  1619  	if block == nil {
  1620  		// When the tx is unmined, we only mark the commitment as spent by an
  1621  		// unmined tx.
  1622  		return s.replaceTicketCommitmentUnminedSpent(ns, rec.TxType,
  1623  			&rec.MsgTx, true)
  1624  	}
  1625  
  1626  	// When the tx is mined we completely remove the commitment from the unspent
  1627  	// commitments index.
  1628  	return s.removeUnspentTicketCommitments(ns, rec.TxType, &rec.MsgTx)
  1629  }
  1630  
  1631  // copied from txscript/v1
  1632  func getScriptHashFromP2SHScript(pkScript []byte) ([]byte, error) {
  1633  	// Scan through the opcodes until the first HASH160 opcode is found.
  1634  	const scriptVersion = 0
  1635  	tokenizer := txscript.MakeScriptTokenizer(scriptVersion, pkScript)
  1636  	for tokenizer.Next() {
  1637  		if tokenizer.Opcode() == txscript.OP_HASH160 {
  1638  			break
  1639  		}
  1640  	}
  1641  
  1642  	// Attempt to extract the script hash if the script is not already fully
  1643  	// parsed and didn't already fail during parsing above.
  1644  	//
  1645  	// Note that this means a script without a data push for the script hash or
  1646  	// where OP_HASH160 wasn't found will result in nil data being returned.
  1647  	// This was done to preserve existing behavior, although it is questionable
  1648  	// since a p2sh script has a specific form and if there is no push here,
  1649  	// it's not really a p2sh script and thus should probably have returned an
  1650  	// appropriate error for calling the function incorrectly.
  1651  	if tokenizer.Next() {
  1652  		return tokenizer.Data(), nil
  1653  	}
  1654  	return nil, tokenizer.Err()
  1655  }
  1656  
  1657  // AddMultisigOut adds a P2SH multisignature spendable output into the
  1658  // transaction manager. In the event that the output already existed but
  1659  // was not mined, the output is updated so its value reflects the block
  1660  // it was included in.
  1661  func (s *Store) AddMultisigOut(dbtx walletdb.ReadWriteTx, rec *TxRecord, block *BlockMeta, index uint32) error {
  1662  	ns := dbtx.ReadWriteBucket(wtxmgrBucketKey)
  1663  	addrmgrNs := dbtx.ReadWriteBucket(waddrmgrBucketKey)
  1664  
  1665  	if int(index) >= len(rec.MsgTx.TxOut) {
  1666  		return errors.E(errors.Invalid, "transaction output does not exist")
  1667  	}
  1668  
  1669  	empty := &chainhash.Hash{}
  1670  
  1671  	// Check to see if the output already exists and is now being
  1672  	// mined into a block. If it does, update the record and return.
  1673  	key := keyMultisigOut(rec.Hash, index)
  1674  	val := existsMultisigOutCopy(ns, key)
  1675  	if val != nil && block != nil {
  1676  		blockHashV, _ := fetchMultisigOutMined(val)
  1677  		if blockHashV.IsEqual(empty) {
  1678  			setMultisigOutMined(val, block.Block.Hash,
  1679  				uint32(block.Block.Height))
  1680  			return putMultisigOutRawValues(ns, key, val)
  1681  		}
  1682  		return errors.E(errors.Invalid, "multisig credit is mined")
  1683  	}
  1684  	// The multisignature output already exists in the database
  1685  	// as an unmined, unspent output and something is trying to
  1686  	// add it in duplicate. Return.
  1687  	if val != nil && block == nil {
  1688  		blockHashV, _ := fetchMultisigOutMined(val)
  1689  		if blockHashV.IsEqual(empty) {
  1690  			return nil
  1691  		}
  1692  	}
  1693  
  1694  	// Dummy block for created transactions.
  1695  	if block == nil {
  1696  		block = &BlockMeta{Block{*empty, 0},
  1697  			rec.Received,
  1698  			0}
  1699  	}
  1700  
  1701  	// Otherwise create a full record and insert it.
  1702  	version := rec.MsgTx.TxOut[index].Version
  1703  	p2shScript := rec.MsgTx.TxOut[index].PkScript
  1704  	class := stdscript.DetermineScriptType(version, p2shScript)
  1705  	tree := wire.TxTreeRegular
  1706  	class, isStakeType := txrules.StakeSubScriptType(class)
  1707  	if isStakeType {
  1708  		tree = wire.TxTreeStake
  1709  	}
  1710  	if class != stdscript.STScriptHash {
  1711  		return errors.E(errors.Invalid, "multisig output must be P2SH")
  1712  	}
  1713  	scriptHash, err := getScriptHashFromP2SHScript(p2shScript)
  1714  	if err != nil {
  1715  		return err
  1716  	}
  1717  	multisigScript, err := s.manager.redeemScriptForHash160(addrmgrNs, scriptHash)
  1718  	if err != nil {
  1719  		return err
  1720  	}
  1721  	if version != 0 {
  1722  		return errors.E(errors.IO, "only version 0 scripts are supported")
  1723  	}
  1724  	multisigDetails := stdscript.ExtractMultiSigScriptDetailsV0(multisigScript, false)
  1725  	if !multisigDetails.Valid {
  1726  		return errors.E(errors.IO, "invalid m-of-n multisig script")
  1727  	}
  1728  	var p2shScriptHash [ripemd160.Size]byte
  1729  	copy(p2shScriptHash[:], scriptHash)
  1730  	val = valueMultisigOut(p2shScriptHash,
  1731  		uint8(multisigDetails.RequiredSigs),
  1732  		uint8(multisigDetails.NumPubKeys),
  1733  		false,
  1734  		tree,
  1735  		block.Block.Hash,
  1736  		uint32(block.Block.Height),
  1737  		dcrutil.Amount(rec.MsgTx.TxOut[index].Value),
  1738  		*empty,     // Unspent
  1739  		0xFFFFFFFF, // Unspent
  1740  		rec.Hash)
  1741  
  1742  	// Write the output, and insert the unspent key.
  1743  	err = putMultisigOutRawValues(ns, key, val)
  1744  	if err != nil {
  1745  		return err
  1746  	}
  1747  	return putMultisigOutUS(ns, key)
  1748  }
  1749  
  1750  // SpendMultisigOut spends a multisignature output by making it spent in
  1751  // the general bucket and removing it from the unspent bucket.
  1752  func (s *Store) SpendMultisigOut(ns walletdb.ReadWriteBucket, op *wire.OutPoint, spendHash chainhash.Hash, spendIndex uint32) error {
  1753  	// Mark the output spent.
  1754  	key := keyMultisigOut(op.Hash, op.Index)
  1755  	val := existsMultisigOutCopy(ns, key)
  1756  	if val == nil {
  1757  		return errors.E(errors.NotExist, errors.Errorf("no multisig output for outpoint %v", op))
  1758  	}
  1759  	// Attempting to double spend an outpoint is an error.
  1760  	if fetchMultisigOutSpent(val) {
  1761  		_, foundSpendHash, foundSpendIndex := fetchMultisigOutSpentVerbose(val)
  1762  		// It's not technically an error to try to respend
  1763  		// the output with exactly the same transaction.
  1764  		// However, there's no need to set it again. Just return.
  1765  		if spendHash == foundSpendHash && foundSpendIndex == spendIndex {
  1766  			return nil
  1767  		}
  1768  		return errors.E(errors.DoubleSpend, errors.Errorf("outpoint %v spent by %v", op, &foundSpendHash))
  1769  	}
  1770  	setMultisigOutSpent(val, spendHash, spendIndex)
  1771  
  1772  	// Check to see that it's in the unspent bucket.
  1773  	existsUnspent := existsMultisigOutUS(ns, key)
  1774  	if !existsUnspent {
  1775  		return errors.E(errors.IO, "missing unspent multisig record")
  1776  	}
  1777  
  1778  	// Write the updated output, and delete the unspent key.
  1779  	err := putMultisigOutRawValues(ns, key, val)
  1780  	if err != nil {
  1781  		return err
  1782  	}
  1783  	return deleteMultisigOutUS(ns, key)
  1784  }
  1785  
  1786  func approvesParent(voteBits uint16) bool {
  1787  	return dcrutil.IsFlagSet16(voteBits, dcrutil.BlockValid)
  1788  }
  1789  
  1790  // Rollback removes all blocks at height onwards, moving any transactions within
  1791  // each block to the unconfirmed pool.
  1792  func (s *Store) Rollback(dbtx walletdb.ReadWriteTx, height int32) error {
  1793  	// Note: does not stake validate the parent block at height-1.  Assumes the
  1794  	// rollback is being done to add more blocks starting at height, and stake
  1795  	// validation will occur when that block is attached.
  1796  
  1797  	ns := dbtx.ReadWriteBucket(wtxmgrBucketKey)
  1798  	addrmgrNs := dbtx.ReadWriteBucket(waddrmgrBucketKey)
  1799  
  1800  	if height == 0 {
  1801  		return errors.E(errors.Invalid, "cannot rollback the genesis block")
  1802  	}
  1803  
  1804  	minedBalance, err := fetchMinedBalance(ns)
  1805  	if err != nil {
  1806  		return err
  1807  	}
  1808  
  1809  	// Keep track of all credits that were removed from coinbase
  1810  	// transactions.  After detaching all blocks, if any transaction record
  1811  	// exists in unmined that spends these outputs, remove them and their
  1812  	// spend chains.
  1813  	//
  1814  	// It is necessary to keep these in memory and fix the unmined
  1815  	// transactions later since blocks are removed in increasing order.
  1816  	var coinBaseCredits []wire.OutPoint
  1817  
  1818  	var heightsToRemove []int32
  1819  
  1820  	it := makeReverseBlockIterator(ns)
  1821  	defer it.close()
  1822  	for it.prev() {
  1823  		b := &it.elem
  1824  		if it.elem.Height < height {
  1825  			break
  1826  		}
  1827  
  1828  		heightsToRemove = append(heightsToRemove, it.elem.Height)
  1829  
  1830  		log.Debugf("Rolling back transactions from block %v height %d",
  1831  			b.Hash, b.Height)
  1832  
  1833  		// cache the values of removed credits so they can be inspected even
  1834  		// after removal from the db.
  1835  		removedCredits := make(map[string][]byte)
  1836  
  1837  		for i := range b.transactions {
  1838  			txHash := &b.transactions[i]
  1839  
  1840  			recKey := keyTxRecord(txHash, &b.Block)
  1841  			recVal := existsRawTxRecord(ns, recKey)
  1842  			var rec TxRecord
  1843  			err = readRawTxRecord(txHash, recVal, &rec)
  1844  			if err != nil {
  1845  				return err
  1846  			}
  1847  
  1848  			err = deleteTxRecord(ns, txHash, &b.Block)
  1849  			if err != nil {
  1850  				return err
  1851  			}
  1852  
  1853  			// Handle coinbase transactions specially since they are
  1854  			// not moved to the unconfirmed store.  A coinbase cannot
  1855  			// contain any debits, but all credits should be removed
  1856  			// and the mined balance decremented.
  1857  			if compat.IsEitherCoinBaseTx(&rec.MsgTx) {
  1858  				for i, output := range rec.MsgTx.TxOut {
  1859  					k, v := existsCredit(ns, &rec.Hash,
  1860  						uint32(i), &b.Block)
  1861  					if v == nil {
  1862  						continue
  1863  					}
  1864  
  1865  					coinBaseCredits = append(coinBaseCredits, wire.OutPoint{
  1866  						Hash:  rec.Hash,
  1867  						Index: uint32(i),
  1868  						Tree:  wire.TxTreeRegular,
  1869  					})
  1870  
  1871  					outPointKey := canonicalOutPoint(&rec.Hash, uint32(i))
  1872  					credKey := existsRawUnspent(ns, outPointKey)
  1873  					if credKey != nil {
  1874  						minedBalance -= dcrutil.Amount(output.Value)
  1875  						err = deleteRawUnspent(ns, outPointKey)
  1876  						if err != nil {
  1877  							return err
  1878  						}
  1879  					}
  1880  					removedCredits[string(k)] = v
  1881  					err = deleteRawCredit(ns, k)
  1882  					if err != nil {
  1883  						return err
  1884  					}
  1885  
  1886  					// Check if this output is a multisignature
  1887  					// P2SH output. If it is, access the value
  1888  					// for the key and mark it unmined.
  1889  					msKey := keyMultisigOut(*txHash, uint32(i))
  1890  					msVal := existsMultisigOutCopy(ns, msKey)
  1891  					if msVal != nil {
  1892  						setMultisigOutUnmined(msVal)
  1893  						err := putMultisigOutRawValues(ns, msKey, msVal)
  1894  						if err != nil {
  1895  							return err
  1896  						}
  1897  					}
  1898  				}
  1899  
  1900  				continue
  1901  			}
  1902  
  1903  			err = putRawUnmined(ns, txHash[:], recVal)
  1904  			if err != nil {
  1905  				return err
  1906  			}
  1907  
  1908  			txType := rec.TxType
  1909  
  1910  			// For each debit recorded for this transaction, mark
  1911  			// the credit it spends as unspent (as long as it still
  1912  			// exists) and delete the debit.  The previous output is
  1913  			// recorded in the unconfirmed store for every previous
  1914  			// output, not just debits.
  1915  			for i, input := range rec.MsgTx.TxIn {
  1916  				// Skip stakebases.
  1917  				if i == 0 && txType == stake.TxTypeSSGen {
  1918  					continue
  1919  				}
  1920  
  1921  				prevOut := &input.PreviousOutPoint
  1922  				prevOutKey := canonicalOutPoint(&prevOut.Hash,
  1923  					prevOut.Index)
  1924  				err = putRawUnminedInput(ns, prevOutKey, rec.Hash[:])
  1925  				if err != nil {
  1926  					return err
  1927  				}
  1928  
  1929  				// If this input is a debit, remove the debit
  1930  				// record and mark the credit that it spent as
  1931  				// unspent, incrementing the mined balance.
  1932  				debKey, credKey, err := existsDebit(ns,
  1933  					&rec.Hash, uint32(i), &b.Block)
  1934  				if err != nil {
  1935  					return err
  1936  				}
  1937  				if debKey == nil {
  1938  					continue
  1939  				}
  1940  
  1941  				// Store the credit OP code for later use.  Since the credit may
  1942  				// already have been removed if it also appeared in this block,
  1943  				// a cache of removed credits is also checked.
  1944  				credVal := existsRawCredit(ns, credKey)
  1945  				if credVal == nil {
  1946  					credVal = removedCredits[string(credKey)]
  1947  				}
  1948  				if credVal == nil {
  1949  					return errors.E(errors.IO, errors.Errorf("missing credit "+
  1950  						"%v, key %x, spent by %v", prevOut, credKey, &rec.Hash))
  1951  				}
  1952  				creditOpCode := fetchRawCreditTagOpCode(credVal)
  1953  
  1954  				// unspendRawCredit does not error in case the no credit exists
  1955  				// for this key, but this behavior is correct.  Since
  1956  				// transactions are removed in an unspecified order
  1957  				// (transactions in the blo	ck record are not sorted by
  1958  				// appearance in the block), this credit may have already been
  1959  				// removed.
  1960  				var amt dcrutil.Amount
  1961  				amt, err = unspendRawCredit(ns, credKey)
  1962  				if err != nil {
  1963  					return err
  1964  				}
  1965  
  1966  				err = deleteRawDebit(ns, debKey)
  1967  				if err != nil {
  1968  					return err
  1969  				}
  1970  
  1971  				// If the credit was previously removed in the
  1972  				// rollback, the credit amount is zero.  Only
  1973  				// mark the previously spent credit as unspent
  1974  				// if it still exists.
  1975  				if amt == 0 {
  1976  					continue
  1977  				}
  1978  				unspentVal, err := fetchRawCreditUnspentValue(credKey)
  1979  				if err != nil {
  1980  					return err
  1981  				}
  1982  
  1983  				// Ticket output spends are never decremented, so no need
  1984  				// to add them back.
  1985  				if !(creditOpCode == txscript.OP_SSTX) {
  1986  					minedBalance += amt
  1987  				}
  1988  
  1989  				err = putRawUnspent(ns, prevOutKey, unspentVal)
  1990  				if err != nil {
  1991  					return err
  1992  				}
  1993  
  1994  				// Check if this input uses a multisignature P2SH
  1995  				// output. If it did, mark the output unspent
  1996  				// and create an entry in the unspent bucket.
  1997  				msVal := existsMultisigOutCopy(ns, prevOutKey)
  1998  				if msVal != nil {
  1999  					setMultisigOutUnSpent(msVal)
  2000  					err := putMultisigOutRawValues(ns, prevOutKey, msVal)
  2001  					if err != nil {
  2002  						return err
  2003  					}
  2004  					err = putMultisigOutUS(ns, prevOutKey)
  2005  					if err != nil {
  2006  						return err
  2007  					}
  2008  				}
  2009  			}
  2010  
  2011  			// For each detached non-coinbase credit, move the
  2012  			// credit output to unmined.  If the credit is marked
  2013  			// unspent, it is removed from the utxo set and the
  2014  			// mined balance is decremented.
  2015  			//
  2016  			// TODO: use a credit iterator
  2017  			for i, output := range rec.MsgTx.TxOut {
  2018  				k, v := existsCredit(ns, &rec.Hash, uint32(i),
  2019  					&b.Block)
  2020  				if v == nil {
  2021  					continue
  2022  				}
  2023  				vcopy := make([]byte, len(v))
  2024  				copy(vcopy, v)
  2025  				removedCredits[string(k)] = vcopy
  2026  
  2027  				amt, change, err := fetchRawCreditAmountChange(v)
  2028  				if err != nil {
  2029  					return err
  2030  				}
  2031  				opCode := fetchRawCreditTagOpCode(v)
  2032  				isCoinbase := fetchRawCreditIsCoinbase(v)
  2033  				hasExpiry := fetchRawCreditHasExpiry(v, DBVersion)
  2034  
  2035  				scrType := pkScriptType(output.Version, output.PkScript)
  2036  				scrLoc := rec.MsgTx.PkScriptLocs()[i]
  2037  				scrLen := len(rec.MsgTx.TxOut[i].PkScript)
  2038  
  2039  				acct, err := s.fetchAccountForPkScript(addrmgrNs, v, nil, output.PkScript)
  2040  				if err != nil {
  2041  					return err
  2042  				}
  2043  
  2044  				outPointKey := canonicalOutPoint(&rec.Hash, uint32(i))
  2045  				unminedCredVal := valueUnminedCredit(amt, change, opCode,
  2046  					isCoinbase, hasExpiry, scrType, uint32(scrLoc), uint32(scrLen),
  2047  					acct, DBVersion)
  2048  				err = putRawUnminedCredit(ns, outPointKey, unminedCredVal)
  2049  				if err != nil {
  2050  					return err
  2051  				}
  2052  
  2053  				err = deleteRawCredit(ns, k)
  2054  				if err != nil {
  2055  					return err
  2056  				}
  2057  
  2058  				credKey := existsRawUnspent(ns, outPointKey)
  2059  				if credKey != nil {
  2060  					// Ticket amounts were never added, so ignore them when
  2061  					// correcting the balance.
  2062  					isTicketOutput := (txType == stake.TxTypeSStx && i == 0)
  2063  					if !isTicketOutput {
  2064  						minedBalance -= dcrutil.Amount(output.Value)
  2065  					}
  2066  					err = deleteRawUnspent(ns, outPointKey)
  2067  					if err != nil {
  2068  						return err
  2069  					}
  2070  				}
  2071  
  2072  				// Check if this output is a multisignature
  2073  				// P2SH output. If it is, access the value
  2074  				// for the key and mark it unmined.
  2075  				msKey := keyMultisigOut(*txHash, uint32(i))
  2076  				msVal := existsMultisigOutCopy(ns, msKey)
  2077  				if msVal != nil {
  2078  					setMultisigOutUnmined(msVal)
  2079  					err := putMultisigOutRawValues(ns, msKey, msVal)
  2080  					if err != nil {
  2081  						return err
  2082  					}
  2083  				}
  2084  			}
  2085  
  2086  			// When rolling back votes and revocations, return unspent status
  2087  			// for tracked commitments.
  2088  			if (rec.TxType == stake.TxTypeSSGen) || (rec.TxType == stake.TxTypeSSRtx) {
  2089  				err = s.replaceTicketCommitmentUnminedSpent(ns, rec.TxType, &rec.MsgTx, true)
  2090  				if err != nil {
  2091  					return err
  2092  				}
  2093  			}
  2094  		}
  2095  
  2096  		// reposition cursor before deleting this k/v pair and advancing to the
  2097  		// previous.
  2098  		it.reposition(it.elem.Height)
  2099  
  2100  		// Avoid cursor deletion until bolt issue #620 is resolved.
  2101  		// err = it.delete()
  2102  		// if err != nil {
  2103  		// 	return err
  2104  		// }
  2105  	}
  2106  	if it.err != nil {
  2107  		return it.err
  2108  	}
  2109  
  2110  	// Delete the block records outside of the iteration since cursor deletion
  2111  	// is broken.
  2112  	for _, h := range heightsToRemove {
  2113  		err = deleteBlockRecord(ns, h)
  2114  		if err != nil {
  2115  			return err
  2116  		}
  2117  	}
  2118  
  2119  	for _, op := range coinBaseCredits {
  2120  		opKey := canonicalOutPoint(&op.Hash, op.Index)
  2121  		unminedKey := existsRawUnminedInput(ns, opKey)
  2122  		if unminedKey != nil {
  2123  			unminedVal := existsRawUnmined(ns, unminedKey)
  2124  			var unminedRec TxRecord
  2125  			copy(unminedRec.Hash[:], unminedKey) // Silly but need an array
  2126  			err = readRawTxRecord(&unminedRec.Hash, unminedVal, &unminedRec)
  2127  			if err != nil {
  2128  				return err
  2129  			}
  2130  
  2131  			log.Debugf("Transaction %v spends a removed coinbase "+
  2132  				"output -- removing as well", unminedRec.Hash)
  2133  			err = s.RemoveUnconfirmed(ns, &unminedRec.MsgTx, &unminedRec.Hash)
  2134  			if err != nil {
  2135  				return err
  2136  			}
  2137  		}
  2138  	}
  2139  
  2140  	err = putMinedBalance(ns, minedBalance)
  2141  	if err != nil {
  2142  		return err
  2143  	}
  2144  
  2145  	// Mark block hash for height-1 as the new main chain tip.
  2146  	_, newTipBlockRecord := existsBlockRecord(ns, height-1)
  2147  	newTipHash := extractRawBlockRecordHash(newTipBlockRecord)
  2148  	err = ns.Put(rootTipBlock, newTipHash)
  2149  	if err != nil {
  2150  		return errors.E(errors.IO, err)
  2151  	}
  2152  
  2153  	return nil
  2154  }
  2155  
  2156  // outputCreditInfo fetches information about a credit from the database,
  2157  // fills out a credit struct, and returns it.
  2158  func (s *Store) outputCreditInfo(ns walletdb.ReadBucket, op wire.OutPoint, block *Block) (*Credit, error) {
  2159  	// It has to exists as a credit or an unmined credit.
  2160  	// Look both of these up. If it doesn't, throw an
  2161  	// error. Check unmined first, then mined.
  2162  	var minedCredV []byte
  2163  	unminedCredV := existsRawUnminedCredit(ns,
  2164  		canonicalOutPoint(&op.Hash, op.Index))
  2165  	if unminedCredV == nil {
  2166  		if block != nil {
  2167  			credK := keyCredit(&op.Hash, op.Index, block)
  2168  			minedCredV = existsRawCredit(ns, credK)
  2169  		}
  2170  	}
  2171  	if minedCredV == nil && unminedCredV == nil {
  2172  		return nil, errors.E(errors.IO, errors.Errorf("missing credit for outpoint %v", &op))
  2173  	}
  2174  
  2175  	// Error for DB inconsistency if we find any.
  2176  	if minedCredV != nil && unminedCredV != nil {
  2177  		return nil, errors.E(errors.IO, errors.Errorf("inconsistency: credit %v is marked mined and unmined", &op))
  2178  	}
  2179  
  2180  	var amt dcrutil.Amount
  2181  	var opCode uint8
  2182  	var isCoinbase bool
  2183  	var hasExpiry bool
  2184  	var mined bool
  2185  	var blockTime time.Time
  2186  	var pkScript []byte
  2187  	var receiveTime time.Time
  2188  
  2189  	if unminedCredV != nil {
  2190  		var err error
  2191  		amt, err = fetchRawUnminedCreditAmount(unminedCredV)
  2192  		if err != nil {
  2193  			return nil, err
  2194  		}
  2195  
  2196  		opCode = fetchRawUnminedCreditTagOpCode(unminedCredV)
  2197  		hasExpiry = fetchRawCreditHasExpiry(unminedCredV, DBVersion)
  2198  
  2199  		v := existsRawUnmined(ns, op.Hash[:])
  2200  		received, err := fetchRawUnminedReceiveTime(v)
  2201  		if err != nil {
  2202  			return nil, err
  2203  		}
  2204  		receiveTime = time.Unix(received, 0)
  2205  
  2206  		var tx wire.MsgTx
  2207  		err = tx.Deserialize(bytes.NewReader(extractRawUnminedTx(v)))
  2208  		if err != nil {
  2209  			return nil, errors.E(errors.IO, err)
  2210  		}
  2211  		if op.Index >= uint32(len(tx.TxOut)) {
  2212  			return nil, errors.E(errors.IO, errors.Errorf("no output %d for tx %v", op.Index, &op.Hash))
  2213  		}
  2214  		pkScript = tx.TxOut[op.Index].PkScript
  2215  	} else {
  2216  		mined = true
  2217  
  2218  		var err error
  2219  		amt, err = fetchRawCreditAmount(minedCredV)
  2220  		if err != nil {
  2221  			return nil, err
  2222  		}
  2223  
  2224  		opCode = fetchRawCreditTagOpCode(minedCredV)
  2225  		isCoinbase = fetchRawCreditIsCoinbase(minedCredV)
  2226  		hasExpiry = fetchRawCreditHasExpiry(minedCredV, DBVersion)
  2227  
  2228  		scrLoc := fetchRawCreditScriptOffset(minedCredV)
  2229  		scrLen := fetchRawCreditScriptLength(minedCredV)
  2230  
  2231  		recK, recV := existsTxRecord(ns, &op.Hash, block)
  2232  		receiveTime = fetchRawTxRecordReceived(recV)
  2233  		pkScript, err = fetchRawTxRecordPkScript(recK, recV, op.Index,
  2234  			scrLoc, scrLen)
  2235  		if err != nil {
  2236  			return nil, err
  2237  		}
  2238  	}
  2239  
  2240  	op.Tree = wire.TxTreeRegular
  2241  	if opCode != opNonstake {
  2242  		op.Tree = wire.TxTreeStake
  2243  	}
  2244  
  2245  	c := &Credit{
  2246  		OutPoint: op,
  2247  		BlockMeta: BlockMeta{
  2248  			Block: Block{Height: -1},
  2249  			Time:  blockTime,
  2250  		},
  2251  		Amount:       amt,
  2252  		PkScript:     pkScript,
  2253  		Received:     receiveTime,
  2254  		FromCoinBase: isCoinbase,
  2255  		HasExpiry:    hasExpiry,
  2256  	}
  2257  	if mined {
  2258  		c.BlockMeta.Block = *block
  2259  	}
  2260  	return c, nil
  2261  }
  2262  
  2263  func randUint32() uint32 {
  2264  	b := make([]byte, 4)
  2265  	rand.Read(b[:])
  2266  	return binary.LittleEndian.Uint32(b)
  2267  }
  2268  
  2269  func randUint32n(n uint32) uint32 {
  2270  	if n < 2 {
  2271  		return 0
  2272  	}
  2273  	n--
  2274  	mask := ^uint32(0) >> bits.LeadingZeros32(n)
  2275  	for {
  2276  		v := randUint32() & mask
  2277  		if v <= n {
  2278  			return v
  2279  		}
  2280  	}
  2281  }
  2282  
  2283  func shuffle(n int, swap func(i, j int)) {
  2284  	if n < 0 {
  2285  		panic("shuffle: negative n")
  2286  	}
  2287  	if int64(n) >= 1<<32 {
  2288  		panic("shuffle: large n")
  2289  	}
  2290  
  2291  	// Fisher-Yates shuffle: https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
  2292  	for i := uint32(0); i < uint32(n); i++ {
  2293  		j := randUint32n(uint32(n)-i) + i
  2294  		swap(int(i), int(j))
  2295  	}
  2296  }
  2297  
  2298  // UnspentOutputCount returns the number of mined unspent Credits (including
  2299  // those spent by unmined transactions).
  2300  func (s *Store) UnspentOutputCount(dbtx walletdb.ReadTx) int {
  2301  	ns := dbtx.ReadBucket(wtxmgrBucketKey)
  2302  	return ns.NestedReadBucket(bucketUnspent).KeyN()
  2303  }
  2304  
  2305  // randomUTXO returns a random key/value pair from the unspent bucket, ignoring
  2306  // any keys that match the skip function.
  2307  func (s *Store) randomUTXO(dbtx walletdb.ReadTx, skip func(k, v []byte) bool) (k, v []byte, err error) {
  2308  	ns := dbtx.ReadBucket(wtxmgrBucketKey)
  2309  
  2310  	r := make([]byte, 33)
  2311  	_, err = rand.Read(r)
  2312  	if err != nil {
  2313  		return nil, nil, err
  2314  	}
  2315  	randKey := r[:32]
  2316  	prevFirst := r[32]&1 == 1
  2317  
  2318  	c := ns.NestedReadBucket(bucketUnspent).ReadCursor()
  2319  	k, v = c.Seek(randKey)
  2320  	iter := c.Next
  2321  	if prevFirst {
  2322  		iter = c.Prev
  2323  		k, v = iter()
  2324  	}
  2325  
  2326  	var keys [][]byte
  2327  	for ; k != nil; k, v = iter() {
  2328  		if len(keys) > 0 && !bytes.Equal(keys[0][:32], k[:32]) {
  2329  			break
  2330  		}
  2331  		if skip(k, v) {
  2332  			continue
  2333  		}
  2334  		keys = append(keys, append(make([]byte, 0, 36), k...))
  2335  	}
  2336  	// Pick random output when at least one random transaction was found.
  2337  	if len(keys) > 0 {
  2338  		k, v = c.Seek(keys[randUint32n(uint32(len(keys)))])
  2339  		c.Close()
  2340  		return k, v, nil
  2341  	}
  2342  
  2343  	// Search the opposite direction from the random seek key.
  2344  	if prevFirst {
  2345  		k, v = c.Seek(randKey)
  2346  		iter = c.Next
  2347  	} else {
  2348  		c.Seek(randKey)
  2349  		iter = c.Prev
  2350  		k, v = iter()
  2351  	}
  2352  	for ; k != nil; k, v = iter() {
  2353  		if len(keys) > 0 && !bytes.Equal(keys[0][:32], k[:32]) {
  2354  			break
  2355  		}
  2356  		if skip(k, v) {
  2357  			continue
  2358  		}
  2359  		keys = append(keys, append(make([]byte, 0, 36), k...))
  2360  	}
  2361  	if len(keys) > 0 {
  2362  		k, v = c.Seek(keys[randUint32n(uint32(len(keys)))])
  2363  		c.Close()
  2364  		return k, v, err
  2365  	}
  2366  
  2367  	c.Close()
  2368  	return nil, nil, nil
  2369  }
  2370  
  2371  // RandomUTXO returns a random unspent Credit, or nil if none matching are
  2372  // found.
  2373  //
  2374  // As an optimization to avoid reading all unspent outputs, this method is
  2375  // limited only to mined outputs, and minConf may not be zero.
  2376  func (s *Store) RandomUTXO(dbtx walletdb.ReadTx, minConf, syncHeight int32) (*Credit, error) {
  2377  	ns := dbtx.ReadBucket(wtxmgrBucketKey)
  2378  
  2379  	if minConf == 0 {
  2380  		return nil, errors.E(errors.Invalid,
  2381  			"optimized random utxo selection not possible with minConf=0")
  2382  	}
  2383  
  2384  	skip := func(k, v []byte) bool {
  2385  		if existsRawUnminedInput(ns, k) != nil {
  2386  			// Output is spent by an unmined transaction.
  2387  			return true
  2388  		}
  2389  		var block Block
  2390  		err := readUnspentBlock(v, &block)
  2391  		if err != nil || !confirmed(minConf, block.Height, syncHeight) {
  2392  			return true
  2393  		}
  2394  		return false
  2395  	}
  2396  	k, v, err := s.randomUTXO(dbtx, skip)
  2397  	if k == nil || err != nil {
  2398  		return nil, err
  2399  	}
  2400  	var op wire.OutPoint
  2401  	var block Block
  2402  	err = readCanonicalOutPoint(k, &op)
  2403  	if err != nil {
  2404  		return nil, err
  2405  	}
  2406  	err = readUnspentBlock(v, &block)
  2407  	if err != nil {
  2408  		return nil, err
  2409  	}
  2410  	return s.outputCreditInfo(ns, op, &block)
  2411  }
  2412  
  2413  // UnspentOutputs returns all unspent received transaction outputs.
  2414  // The order is undefined.
  2415  func (s *Store) UnspentOutputs(dbtx walletdb.ReadTx) ([]*Credit, error) {
  2416  	ns := dbtx.ReadBucket(wtxmgrBucketKey)
  2417  	var unspent []*Credit
  2418  
  2419  	var op wire.OutPoint
  2420  	var block Block
  2421  	c := ns.NestedReadBucket(bucketUnspent).ReadCursor()
  2422  	for k, v := c.First(); k != nil; k, v = c.Next() {
  2423  		err := readCanonicalOutPoint(k, &op)
  2424  		if err != nil {
  2425  			c.Close()
  2426  			return nil, err
  2427  		}
  2428  		if existsRawUnminedInput(ns, k) != nil {
  2429  			// Output is spent by an unmined transaction.
  2430  			// Skip this k/v pair.
  2431  			continue
  2432  		}
  2433  
  2434  		err = readUnspentBlock(v, &block)
  2435  		if err != nil {
  2436  			c.Close()
  2437  			return nil, err
  2438  		}
  2439  
  2440  		cred, err := s.outputCreditInfo(ns, op, &block)
  2441  		if err != nil {
  2442  			c.Close()
  2443  			return nil, err
  2444  		}
  2445  
  2446  		unspent = append(unspent, cred)
  2447  	}
  2448  	c.Close()
  2449  
  2450  	c = ns.NestedReadBucket(bucketUnminedCredits).ReadCursor()
  2451  	for k, _ := c.First(); k != nil; k, _ = c.Next() {
  2452  		if existsRawUnminedInput(ns, k) != nil {
  2453  			// Output is spent by an unmined transaction.
  2454  			// Skip to next unmined credit.
  2455  			continue
  2456  		}
  2457  
  2458  		// Skip outputs from unpublished transactions.
  2459  		txHash := k[:32]
  2460  		if existsUnpublished(ns, txHash) {
  2461  			continue
  2462  		}
  2463  
  2464  		err := readCanonicalOutPoint(k, &op)
  2465  		if err != nil {
  2466  			c.Close()
  2467  			return nil, err
  2468  		}
  2469  
  2470  		cred, err := s.outputCreditInfo(ns, op, nil)
  2471  		if err != nil {
  2472  			c.Close()
  2473  			return nil, err
  2474  		}
  2475  
  2476  		unspent = append(unspent, cred)
  2477  	}
  2478  	c.Close()
  2479  
  2480  	log.Tracef("%v many utxos found in database", len(unspent))
  2481  
  2482  	return unspent, nil
  2483  }
  2484  
  2485  // UnspentOutput returns details for an unspent received transaction output.
  2486  // Returns error NotExist if the specified outpoint cannot be found or has been
  2487  // spent by a mined transaction. Mined transactions that are spent by a mempool
  2488  // transaction are not affected by this.
  2489  func (s *Store) UnspentOutput(ns walletdb.ReadBucket, op wire.OutPoint, includeMempool bool) (*Credit, error) {
  2490  	k := canonicalOutPoint(&op.Hash, op.Index)
  2491  	// Check if unspent output is in mempool (if includeMempool == true).
  2492  	if includeMempool && existsRawUnminedCredit(ns, k) != nil {
  2493  		return s.outputCreditInfo(ns, op, nil)
  2494  	}
  2495  	// Check for unspent output in bucket for mined unspents.
  2496  	if v := ns.NestedReadBucket(bucketUnspent).Get(k); v != nil {
  2497  		var block Block
  2498  		err := readUnspentBlock(v, &block)
  2499  		if err != nil {
  2500  			return nil, err
  2501  		}
  2502  		return s.outputCreditInfo(ns, op, &block)
  2503  	}
  2504  	return nil, errors.E(errors.NotExist, errors.Errorf("no unspent output %v", op))
  2505  }
  2506  
  2507  // ForEachUnspentOutpoint calls f on each UTXO outpoint.
  2508  // The order is undefined.
  2509  func (s *Store) ForEachUnspentOutpoint(dbtx walletdb.ReadTx, f func(*wire.OutPoint) error) error {
  2510  	ns := dbtx.ReadBucket(wtxmgrBucketKey)
  2511  	c := ns.NestedReadBucket(bucketUnspent).ReadCursor()
  2512  	defer func() {
  2513  		c.Close()
  2514  	}()
  2515  	for k, v := c.First(); k != nil; k, v = c.Next() {
  2516  		var op wire.OutPoint
  2517  		err := readCanonicalOutPoint(k, &op)
  2518  		if err != nil {
  2519  			return err
  2520  		}
  2521  		if existsRawUnminedInput(ns, k) != nil {
  2522  			// Output is spent by an unmined transaction.
  2523  			// Skip this k/v pair.
  2524  			continue
  2525  		}
  2526  
  2527  		block := new(Block)
  2528  		err = readUnspentBlock(v, block)
  2529  		if err != nil {
  2530  			return err
  2531  		}
  2532  
  2533  		kC := keyCredit(&op.Hash, op.Index, block)
  2534  		vC := existsRawCredit(ns, kC)
  2535  		opCode := fetchRawCreditTagOpCode(vC)
  2536  		op.Tree = wire.TxTreeRegular
  2537  		if opCode != opNonstake {
  2538  			op.Tree = wire.TxTreeStake
  2539  		}
  2540  
  2541  		if err := f(&op); err != nil {
  2542  			return err
  2543  		}
  2544  	}
  2545  
  2546  	c.Close()
  2547  	c = ns.NestedReadBucket(bucketUnminedCredits).ReadCursor()
  2548  	for k, v := c.First(); k != nil; k, v = c.Next() {
  2549  		if existsRawUnminedInput(ns, k) != nil {
  2550  			// Output is spent by an unmined transaction.
  2551  			// Skip to next unmined credit.
  2552  			continue
  2553  		}
  2554  
  2555  		// Skip outputs from unpublished transactions.
  2556  		txHash := k[:32]
  2557  		if existsUnpublished(ns, txHash) {
  2558  			continue
  2559  		}
  2560  
  2561  		var op wire.OutPoint
  2562  		err := readCanonicalOutPoint(k, &op)
  2563  		if err != nil {
  2564  			return err
  2565  		}
  2566  
  2567  		opCode := fetchRawUnminedCreditTagOpCode(v)
  2568  		op.Tree = wire.TxTreeRegular
  2569  		if opCode != opNonstake {
  2570  			op.Tree = wire.TxTreeStake
  2571  		}
  2572  
  2573  		if err := f(&op); err != nil {
  2574  			return err
  2575  		}
  2576  	}
  2577  
  2578  	return nil
  2579  }
  2580  
  2581  // IsUnspentOutpoint returns whether the outpoint is recorded as a wallet UTXO.
  2582  func (s *Store) IsUnspentOutpoint(dbtx walletdb.ReadTx, op *wire.OutPoint) bool {
  2583  	ns := dbtx.ReadBucket(wtxmgrBucketKey)
  2584  
  2585  	// Outputs from unpublished transactions are not UTXOs yet.
  2586  	if existsUnpublished(ns, op.Hash[:]) {
  2587  		return false
  2588  	}
  2589  
  2590  	k := canonicalOutPoint(&op.Hash, op.Index)
  2591  	if v := ns.NestedReadBucket(bucketUnspent); v != nil {
  2592  		// Output is mined and not spent by any other mined tx, but may be spent
  2593  		// by an unmined transaction.
  2594  		return existsRawUnminedInput(ns, k) == nil
  2595  	}
  2596  	if v := existsRawUnminedCredit(ns, k); v != nil {
  2597  		// Output is in an unmined transaction, but may be spent by another
  2598  		// unmined transaction.
  2599  		return existsRawUnminedInput(ns, k) == nil
  2600  	}
  2601  	return false
  2602  }
  2603  
  2604  // UnspentTickets returns all unspent tickets that are known for this wallet.
  2605  // Tickets that have been spent by an unmined vote that is not a vote on the tip
  2606  // block are also considered unspent and are returned.  The order of the hashes
  2607  // is undefined.
  2608  func (s *Store) UnspentTickets(dbtx walletdb.ReadTx, syncHeight int32, includeImmature bool) ([]chainhash.Hash, error) {
  2609  	ns := dbtx.ReadBucket(wtxmgrBucketKey)
  2610  	tipBlock, _ := s.MainChainTip(dbtx)
  2611  	var tickets []chainhash.Hash
  2612  	c := ns.NestedReadBucket(bucketTickets).ReadCursor()
  2613  	defer c.Close()
  2614  	var hash chainhash.Hash
  2615  	for ticketHash, _ := c.First(); ticketHash != nil; ticketHash, _ = c.Next() {
  2616  		copy(hash[:], ticketHash)
  2617  
  2618  		// Skip over tickets that are spent by votes or revocations.  As long as
  2619  		// the ticket is relevant to the wallet, output zero is recorded as a
  2620  		// credit.  Use the credit's spent tracking to determine if the ticket
  2621  		// is spent or not.
  2622  		opKey := canonicalOutPoint(&hash, 0)
  2623  		if existsRawUnspent(ns, opKey) == nil {
  2624  			// No unspent record indicates the output was spent by a mined
  2625  			// transaction.
  2626  			continue
  2627  		}
  2628  		if spenderHash := existsRawUnminedInput(ns, opKey); spenderHash != nil {
  2629  			// A non-nil record for the outpoint indicates that there exists an
  2630  			// unmined transaction that spends the output.  Determine if the
  2631  			// spender is a vote, and append the hash if the vote is not for the
  2632  			// tip block height.  Otherwise continue to the next ticket.
  2633  			serializedSpender := extractRawUnminedTx(existsRawUnmined(ns, spenderHash))
  2634  			if serializedSpender == nil {
  2635  				continue
  2636  			}
  2637  			var spender wire.MsgTx
  2638  			err := spender.Deserialize(bytes.NewReader(serializedSpender))
  2639  			if err != nil {
  2640  				return nil, errors.E(errors.IO, err)
  2641  			}
  2642  			if stake.IsSSGen(&spender) {
  2643  				voteBlock, _ := stake.SSGenBlockVotedOn(&spender)
  2644  				if voteBlock != tipBlock {
  2645  					goto Include
  2646  				}
  2647  			}
  2648  
  2649  			continue
  2650  		}
  2651  
  2652  		// When configured to exclude immature tickets, skip the transaction if
  2653  		// is unmined or has not reached ticket maturity yet.
  2654  		if !includeImmature {
  2655  			txRecKey, _ := latestTxRecord(ns, ticketHash)
  2656  			if txRecKey == nil {
  2657  				continue
  2658  			}
  2659  			var height int32
  2660  			err := readRawTxRecordBlockHeight(txRecKey, &height)
  2661  			if err != nil {
  2662  				return nil, err
  2663  			}
  2664  			if !ticketMatured(s.chainParams, height, syncHeight) {
  2665  				continue
  2666  			}
  2667  		}
  2668  
  2669  	Include:
  2670  		tickets = append(tickets, hash)
  2671  	}
  2672  	return tickets, nil
  2673  }
  2674  
  2675  // OwnTicket returns whether ticketHash is the hash of a ticket purchase
  2676  // transaction managed by the wallet.
  2677  func (s *Store) OwnTicket(dbtx walletdb.ReadTx, ticketHash *chainhash.Hash) bool {
  2678  	ns := dbtx.ReadBucket(wtxmgrBucketKey)
  2679  	v := existsRawTicketRecord(ns, ticketHash[:])
  2680  	return v != nil
  2681  }
  2682  
  2683  // Ticket embeds a TxRecord for a ticket purchase transaction, the block it is
  2684  // mined in (if any), and the transaction hash of the vote or revocation
  2685  // transaction that spends the ticket (if any).
  2686  type Ticket struct {
  2687  	TxRecord
  2688  	Block       Block          // Height -1 if unmined
  2689  	SpenderHash chainhash.Hash // Zero value if unspent
  2690  }
  2691  
  2692  // TicketIterator is used to iterate over all ticket purchase transactions.
  2693  type TicketIterator struct {
  2694  	Ticket
  2695  	ns     walletdb.ReadBucket
  2696  	c      walletdb.ReadCursor
  2697  	ck, cv []byte
  2698  	err    error
  2699  }
  2700  
  2701  // IterateTickets returns an object used to iterate over all ticket purchase
  2702  // transactions.
  2703  func (s *Store) IterateTickets(dbtx walletdb.ReadTx) *TicketIterator {
  2704  	ns := dbtx.ReadBucket(wtxmgrBucketKey)
  2705  	c := ns.NestedReadBucket(bucketTickets).ReadCursor()
  2706  	ck, cv := c.First()
  2707  	return &TicketIterator{ns: ns, c: c, ck: ck, cv: cv}
  2708  }
  2709  
  2710  // Next reads the next Ticket from the database, writing it to the iterator's
  2711  // embedded Ticket member.  Returns false after all tickets have been iterated
  2712  // over or an error occurs.
  2713  func (it *TicketIterator) Next() bool {
  2714  	if it.err != nil {
  2715  		return false
  2716  	}
  2717  
  2718  	// Some tickets may be recorded in the tickets bucket but the transaction
  2719  	// records for them are missing because they were double spent and removed.
  2720  	// Add a label here so that the code below can branch back here to skip to
  2721  	// the next ticket.  This could also be implemented using a for loop, but at
  2722  	// the loss of an indent.
  2723  CheckNext:
  2724  
  2725  	// The cursor value will be nil when all items in the bucket have been
  2726  	// iterated over.
  2727  	if it.cv == nil {
  2728  		return false
  2729  	}
  2730  
  2731  	// Determine whether there is a mined transaction record for the ticket
  2732  	// purchase, an unmined transaction record, or no recorded transaction at
  2733  	// all.
  2734  	var ticketHash chainhash.Hash
  2735  	copy(ticketHash[:], it.ck)
  2736  	if k, v := latestTxRecord(it.ns, it.ck); v != nil {
  2737  		// Ticket is recorded mined
  2738  		err := readRawTxRecordBlock(k, &it.Block)
  2739  		if err != nil {
  2740  			it.err = err
  2741  			return false
  2742  		}
  2743  		err = readRawTxRecord(&ticketHash, v, &it.TxRecord)
  2744  		if err != nil {
  2745  			it.err = err
  2746  			return false
  2747  		}
  2748  
  2749  		// Check if the ticket is spent or not.  Look up the credit for output 0
  2750  		// and check if either a debit is recorded or the output is spent by an
  2751  		// unmined transaction.
  2752  		_, credVal := existsCredit(it.ns, &ticketHash, 0, &it.Block)
  2753  		if credVal != nil {
  2754  			if extractRawCreditIsSpent(credVal) {
  2755  				debKey := extractRawCreditSpenderDebitKey(credVal)
  2756  				debHash := extractRawDebitHash(debKey)
  2757  				copy(it.SpenderHash[:], debHash)
  2758  			} else {
  2759  				it.SpenderHash = chainhash.Hash{}
  2760  			}
  2761  		} else {
  2762  			opKey := canonicalOutPoint(&ticketHash, 0)
  2763  			spenderVal := existsRawUnminedInput(it.ns, opKey)
  2764  			if spenderVal != nil {
  2765  				copy(it.SpenderHash[:], spenderVal)
  2766  			} else {
  2767  				it.SpenderHash = chainhash.Hash{}
  2768  			}
  2769  		}
  2770  	} else if v := existsRawUnmined(it.ns, ticketHash[:]); v != nil {
  2771  		// Ticket is recorded unmined
  2772  		it.Block = Block{Height: -1}
  2773  		// Unmined tickets cannot be spent
  2774  		it.SpenderHash = chainhash.Hash{}
  2775  		err := readRawTxRecord(&ticketHash, v, &it.TxRecord)
  2776  		if err != nil {
  2777  			it.err = err
  2778  			return false
  2779  		}
  2780  	} else {
  2781  		// Transaction was removed, skip to next
  2782  		it.ck, it.cv = it.c.Next()
  2783  		goto CheckNext
  2784  	}
  2785  
  2786  	// Advance the cursor to the next item before returning.  Next expects the
  2787  	// cursor key and value to be set to the next item to read.
  2788  	it.ck, it.cv = it.c.Next()
  2789  
  2790  	return true
  2791  }
  2792  
  2793  // Err returns the final error state of the iterator.  It should be checked
  2794  // after iteration completes when Next returns false.
  2795  func (it *TicketIterator) Err() error { return it.err }
  2796  
  2797  func (it *TicketIterator) Close() {
  2798  	if it.c != nil {
  2799  		it.c.Close()
  2800  	}
  2801  }
  2802  
  2803  // MultisigCredit is a redeemable P2SH multisignature credit.
  2804  type MultisigCredit struct {
  2805  	OutPoint   *wire.OutPoint
  2806  	ScriptHash [ripemd160.Size]byte
  2807  	MSScript   []byte
  2808  	M          uint8
  2809  	N          uint8
  2810  	Amount     dcrutil.Amount
  2811  }
  2812  
  2813  // GetMultisigOutput takes an outpoint and returns multisignature
  2814  // credit data stored about it.
  2815  func (s *Store) GetMultisigOutput(ns walletdb.ReadBucket, op *wire.OutPoint) (*MultisigOut, error) {
  2816  	key := canonicalOutPoint(&op.Hash, op.Index)
  2817  	val := existsMultisigOutCopy(ns, key)
  2818  	if val == nil {
  2819  		return nil, errors.E(errors.NotExist, errors.Errorf("no multisig output for outpoint %v", op))
  2820  	}
  2821  
  2822  	return fetchMultisigOut(key, val)
  2823  }
  2824  
  2825  // UnspentMultisigCreditsForAddress returns all unspent multisignature P2SH
  2826  // credits in the wallet for some specified address.
  2827  func (s *Store) UnspentMultisigCreditsForAddress(dbtx walletdb.ReadTx, addr stdaddr.Address) ([]*MultisigCredit, error) {
  2828  	ns := dbtx.ReadBucket(wtxmgrBucketKey)
  2829  	addrmgrNs := dbtx.ReadBucket(waddrmgrBucketKey)
  2830  
  2831  	p2shAddr, ok := addr.(*stdaddr.AddressScriptHashV0)
  2832  	if !ok {
  2833  		return nil, errors.E(errors.Invalid, "address must be P2SH")
  2834  	}
  2835  	addrScrHash := p2shAddr.Hash160()
  2836  
  2837  	var mscs []*MultisigCredit
  2838  	c := ns.NestedReadBucket(bucketMultisigUsp).ReadCursor()
  2839  	defer c.Close()
  2840  	for k, _ := c.First(); k != nil; k, _ = c.Next() {
  2841  		val := existsMultisigOutCopy(ns, k)
  2842  		if val == nil {
  2843  			return nil, errors.E(errors.IO, "missing multisig credit")
  2844  		}
  2845  
  2846  		// Skip everything that's unrelated to the address
  2847  		// we're concerned about.
  2848  		scriptHash := fetchMultisigOutScrHash(val)
  2849  		if scriptHash != *addrScrHash {
  2850  			continue
  2851  		}
  2852  
  2853  		var op wire.OutPoint
  2854  		err := readCanonicalOutPoint(k, &op)
  2855  		if err != nil {
  2856  			return nil, err
  2857  		}
  2858  
  2859  		multisigScript, err := s.manager.redeemScriptForHash160(addrmgrNs, scriptHash[:])
  2860  		if err != nil {
  2861  			return nil, err
  2862  		}
  2863  		m, n := fetchMultisigOutMN(val)
  2864  		amount := fetchMultisigOutAmount(val)
  2865  		op.Tree = fetchMultisigOutTree(val)
  2866  
  2867  		msc := &MultisigCredit{
  2868  			&op,
  2869  			scriptHash,
  2870  			multisigScript,
  2871  			m,
  2872  			n,
  2873  			amount,
  2874  		}
  2875  		mscs = append(mscs, msc)
  2876  	}
  2877  
  2878  	return mscs, nil
  2879  }
  2880  
  2881  type minimalCredit struct {
  2882  	txRecordKey []byte
  2883  	index       uint32
  2884  	Amount      int64
  2885  	tree        int8
  2886  	unmined     bool
  2887  }
  2888  
  2889  // byUtxoAmount defines the methods needed to satisify sort.Interface to
  2890  // sort a slice of Utxos by their amount.
  2891  type byUtxoAmount []*minimalCredit
  2892  
  2893  func (u byUtxoAmount) Len() int           { return len(u) }
  2894  func (u byUtxoAmount) Less(i, j int) bool { return u[i].Amount < u[j].Amount }
  2895  func (u byUtxoAmount) Swap(i, j int)      { u[i], u[j] = u[j], u[i] }
  2896  
  2897  // confirmed checks whether a transaction at height txHeight has met minConf
  2898  // confirmations for a blockchain at height curHeight.
  2899  func confirmed(minConf, txHeight, curHeight int32) bool {
  2900  	return confirms(txHeight, curHeight) >= minConf
  2901  }
  2902  
  2903  // confirms returns the number of confirmations for a transaction in a block at
  2904  // height txHeight (or -1 for an unconfirmed tx) given the chain height
  2905  // curHeight.
  2906  func confirms(txHeight, curHeight int32) int32 {
  2907  	switch {
  2908  	case txHeight == -1, txHeight > curHeight:
  2909  		return 0
  2910  	default:
  2911  		return curHeight - txHeight + 1
  2912  	}
  2913  }
  2914  
  2915  // coinbaseMatured returns whether a transaction mined at txHeight has
  2916  // reached coinbase maturity in a chain with tip height curHeight.
  2917  func coinbaseMatured(params *chaincfg.Params, txHeight, curHeight int32) bool {
  2918  	return txHeight >= 0 && curHeight-txHeight+1 > int32(params.CoinbaseMaturity)
  2919  }
  2920  
  2921  // ticketChangeMatured returns whether a ticket change mined at
  2922  // txHeight has reached ticket maturity in a chain with a tip height
  2923  // curHeight.
  2924  func ticketChangeMatured(params *chaincfg.Params, txHeight, curHeight int32) bool {
  2925  	return txHeight >= 0 && curHeight-txHeight+1 > int32(params.SStxChangeMaturity)
  2926  }
  2927  
  2928  // ticketMatured returns whether a ticket mined at txHeight has
  2929  // reached ticket maturity in a chain with a tip height curHeight.
  2930  func ticketMatured(params *chaincfg.Params, txHeight, curHeight int32) bool {
  2931  	// dcrd has an off-by-one in the calculation of the ticket
  2932  	// maturity, which results in maturity being one block higher
  2933  	// than the params would indicate.
  2934  	return txHeight >= 0 && curHeight-txHeight > int32(params.TicketMaturity)
  2935  }
  2936  
  2937  func (s *Store) fastCreditPkScriptLookup(ns walletdb.ReadBucket, credKey []byte, unminedCredKey []byte) ([]byte, error) {
  2938  	// It has to exists as a credit or an unmined credit.
  2939  	// Look both of these up. If it doesn't, throw an
  2940  	// error. Check unmined first, then mined.
  2941  	var minedCredV []byte
  2942  	unminedCredV := existsRawUnminedCredit(ns, unminedCredKey)
  2943  	if unminedCredV == nil {
  2944  		minedCredV = existsRawCredit(ns, credKey)
  2945  	}
  2946  	if minedCredV == nil && unminedCredV == nil {
  2947  		return nil, errors.E(errors.IO, "missing mined and unmined credit")
  2948  	}
  2949  
  2950  	if unminedCredV != nil { // unmined
  2951  		var op wire.OutPoint
  2952  		err := readCanonicalOutPoint(unminedCredKey, &op)
  2953  		if err != nil {
  2954  			return nil, err
  2955  		}
  2956  		k := op.Hash[:]
  2957  		v := existsRawUnmined(ns, k)
  2958  		var tx wire.MsgTx
  2959  		err = tx.Deserialize(bytes.NewReader(extractRawUnminedTx(v)))
  2960  		if err != nil {
  2961  			return nil, errors.E(errors.IO, err)
  2962  		}
  2963  		if op.Index >= uint32(len(tx.TxOut)) {
  2964  			return nil, errors.E(errors.IO, errors.Errorf("no output %d for tx %v", op.Index, &op.Hash))
  2965  		}
  2966  		return tx.TxOut[op.Index].PkScript, nil
  2967  	}
  2968  
  2969  	scrLoc := fetchRawCreditScriptOffset(minedCredV)
  2970  	scrLen := fetchRawCreditScriptLength(minedCredV)
  2971  
  2972  	k := extractRawCreditTxRecordKey(credKey)
  2973  	v := existsRawTxRecord(ns, k)
  2974  	idx := extractRawCreditIndex(credKey)
  2975  	return fetchRawTxRecordPkScript(k, v, idx, scrLoc, scrLen)
  2976  }
  2977  
  2978  // minimalCreditToCredit looks up a minimal credit's data and prepares a Credit
  2979  // from this data.
  2980  func (s *Store) minimalCreditToCredit(ns walletdb.ReadBucket, mc *minimalCredit) (*Credit, error) {
  2981  	var cred *Credit
  2982  
  2983  	switch mc.unmined {
  2984  	case false: // Mined transactions.
  2985  		opHash, err := chainhash.NewHash(mc.txRecordKey[0:32])
  2986  		if err != nil {
  2987  			return nil, err
  2988  		}
  2989  
  2990  		var block Block
  2991  		err = readUnspentBlock(mc.txRecordKey[32:68], &block)
  2992  		if err != nil {
  2993  			return nil, err
  2994  		}
  2995  
  2996  		var op wire.OutPoint
  2997  		op.Hash = *opHash
  2998  		op.Index = mc.index
  2999  
  3000  		cred, err = s.outputCreditInfo(ns, op, &block)
  3001  		if err != nil {
  3002  			return nil, err
  3003  		}
  3004  
  3005  	case true: // Unmined transactions.
  3006  		opHash, err := chainhash.NewHash(mc.txRecordKey[0:32])
  3007  		if err != nil {
  3008  			return nil, err
  3009  		}
  3010  
  3011  		var op wire.OutPoint
  3012  		op.Hash = *opHash
  3013  		op.Index = mc.index
  3014  
  3015  		cred, err = s.outputCreditInfo(ns, op, nil)
  3016  		if err != nil {
  3017  			return nil, err
  3018  		}
  3019  	}
  3020  
  3021  	return cred, nil
  3022  }
  3023  
  3024  // InputSource provides a method (SelectInputs) to incrementally select unspent
  3025  // outputs to use as transaction inputs.
  3026  type InputSource struct {
  3027  	source func(dcrutil.Amount) (*txauthor.InputDetail, error)
  3028  }
  3029  
  3030  // SelectInputs selects transaction inputs to redeem unspent outputs stored in
  3031  // the database.  It may be called multiple times with increasing target amounts
  3032  // to return additional inputs for a higher target amount.  It returns the total
  3033  // input amount referenced by the previous transaction outputs, a slice of
  3034  // transaction inputs referencing these outputs, and a slice of previous output
  3035  // scripts from each previous output referenced by the corresponding input.
  3036  func (s *InputSource) SelectInputs(target dcrutil.Amount) (*txauthor.InputDetail, error) {
  3037  	return s.source(target)
  3038  }
  3039  
  3040  // MakeInputSource creates an InputSource to redeem unspent outputs from an
  3041  // account.  The minConf and syncHeight parameters are used to filter outputs
  3042  // based on some spendable policy.  An ignore func is called to determine whether
  3043  // an output must be excluded from the source, and may be nil to ignore nothing.
  3044  func (s *Store) MakeInputSource(dbtx walletdb.ReadTx, account uint32, minConf,
  3045  	syncHeight int32, ignore func(*wire.OutPoint) bool) InputSource {
  3046  
  3047  	ns := dbtx.ReadBucket(wtxmgrBucketKey)
  3048  	addrmgrNs := dbtx.ReadBucket(waddrmgrBucketKey)
  3049  
  3050  	// Cursors to iterate over the (mined) unspent and unmined credit
  3051  	// buckets.  These are closed over by the returned input source and
  3052  	// reused across multiple calls.
  3053  	//
  3054  	// These cursors are initialized to nil and are set to a valid cursor
  3055  	// when first needed.  This is done since cursors are not positioned
  3056  	// when created, and positioning a cursor also returns a key/value pair.
  3057  	// The simplest way to handle this is to branch to either cursor.First
  3058  	// or cursor.Next depending on whether the cursor has already been
  3059  	// created or not.
  3060  	var bucketUnspentCursor, bucketUnminedCreditsCursor walletdb.ReadCursor
  3061  
  3062  	defer func() {
  3063  		if bucketUnspentCursor != nil {
  3064  			bucketUnspentCursor.Close()
  3065  			bucketUnspentCursor = nil
  3066  		}
  3067  
  3068  		if bucketUnminedCreditsCursor != nil {
  3069  			bucketUnminedCreditsCursor.Close()
  3070  			bucketUnminedCreditsCursor = nil
  3071  		}
  3072  	}()
  3073  
  3074  	type remainingKey struct {
  3075  		k       []byte
  3076  		unmined bool
  3077  	}
  3078  
  3079  	// Current inputs and their total value.  These are closed over by the
  3080  	// returned input source and reused across multiple calls.
  3081  	var (
  3082  		currentTotal      dcrutil.Amount
  3083  		currentInputs     []*wire.TxIn
  3084  		currentScripts    [][]byte
  3085  		redeemScriptSizes []int
  3086  		seen              = make(map[string]struct{}) // random unspent bucket keys
  3087  		numUnspent        = ns.NestedReadBucket(bucketUnspent).KeyN()
  3088  		randTries         int
  3089  		remainingKeys     []remainingKey
  3090  	)
  3091  
  3092  	if minConf != 0 {
  3093  		log.Debugf("Unspent bucket k/v count: %v", numUnspent)
  3094  	}
  3095  
  3096  	skip := func(k, v []byte) bool {
  3097  		if existsRawUnminedInput(ns, k) != nil {
  3098  			// Output is spent by an unmined transaction.
  3099  			// Skip to next unmined credit.
  3100  			return true
  3101  		}
  3102  		var block Block
  3103  		err := readUnspentBlock(v, &block)
  3104  		if err != nil || !confirmed(minConf, block.Height, syncHeight) {
  3105  			return true
  3106  		}
  3107  		if _, ok := seen[string(k)]; ok {
  3108  			// already found by the random search
  3109  			return true
  3110  		}
  3111  		return false
  3112  	}
  3113  
  3114  	f := func(target dcrutil.Amount) (*txauthor.InputDetail, error) {
  3115  		for currentTotal < target || target == 0 {
  3116  			var k, v []byte
  3117  			var err error
  3118  			if minConf != 0 && target != 0 && randTries < numUnspent/2 {
  3119  				randTries++
  3120  				k, v, err = s.randomUTXO(dbtx, skip)
  3121  				if k != nil {
  3122  					seen[string(k)] = struct{}{}
  3123  				}
  3124  			} else if remainingKeys == nil {
  3125  				if randTries > 0 {
  3126  					log.Debugf("Abandoned random UTXO selection "+
  3127  						"attempts after %v tries", randTries)
  3128  				}
  3129  				// All remaining keys not discovered by the
  3130  				// random search (if any was performed) are read
  3131  				// into memory and shuffled, and then iterated
  3132  				// over.
  3133  				remainingKeys = make([]remainingKey, 0)
  3134  				b := ns.NestedReadBucket(bucketUnspent)
  3135  				err = b.ForEach(func(k, v []byte) error {
  3136  					if skip(k, v) {
  3137  						return nil
  3138  					}
  3139  					kcopy := make([]byte, len(k))
  3140  					copy(kcopy, k)
  3141  					remainingKeys = append(remainingKeys, remainingKey{
  3142  						k: kcopy,
  3143  					})
  3144  					return nil
  3145  				})
  3146  				if err != nil {
  3147  					return nil, err
  3148  				}
  3149  				if minConf == 0 {
  3150  					b = ns.NestedReadBucket(bucketUnminedCredits)
  3151  					err = b.ForEach(func(k, v []byte) error {
  3152  						if _, ok := seen[string(k)]; ok {
  3153  							return nil
  3154  						}
  3155  						// Skip unmined outputs from unpublished transactions.
  3156  						if txHash := k[:32]; existsUnpublished(ns, txHash) {
  3157  							return nil
  3158  						}
  3159  						// Skip ticket outputs, as only SSGen can spend these.
  3160  						opcode := fetchRawUnminedCreditTagOpCode(v)
  3161  						if opcode == txscript.OP_SSTX {
  3162  							return nil
  3163  						}
  3164  						// Skip outputs that are not mature.
  3165  						switch opcode {
  3166  						case txscript.OP_SSGEN, txscript.OP_SSTXCHANGE, txscript.OP_SSRTX,
  3167  							txscript.OP_TADD, txscript.OP_TGEN:
  3168  							return nil
  3169  						}
  3170  
  3171  						kcopy := make([]byte, len(k))
  3172  						copy(kcopy, k)
  3173  						remainingKeys = append(remainingKeys, remainingKey{
  3174  							k:       kcopy,
  3175  							unmined: true,
  3176  						})
  3177  						return nil
  3178  					})
  3179  					if err != nil {
  3180  						return nil, err
  3181  					}
  3182  				}
  3183  				shuffle(len(remainingKeys), func(i, j int) {
  3184  					remainingKeys[i], remainingKeys[j] = remainingKeys[j], remainingKeys[i]
  3185  				})
  3186  			}
  3187  
  3188  			var unmined bool
  3189  			if k == nil {
  3190  				if len(remainingKeys) == 0 {
  3191  					// No more UTXOs available.
  3192  					break
  3193  				}
  3194  				next := remainingKeys[0]
  3195  				remainingKeys = remainingKeys[1:]
  3196  				k, unmined = next.k, next.unmined
  3197  			}
  3198  			if !unmined {
  3199  				v = ns.NestedReadBucket(bucketUnspent).Get(k)
  3200  			} else {
  3201  				v = ns.NestedReadBucket(bucketUnminedCredits).Get(k)
  3202  			}
  3203  
  3204  			tree := wire.TxTreeRegular
  3205  			var op wire.OutPoint
  3206  			var amt dcrutil.Amount
  3207  			var pkScript []byte
  3208  
  3209  			if !unmined {
  3210  				cKey := make([]byte, 72)
  3211  				copy(cKey[0:32], k[0:32])   // Tx hash
  3212  				copy(cKey[32:36], v[0:4])   // Block height
  3213  				copy(cKey[36:68], v[4:36])  // Block hash
  3214  				copy(cKey[68:72], k[32:36]) // Output index
  3215  
  3216  				cVal := existsRawCredit(ns, cKey)
  3217  
  3218  				// Check the account first.
  3219  				pkScript, err = s.fastCreditPkScriptLookup(ns, cKey, nil)
  3220  				if err != nil {
  3221  					return nil, err
  3222  				}
  3223  				thisAcct, err := s.fetchAccountForPkScript(addrmgrNs, cVal, nil, pkScript)
  3224  				if err != nil {
  3225  					return nil, err
  3226  				}
  3227  				if account != thisAcct {
  3228  					continue
  3229  				}
  3230  
  3231  				var spent bool
  3232  				amt, spent, err = fetchRawCreditAmountSpent(cVal)
  3233  				if err != nil {
  3234  					return nil, err
  3235  				}
  3236  
  3237  				// This should never happen since this is already in bucket
  3238  				// unspent, but let's be careful anyway.
  3239  				if spent {
  3240  					continue
  3241  				}
  3242  
  3243  				// Skip zero value outputs.
  3244  				if amt == 0 {
  3245  					continue
  3246  				}
  3247  
  3248  				// Skip ticket outputs, as only SSGen can spend these.
  3249  				opcode := fetchRawCreditTagOpCode(cVal)
  3250  				if opcode == txscript.OP_SSTX {
  3251  					continue
  3252  				}
  3253  
  3254  				// Only include this output if it meets the required number of
  3255  				// confirmations.  Coinbase transactions must have have reached
  3256  				// maturity before their outputs may be spent.
  3257  				txHeight := extractRawCreditHeight(cKey)
  3258  				if !confirmed(minConf, txHeight, syncHeight) {
  3259  					continue
  3260  				}
  3261  
  3262  				// Skip outputs that are not mature.
  3263  				if opcode == opNonstake && fetchRawCreditIsCoinbase(cVal) {
  3264  					if !coinbaseMatured(s.chainParams, txHeight, syncHeight) {
  3265  						continue
  3266  					}
  3267  				}
  3268  				switch opcode {
  3269  				case txscript.OP_SSGEN, txscript.OP_SSRTX, txscript.OP_TADD,
  3270  					txscript.OP_TGEN:
  3271  					if !coinbaseMatured(s.chainParams, txHeight, syncHeight) {
  3272  						continue
  3273  					}
  3274  				}
  3275  				if opcode == txscript.OP_SSTXCHANGE {
  3276  					if !ticketChangeMatured(s.chainParams, txHeight, syncHeight) {
  3277  						continue
  3278  					}
  3279  				}
  3280  
  3281  				// Determine the txtree for the outpoint by whether or not it's
  3282  				// using stake tagged outputs.
  3283  				if opcode != opNonstake {
  3284  					tree = wire.TxTreeStake
  3285  				}
  3286  
  3287  				err = readCanonicalOutPoint(k, &op)
  3288  				if err != nil {
  3289  					return nil, err
  3290  				}
  3291  				op.Tree = tree
  3292  
  3293  			} else {
  3294  				// Check the account first.
  3295  				pkScript, err = s.fastCreditPkScriptLookup(ns, nil, k)
  3296  				if err != nil {
  3297  					return nil, err
  3298  				}
  3299  				thisAcct, err := s.fetchAccountForPkScript(addrmgrNs, nil, v, pkScript)
  3300  				if err != nil {
  3301  					return nil, err
  3302  				}
  3303  				if account != thisAcct {
  3304  					continue
  3305  				}
  3306  
  3307  				amt, err = fetchRawUnminedCreditAmount(v)
  3308  				if err != nil {
  3309  					return nil, err
  3310  				}
  3311  
  3312  				// Determine the txtree for the outpoint by whether or not it's
  3313  				// using stake tagged outputs.
  3314  				tree = wire.TxTreeRegular
  3315  				opcode := fetchRawUnminedCreditTagOpCode(v)
  3316  				if opcode != opNonstake {
  3317  					tree = wire.TxTreeStake
  3318  				}
  3319  
  3320  				err = readCanonicalOutPoint(k, &op)
  3321  				if err != nil {
  3322  					return nil, err
  3323  				}
  3324  				op.Tree = tree
  3325  			}
  3326  
  3327  			if ignore != nil && ignore(&op) {
  3328  				continue
  3329  			}
  3330  
  3331  			input := wire.NewTxIn(&op, int64(amt), nil)
  3332  
  3333  			// Unspent credits are currently expected to be either P2PKH or
  3334  			// P2PK, P2PKH/P2SH nested in a revocation/stakechange/vote output.
  3335  			// Ignore stake P2SH since it can pay to any script, which the
  3336  			// wallet may not recognize.
  3337  			var scriptSize int
  3338  			scriptClass := stdscript.DetermineScriptType(scriptVersionAssumed, pkScript)
  3339  			scriptSubClass, _ := txrules.StakeSubScriptType(scriptClass)
  3340  			switch scriptSubClass {
  3341  			case stdscript.STPubKeyHashEcdsaSecp256k1:
  3342  				scriptSize = txsizes.RedeemP2PKHSigScriptSize
  3343  			case stdscript.STPubKeyEcdsaSecp256k1:
  3344  				scriptSize = txsizes.RedeemP2PKSigScriptSize
  3345  			default:
  3346  				log.Errorf("unexpected script class for credit: %v", scriptClass)
  3347  				continue
  3348  			}
  3349  
  3350  			currentTotal += amt
  3351  			currentInputs = append(currentInputs, input)
  3352  			currentScripts = append(currentScripts, pkScript)
  3353  			redeemScriptSizes = append(redeemScriptSizes, scriptSize)
  3354  		}
  3355  
  3356  		inputDetail := &txauthor.InputDetail{
  3357  			Amount:            currentTotal,
  3358  			Inputs:            currentInputs,
  3359  			Scripts:           currentScripts,
  3360  			RedeemScriptSizes: redeemScriptSizes,
  3361  		}
  3362  
  3363  		return inputDetail, nil
  3364  	}
  3365  
  3366  	return InputSource{source: f}
  3367  }
  3368  
  3369  // balanceFullScan does a fullscan of the UTXO set to get the current balance.
  3370  // It is less efficient than the other balance functions, but works fine for
  3371  // accounts.
  3372  func (s *Store) balanceFullScan(dbtx walletdb.ReadTx, minConf int32, syncHeight int32) (map[uint32]*Balances, error) {
  3373  	ns := dbtx.ReadBucket(wtxmgrBucketKey)
  3374  	addrmgrNs := dbtx.ReadBucket(waddrmgrBucketKey)
  3375  
  3376  	accountBalances := make(map[uint32]*Balances)
  3377  	c := ns.NestedReadBucket(bucketUnspent).ReadCursor()
  3378  	for k, v := c.First(); k != nil; k, v = c.Next() {
  3379  		if existsRawUnminedInput(ns, k) != nil {
  3380  			// Output is spent by an unmined transaction.
  3381  			// Skip to next unmined credit.
  3382  			continue
  3383  		}
  3384  
  3385  		cKey := make([]byte, 72)
  3386  		copy(cKey[0:32], k[0:32])   // Tx hash
  3387  		copy(cKey[32:36], v[0:4])   // Block height
  3388  		copy(cKey[36:68], v[4:36])  // Block hash
  3389  		copy(cKey[68:72], k[32:36]) // Output index
  3390  
  3391  		cVal := existsRawCredit(ns, cKey)
  3392  		if cVal == nil {
  3393  			c.Close()
  3394  			return nil, errors.E(errors.IO, "missing credit for unspent output")
  3395  		}
  3396  
  3397  		// Check the account first.
  3398  		pkScript, err := s.fastCreditPkScriptLookup(ns, cKey, nil)
  3399  		if err != nil {
  3400  			c.Close()
  3401  			return nil, err
  3402  		}
  3403  		thisAcct, err := s.fetchAccountForPkScript(addrmgrNs, cVal, nil, pkScript)
  3404  		if err != nil {
  3405  			c.Close()
  3406  			return nil, err
  3407  		}
  3408  
  3409  		utxoAmt, err := fetchRawCreditAmount(cVal)
  3410  		if err != nil {
  3411  			c.Close()
  3412  			return nil, err
  3413  		}
  3414  
  3415  		height := extractRawCreditHeight(cKey)
  3416  		opcode := fetchRawCreditTagOpCode(cVal)
  3417  
  3418  		ab, ok := accountBalances[thisAcct]
  3419  		if !ok {
  3420  			ab = &Balances{
  3421  				Account: thisAcct,
  3422  			}
  3423  			accountBalances[thisAcct] = ab
  3424  		}
  3425  
  3426  		switch opcode {
  3427  		case txscript.OP_TGEN:
  3428  			// Or add another type of balance?
  3429  			fallthrough
  3430  		case opNonstake:
  3431  			isConfirmed := confirmed(minConf, height, syncHeight)
  3432  			creditFromCoinbase := fetchRawCreditIsCoinbase(cVal)
  3433  			matureCoinbase := (creditFromCoinbase &&
  3434  				coinbaseMatured(s.chainParams, height, syncHeight))
  3435  
  3436  			if (isConfirmed && !creditFromCoinbase) ||
  3437  				matureCoinbase {
  3438  				ab.Spendable += utxoAmt
  3439  			} else if creditFromCoinbase && !matureCoinbase {
  3440  				ab.ImmatureCoinbaseRewards += utxoAmt
  3441  			}
  3442  
  3443  			ab.Total += utxoAmt
  3444  		case txscript.OP_SSTX:
  3445  			ab.VotingAuthority += utxoAmt
  3446  		case txscript.OP_SSGEN:
  3447  			fallthrough
  3448  		case txscript.OP_SSRTX:
  3449  			if coinbaseMatured(s.chainParams, height, syncHeight) {
  3450  				ab.Spendable += utxoAmt
  3451  			} else {
  3452  				ab.ImmatureStakeGeneration += utxoAmt
  3453  			}
  3454  
  3455  			ab.Total += utxoAmt
  3456  		case txscript.OP_SSTXCHANGE:
  3457  			if ticketChangeMatured(s.chainParams, height, syncHeight) {
  3458  				ab.Spendable += utxoAmt
  3459  			}
  3460  
  3461  			ab.Total += utxoAmt
  3462  		default:
  3463  			log.Warnf("Unhandled opcode: %v", opcode)
  3464  		}
  3465  	}
  3466  
  3467  	c.Close()
  3468  
  3469  	// Unconfirmed transaction output handling.
  3470  	c = ns.NestedReadBucket(bucketUnminedCredits).ReadCursor()
  3471  	defer c.Close()
  3472  	for k, v := c.First(); k != nil; k, v = c.Next() {
  3473  		// Make sure this output was not spent by an unmined transaction.
  3474  		// If it was, skip this credit.
  3475  		if existsRawUnminedInput(ns, k) != nil {
  3476  			continue
  3477  		}
  3478  
  3479  		// Check the account first.
  3480  		pkScript, err := s.fastCreditPkScriptLookup(ns, nil, k)
  3481  		if err != nil {
  3482  			return nil, err
  3483  		}
  3484  		thisAcct, err := s.fetchAccountForPkScript(addrmgrNs, nil, v, pkScript)
  3485  		if err != nil {
  3486  			return nil, err
  3487  		}
  3488  
  3489  		utxoAmt, err := fetchRawUnminedCreditAmount(v)
  3490  		if err != nil {
  3491  			return nil, err
  3492  		}
  3493  
  3494  		ab, ok := accountBalances[thisAcct]
  3495  		if !ok {
  3496  			ab = &Balances{
  3497  				Account: thisAcct,
  3498  			}
  3499  			accountBalances[thisAcct] = ab
  3500  		}
  3501  		// Skip ticket outputs, as only SSGen can spend these.
  3502  		opcode := fetchRawUnminedCreditTagOpCode(v)
  3503  
  3504  		txHash := k[:32]
  3505  		unpublished := existsUnpublished(ns, txHash)
  3506  
  3507  		switch opcode {
  3508  		case opNonstake:
  3509  			if minConf == 0 && !unpublished {
  3510  				ab.Spendable += utxoAmt
  3511  			} else if !fetchRawCreditIsCoinbase(v) {
  3512  				ab.Unconfirmed += utxoAmt
  3513  			}
  3514  			ab.Total += utxoAmt
  3515  		case txscript.OP_SSTX:
  3516  			ab.VotingAuthority += utxoAmt
  3517  		case txscript.OP_SSGEN:
  3518  			fallthrough
  3519  		case txscript.OP_SSRTX:
  3520  			ab.ImmatureStakeGeneration += utxoAmt
  3521  			ab.Total += utxoAmt
  3522  		case txscript.OP_SSTXCHANGE:
  3523  			ab.Total += utxoAmt
  3524  			continue
  3525  		case txscript.OP_TGEN:
  3526  			// Only consider mined tspends for simpler balance
  3527  			// accounting.
  3528  		default:
  3529  			log.Warnf("Unhandled unconfirmed opcode %v: %v", opcode, v)
  3530  		}
  3531  	}
  3532  
  3533  	// Account for ticket commitments by iterating over the unspent commitments
  3534  	// index.
  3535  	it := makeUnspentTicketCommitsIterator(ns)
  3536  	for it.next() {
  3537  		if it.err != nil {
  3538  			return nil, it.err
  3539  		}
  3540  
  3541  		if it.unminedSpent {
  3542  			// Some unmined tx is redeeming this commitment, so ignore it for
  3543  			// balance purposes.
  3544  			continue
  3545  		}
  3546  
  3547  		ab, ok := accountBalances[it.account]
  3548  		if !ok {
  3549  			ab = &Balances{
  3550  				Account: it.account,
  3551  			}
  3552  			accountBalances[it.account] = ab
  3553  		}
  3554  
  3555  		ab.LockedByTickets += it.amount
  3556  		ab.Total += it.amount
  3557  	}
  3558  	it.close()
  3559  
  3560  	return accountBalances, nil
  3561  }
  3562  
  3563  // Balances is an convenience type.
  3564  type Balances = struct {
  3565  	Account                 uint32
  3566  	ImmatureCoinbaseRewards dcrutil.Amount
  3567  	ImmatureStakeGeneration dcrutil.Amount
  3568  	LockedByTickets         dcrutil.Amount
  3569  	Spendable               dcrutil.Amount
  3570  	Total                   dcrutil.Amount
  3571  	VotingAuthority         dcrutil.Amount
  3572  	Unconfirmed             dcrutil.Amount
  3573  }
  3574  
  3575  // AccountBalance returns a Balances struct for some given account at
  3576  // syncHeight block height with all UTXOS that have minConf manyn confirms.
  3577  func (s *Store) AccountBalance(dbtx walletdb.ReadTx, minConf int32, account uint32) (Balances, error) {
  3578  	balances, err := s.AccountBalances(dbtx, minConf)
  3579  	if err != nil {
  3580  		return Balances{}, err
  3581  	}
  3582  
  3583  	balance, ok := balances[account]
  3584  	if !ok {
  3585  		// No balance for the account was found so must be zero.
  3586  		return Balances{
  3587  			Account: account,
  3588  		}, nil
  3589  	}
  3590  
  3591  	return *balance, nil
  3592  }
  3593  
  3594  // AccountBalances returns a map of all account balances at syncHeight block
  3595  // height with all UTXOs that have minConf many confirms.
  3596  func (s *Store) AccountBalances(dbtx walletdb.ReadTx, minConf int32) (map[uint32]*Balances, error) {
  3597  	_, syncHeight := s.MainChainTip(dbtx)
  3598  	return s.balanceFullScan(dbtx, minConf, syncHeight)
  3599  }