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

     1  // Copyright (c) 2015 The btcsuite developers
     2  // Copyright (c) 2015-2017 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  	"context"
    11  
    12  	"decred.org/dcrwallet/v3/errors"
    13  	"decred.org/dcrwallet/v3/wallet/walletdb"
    14  	"github.com/decred/dcrd/blockchain/stake/v5"
    15  	"github.com/decred/dcrd/chaincfg/chainhash"
    16  	"github.com/decred/dcrd/dcrutil/v4"
    17  	"github.com/decred/dcrd/wire"
    18  )
    19  
    20  // CreditRecord contains metadata regarding a transaction credit for a known
    21  // transaction.  Further details may be looked up by indexing a wire.MsgTx.TxOut
    22  // with the Index field.
    23  type CreditRecord struct {
    24  	Index      uint32
    25  	Amount     dcrutil.Amount
    26  	Spent      bool
    27  	Change     bool
    28  	OpCode     uint8
    29  	IsCoinbase bool
    30  	HasExpiry  bool
    31  }
    32  
    33  // DebitRecord contains metadata regarding a transaction debit for a known
    34  // transaction.  Further details may be looked up by indexing a wire.MsgTx.TxIn
    35  // with the Index field.
    36  type DebitRecord struct {
    37  	Amount dcrutil.Amount
    38  	Index  uint32
    39  }
    40  
    41  // TxDetails is intended to provide callers with access to rich details
    42  // regarding a relevant transaction and which inputs and outputs are credit or
    43  // debits.
    44  type TxDetails struct {
    45  	TxRecord
    46  	Block   BlockMeta
    47  	Credits []CreditRecord
    48  	Debits  []DebitRecord
    49  }
    50  
    51  // Height returns the height of a transaction according to the BlockMeta.
    52  func (t *TxDetails) Height() int32 {
    53  	return t.Block.Block.Height
    54  }
    55  
    56  // minedTxDetails fetches the TxDetails for the mined transaction with hash
    57  // txHash and the passed tx record key and value.
    58  func (s *Store) minedTxDetails(ns walletdb.ReadBucket, txHash *chainhash.Hash, recKey, recVal []byte) (*TxDetails, error) {
    59  	var details TxDetails
    60  
    61  	// Parse transaction record k/v, lookup the full block record for the
    62  	// block time, and read all matching credits, debits.
    63  	err := readRawTxRecord(txHash, recVal, &details.TxRecord)
    64  	if err != nil {
    65  		return nil, err
    66  	}
    67  	err = readRawTxRecordBlock(recKey, &details.Block.Block)
    68  	if err != nil {
    69  		return nil, err
    70  	}
    71  	details.Block.Time, err = fetchBlockTime(ns, details.Block.Height)
    72  	if err != nil {
    73  		return nil, err
    74  	}
    75  
    76  	credIter := makeReadCreditIterator(ns, recKey, DBVersion)
    77  	for credIter.next() {
    78  		if int(credIter.elem.Index) >= len(details.MsgTx.TxOut) {
    79  			credIter.close()
    80  			return nil, errors.E(errors.IO, "saved credit index exceeds number of outputs")
    81  		}
    82  
    83  		// The credit iterator does not record whether this credit was
    84  		// spent by an unmined transaction, so check that here.
    85  		if !credIter.elem.Spent {
    86  			k := canonicalOutPoint(txHash, credIter.elem.Index)
    87  			spent := existsRawUnminedInput(ns, k) != nil
    88  			credIter.elem.Spent = spent
    89  		}
    90  		details.Credits = append(details.Credits, credIter.elem)
    91  	}
    92  	credIter.close()
    93  	if credIter.err != nil {
    94  		return nil, credIter.err
    95  	}
    96  
    97  	debIter := makeReadDebitIterator(ns, recKey)
    98  	defer debIter.close()
    99  	for debIter.next() {
   100  		if int(debIter.elem.Index) >= len(details.MsgTx.TxIn) {
   101  			return nil, errors.E(errors.IO, "saved debit index exceeds number of inputs")
   102  		}
   103  
   104  		details.Debits = append(details.Debits, debIter.elem)
   105  	}
   106  	return &details, debIter.err
   107  }
   108  
   109  // unminedTxDetails fetches the TxDetails for the unmined transaction with the
   110  // hash txHash and the passed unmined record value.
   111  func (s *Store) unminedTxDetails(ns walletdb.ReadBucket, txHash *chainhash.Hash, v []byte) (*TxDetails, error) {
   112  	details := TxDetails{
   113  		Block: BlockMeta{Block: Block{Height: -1}},
   114  	}
   115  	err := readRawTxRecord(txHash, v, &details.TxRecord)
   116  	if err != nil {
   117  		return nil, err
   118  	}
   119  
   120  	it := makeReadUnminedCreditIterator(ns, txHash, DBVersion)
   121  	defer it.close()
   122  	for it.next() {
   123  		if int(it.elem.Index) >= len(details.MsgTx.TxOut) {
   124  			return nil, errors.E(errors.IO, errors.Errorf("credit output index %d does not exist for tx %v", it.elem.Index, txHash))
   125  		}
   126  
   127  		// Set the Spent field since this is not done by the iterator.
   128  		it.elem.Spent = existsRawUnminedInput(ns, it.ck) != nil
   129  		details.Credits = append(details.Credits, it.elem)
   130  	}
   131  	if it.err != nil {
   132  		return nil, it.err
   133  	}
   134  
   135  	// Debit records are not saved for unmined transactions.  Instead, they
   136  	// must be looked up for each transaction input manually.  There are two
   137  	// kinds of previous credits that may be debited by an unmined
   138  	// transaction: mined unspent outputs (which remain marked unspent even
   139  	// when spent by an unmined transaction), and credits from other unmined
   140  	// transactions.  Both situations must be considered.
   141  	for i, output := range details.MsgTx.TxIn {
   142  		opKey := canonicalOutPoint(&output.PreviousOutPoint.Hash,
   143  			output.PreviousOutPoint.Index)
   144  		credKey := existsRawUnspent(ns, opKey)
   145  		if credKey != nil {
   146  			v := existsRawCredit(ns, credKey)
   147  			amount, err := fetchRawCreditAmount(v)
   148  			if err != nil {
   149  				return nil, err
   150  			}
   151  
   152  			details.Debits = append(details.Debits, DebitRecord{
   153  				Amount: amount,
   154  				Index:  uint32(i),
   155  			})
   156  			continue
   157  		}
   158  
   159  		v := existsRawUnminedCredit(ns, opKey)
   160  		if v == nil {
   161  			continue
   162  		}
   163  
   164  		amount, err := fetchRawCreditAmount(v)
   165  		if err != nil {
   166  			return nil, err
   167  		}
   168  		details.Debits = append(details.Debits, DebitRecord{
   169  			Amount: amount,
   170  			Index:  uint32(i),
   171  		})
   172  	}
   173  
   174  	return &details, nil
   175  }
   176  
   177  // TxDetails looks up all recorded details regarding a transaction with some
   178  // hash.  In case of a hash collision, the most recent transaction with a
   179  // matching hash is returned.
   180  func (s *Store) TxDetails(ns walletdb.ReadBucket, txHash *chainhash.Hash) (*TxDetails, error) {
   181  	// First, check whether there exists an unmined transaction with this
   182  	// hash.  Use it if found.
   183  	v := existsRawUnmined(ns, txHash[:])
   184  	if v != nil {
   185  		return s.unminedTxDetails(ns, txHash, v)
   186  	}
   187  
   188  	// Otherwise, if there exists a mined transaction with this matching
   189  	// hash, skip over to the newest and begin fetching all details.
   190  	k, v := latestTxRecord(ns, txHash[:])
   191  	if v == nil {
   192  		return nil, errors.E(errors.NotExist)
   193  	}
   194  	return s.minedTxDetails(ns, txHash, k, v)
   195  }
   196  
   197  // TicketDetails is intended to provide callers with access to rich details
   198  // regarding a relevant transaction and which inputs and outputs are credit or
   199  // debits.
   200  type TicketDetails struct {
   201  	Ticket  *TxDetails
   202  	Spender *TxDetails
   203  }
   204  
   205  // TicketDetails looks up all recorded details regarding a ticket with some
   206  // hash.
   207  //
   208  // Not finding a ticket with this hash is not an error.  In this case,
   209  // a nil TicketDetiails is returned.
   210  func (s *Store) TicketDetails(ns walletdb.ReadBucket, txDetails *TxDetails) (*TicketDetails, error) {
   211  	var ticketDetails = &TicketDetails{}
   212  	if !stake.IsSStx(&txDetails.MsgTx) {
   213  		return nil, nil
   214  	}
   215  	ticketDetails.Ticket = txDetails
   216  	var spenderHash = chainhash.Hash{}
   217  	// Check if the ticket is spent or not.  Look up the credit for output 0
   218  	// and check if either a debit is recorded or the output is spent by an
   219  	// unmined transaction.
   220  	_, credVal := existsCredit(ns, &txDetails.Hash, 0, &txDetails.Block.Block)
   221  	if credVal != nil {
   222  		if extractRawCreditIsSpent(credVal) {
   223  			debKey := extractRawCreditSpenderDebitKey(credVal)
   224  			debHash := extractRawDebitHash(debKey)
   225  			copy(spenderHash[:], debHash)
   226  		}
   227  	} else {
   228  		opKey := canonicalOutPoint(&txDetails.Hash, 0)
   229  		spenderVal := existsRawUnminedInput(ns, opKey)
   230  		if spenderVal != nil {
   231  			copy(spenderHash[:], spenderVal)
   232  		}
   233  	}
   234  	spenderDetails, err := s.TxDetails(ns, &spenderHash)
   235  	if (err != nil) && (!errors.Is(err, errors.NotExist)) {
   236  		return nil, err
   237  	}
   238  	ticketDetails.Spender = spenderDetails
   239  	return ticketDetails, nil
   240  }
   241  
   242  // parseTx deserializes a transaction into a MsgTx using the readRawTxRecord
   243  // method.
   244  func (s *Store) parseTx(txHash chainhash.Hash, v []byte) (*wire.MsgTx, error) {
   245  	details := TxDetails{
   246  		Block: BlockMeta{Block: Block{Height: -1}},
   247  	}
   248  	err := readRawTxRecord(&txHash, v, &details.TxRecord)
   249  	if err != nil {
   250  		return nil, err
   251  	}
   252  
   253  	return &details.MsgTx, nil
   254  }
   255  
   256  // Tx looks up all the stored wire.MsgTx for a transaction with some
   257  // hash.  In case of a hash collision, the most recent transaction with a
   258  // matching hash is returned.
   259  func (s *Store) Tx(ns walletdb.ReadBucket, txHash *chainhash.Hash) (*wire.MsgTx, error) {
   260  	// First, check whether there exists an unmined transaction with this
   261  	// hash.  Use it if found.
   262  	v := existsRawUnmined(ns, txHash[:])
   263  	if v != nil {
   264  		return s.parseTx(*txHash, v)
   265  	}
   266  
   267  	// Otherwise, if there exists a mined transaction with this matching
   268  	// hash, skip over to the newest and begin fetching the msgTx.
   269  	_, v = latestTxRecord(ns, txHash[:])
   270  	if v == nil {
   271  		return nil, errors.E(errors.NotExist,
   272  			errors.Errorf("tx %s not found", txHash.String()))
   273  	}
   274  	return s.parseTx(*txHash, v)
   275  }
   276  
   277  // ExistsTx checks to see if a transaction exists in the database.
   278  func (s *Store) ExistsTx(ns walletdb.ReadBucket, txHash *chainhash.Hash) bool {
   279  	// First, check whether there exists an unmined transaction with this
   280  	// hash.  Use it if found.
   281  	v := existsRawUnmined(ns, txHash[:])
   282  	if v != nil {
   283  		return true
   284  	}
   285  
   286  	// Otherwise, if there exists a mined transaction with this matching
   287  	// hash, skip over to the newest and begin fetching the msgTx.
   288  	_, v = latestTxRecord(ns, txHash[:])
   289  	return v != nil
   290  }
   291  
   292  // ExistsUTXO checks to see if op refers to an unspent transaction output or a
   293  // credit spent by an unmined transaction.  This check is sufficient to
   294  // determine whether a transaction input is relevant to the wallet by spending a
   295  // UTXO or conflicting with another mempool transaction that double spends the
   296  // output.
   297  func (s *Store) ExistsUTXO(dbtx walletdb.ReadTx, op *wire.OutPoint) bool {
   298  	ns := dbtx.ReadBucket(wtxmgrBucketKey)
   299  	k, v := existsUnspent(ns, op)
   300  	if v != nil {
   301  		return true
   302  	}
   303  	return existsRawUnminedCredit(ns, k) != nil
   304  }
   305  
   306  // UniqueTxDetails looks up all recorded details for a transaction recorded
   307  // mined in some particular block, or an unmined transaction if block is nil.
   308  //
   309  // Not finding a transaction with this hash from this block is not an error.  In
   310  // this case, a nil TxDetails is returned.
   311  func (s *Store) UniqueTxDetails(ns walletdb.ReadBucket, txHash *chainhash.Hash,
   312  	block *Block) (*TxDetails, error) {
   313  
   314  	if block == nil {
   315  		v := existsRawUnmined(ns, txHash[:])
   316  		if v == nil {
   317  			return nil, nil
   318  		}
   319  		return s.unminedTxDetails(ns, txHash, v)
   320  	}
   321  
   322  	k, v := existsTxRecord(ns, txHash, block)
   323  	if v == nil {
   324  		return nil, nil
   325  	}
   326  	return s.minedTxDetails(ns, txHash, k, v)
   327  }
   328  
   329  // TxBlockHeight returns the block height of a mined transaction, or -1 for any
   330  // unmined transactions.
   331  func (s *Store) TxBlockHeight(dbtx walletdb.ReadTx, txHash *chainhash.Hash) (int32, error) {
   332  	ns := dbtx.ReadBucket(wtxmgrBucketKey)
   333  	v := existsRawUnmined(ns, txHash[:])
   334  	if v != nil {
   335  		return -1, nil
   336  	}
   337  	k, _ := latestTxRecord(ns, txHash[:])
   338  	if k == nil {
   339  		return 0, errors.E(errors.NotExist, errors.Errorf("no transaction %v", txHash))
   340  	}
   341  	var height int32
   342  	err := readRawTxRecordBlockHeight(k, &height)
   343  	return height, err
   344  }
   345  
   346  // rangeUnminedTransactions executes the function f with TxDetails for every
   347  // unmined transaction.  f is not executed if no unmined transactions exist.
   348  // Error returns from f (if any) are propigated to the caller.  Returns true
   349  // (signaling breaking out of a RangeTransactions) iff f executes and returns
   350  // true.
   351  func (s *Store) rangeUnminedTransactions(ctx context.Context, ns walletdb.ReadBucket, f func([]TxDetails) (bool, error)) (bool, error) {
   352  	var details []TxDetails
   353  	err := ns.NestedReadBucket(bucketUnmined).ForEach(func(k, v []byte) error {
   354  		if ctx.Err() != nil {
   355  			return ctx.Err()
   356  		}
   357  		if len(k) < 32 {
   358  			return errors.E(errors.IO, errors.Errorf("bad unmined tx key len %d", len(k)))
   359  		}
   360  
   361  		var txHash chainhash.Hash
   362  		copy(txHash[:], k)
   363  		detail, err := s.unminedTxDetails(ns, &txHash, v)
   364  		if err != nil {
   365  			return err
   366  		}
   367  
   368  		// Because the key was created while foreach-ing over the
   369  		// bucket, it should be impossible for unminedTxDetails to ever
   370  		// successfully return a nil details struct.
   371  		details = append(details, *detail)
   372  		return nil
   373  	})
   374  	if err == nil && len(details) > 0 {
   375  		return f(details)
   376  	}
   377  	return false, err
   378  }
   379  
   380  // rangeBlockTransactions executes the function f with TxDetails for every block
   381  // between heights begin and end (reverse order when end > begin) until f
   382  // returns true, or the transactions from block is processed.  Returns true iff
   383  // f executes and returns true.
   384  func (s *Store) rangeBlockTransactions(ctx context.Context, ns walletdb.ReadBucket, begin, end int32,
   385  	f func([]TxDetails) (bool, error)) (bool, error) {
   386  
   387  	// Mempool height is considered a high bound.
   388  	if begin < 0 {
   389  		begin = int32(^uint32(0) >> 1)
   390  	}
   391  	if end < 0 {
   392  		end = int32(^uint32(0) >> 1)
   393  	}
   394  
   395  	var blockIter blockIterator
   396  	var advance func(*blockIterator) bool
   397  	if begin < end {
   398  		// Iterate in forwards order
   399  		blockIter = makeReadBlockIterator(ns, begin)
   400  		defer blockIter.close()
   401  		advance = func(it *blockIterator) bool {
   402  			if !it.next() {
   403  				return false
   404  			}
   405  			return it.elem.Height <= end
   406  		}
   407  	} else {
   408  		// Iterate in backwards order, from begin -> end.
   409  		blockIter = makeReadBlockIterator(ns, begin)
   410  		defer blockIter.close()
   411  		advance = func(it *blockIterator) bool {
   412  			if !it.prev() {
   413  				return false
   414  			}
   415  			return end <= it.elem.Height
   416  		}
   417  	}
   418  
   419  	var details []TxDetails
   420  	for advance(&blockIter) {
   421  		if ctx.Err() != nil {
   422  			return false, ctx.Err()
   423  		}
   424  
   425  		block := &blockIter.elem
   426  
   427  		if cap(details) < len(block.transactions) {
   428  			details = make([]TxDetails, 0, len(block.transactions))
   429  		} else {
   430  			details = details[:0]
   431  		}
   432  
   433  		for _, txHash := range block.transactions {
   434  			k := keyTxRecord(&txHash, &block.Block)
   435  			v := existsRawTxRecord(ns, k)
   436  			if v == nil {
   437  				return false, errors.E(errors.IO, errors.Errorf("missing transaction %v for block %v", txHash, block.Height))
   438  			}
   439  			detail := TxDetails{
   440  				Block: BlockMeta{
   441  					Block: block.Block,
   442  					Time:  block.Time,
   443  				},
   444  			}
   445  			err := readRawTxRecord(&txHash, v, &detail.TxRecord)
   446  			if err != nil {
   447  				return false, err
   448  			}
   449  
   450  			credIter := makeReadCreditIterator(ns, k, DBVersion)
   451  			for credIter.next() {
   452  				if int(credIter.elem.Index) >= len(detail.MsgTx.TxOut) {
   453  					credIter.close()
   454  					return false, errors.E(errors.IO, "saved credit index exceeds number of outputs")
   455  				}
   456  
   457  				// The credit iterator does not record whether
   458  				// this credit was spent by an unmined
   459  				// transaction, so check that here.
   460  				if !credIter.elem.Spent {
   461  					k := canonicalOutPoint(&txHash, credIter.elem.Index)
   462  					spent := existsRawUnminedInput(ns, k) != nil
   463  					credIter.elem.Spent = spent
   464  				}
   465  				detail.Credits = append(detail.Credits, credIter.elem)
   466  			}
   467  			credIter.close()
   468  			if credIter.err != nil {
   469  				return false, credIter.err
   470  			}
   471  
   472  			debIter := makeReadDebitIterator(ns, k)
   473  			defer debIter.close()
   474  			for debIter.next() {
   475  				if int(debIter.elem.Index) >= len(detail.MsgTx.TxIn) {
   476  					return false, errors.E(errors.IO, "saved debit index exceeds number of inputs")
   477  				}
   478  
   479  				detail.Debits = append(detail.Debits, debIter.elem)
   480  			}
   481  			if debIter.err != nil {
   482  				return false, debIter.err
   483  			}
   484  
   485  			details = append(details, detail)
   486  		}
   487  
   488  		// Decred: Block records are saved even when no transactions are
   489  		// included.  This is used to save the votebits from every
   490  		// block.  This differs from btcwallet where every block must
   491  		// have one transaction.  Since f may only be called when
   492  		// len(details) > 0, this must be explicitly tested.
   493  		if len(details) == 0 {
   494  			continue
   495  		}
   496  		brk, err := f(details)
   497  		if err != nil || brk {
   498  			return brk, err
   499  		}
   500  	}
   501  	return false, blockIter.err
   502  }
   503  
   504  // RangeTransactions runs the function f on all transaction details between
   505  // blocks on the best chain over the height range [begin,end].  The special
   506  // height -1 may be used to also include unmined transactions.  If the end
   507  // height comes before the begin height, blocks are iterated in reverse order
   508  // and unmined transactions (if any) are processed first.
   509  //
   510  // The function f may return an error which, if non-nil, is propagated to the
   511  // caller.  Additionally, a boolean return value allows exiting the function
   512  // early without reading any additional transactions early when true.
   513  //
   514  // All calls to f are guaranteed to be passed a slice with more than zero
   515  // elements.  The slice may be reused for multiple blocks, so it is not safe to
   516  // use it after the loop iteration it was acquired.
   517  func (s *Store) RangeTransactions(ctx context.Context, ns walletdb.ReadBucket, begin, end int32,
   518  	f func([]TxDetails) (bool, error)) error {
   519  
   520  	var addedUnmined bool
   521  	if begin < 0 {
   522  		brk, err := s.rangeUnminedTransactions(ctx, ns, f)
   523  		if err != nil || brk {
   524  			return err
   525  		}
   526  		addedUnmined = true
   527  	}
   528  
   529  	brk, err := s.rangeBlockTransactions(ctx, ns, begin, end, f)
   530  	if err == nil && !brk && !addedUnmined && end < 0 {
   531  		_, err = s.rangeUnminedTransactions(ctx, ns, f)
   532  	}
   533  	return err
   534  }
   535  
   536  // PreviousPkScripts returns a slice of previous output scripts for each credit
   537  // output this transaction record debits from.
   538  func (s *Store) PreviousPkScripts(ns walletdb.ReadBucket, rec *TxRecord, block *Block) ([][]byte, error) {
   539  	var pkScripts [][]byte
   540  
   541  	if block == nil {
   542  		for _, input := range rec.MsgTx.TxIn {
   543  			prevOut := &input.PreviousOutPoint
   544  
   545  			// Input may spend a previous unmined output, a
   546  			// mined output (which would still be marked
   547  			// unspent), or neither.
   548  
   549  			v := existsRawUnmined(ns, prevOut.Hash[:])
   550  			if v != nil {
   551  				// Ensure a credit exists for this
   552  				// unmined transaction before including
   553  				// the output script.
   554  				k := canonicalOutPoint(&prevOut.Hash, prevOut.Index)
   555  				vUC := existsRawUnminedCredit(ns, k)
   556  				if vUC == nil {
   557  					continue
   558  				}
   559  
   560  				// If we encounter an error here, it likely means
   561  				// we have a legacy outpoint. Ignore the error and
   562  				// just let the scrPos be 0, which will trigger
   563  				// whole transaction deserialization to retrieve
   564  				// the script.
   565  				scrPos := fetchRawUnminedCreditScriptOffset(vUC)
   566  				scrLen := fetchRawUnminedCreditScriptLength(vUC)
   567  
   568  				pkScript, err := fetchRawTxRecordPkScript(
   569  					prevOut.Hash[:], v, prevOut.Index, scrPos, scrLen)
   570  				if err != nil {
   571  					return nil, err
   572  				}
   573  				pkScripts = append(pkScripts, pkScript)
   574  				continue
   575  			}
   576  
   577  			_, credKey := existsUnspent(ns, prevOut)
   578  			if credKey != nil {
   579  				credVal := existsRawCredit(ns, credKey)
   580  				if credVal == nil {
   581  					return nil, errors.E(errors.IO, errors.Errorf("missing credit value for key %x", credKey))
   582  				}
   583  
   584  				// Legacy outputs in the credit bucket may be of the
   585  				// wrong size.
   586  				scrPos := fetchRawCreditScriptOffset(credVal)
   587  				scrLen := fetchRawCreditScriptLength(credVal)
   588  
   589  				k := extractRawCreditTxRecordKey(credKey)
   590  				v = existsRawTxRecord(ns, k)
   591  				pkScript, err := fetchRawTxRecordPkScript(k, v,
   592  					prevOut.Index, scrPos, scrLen)
   593  				if err != nil {
   594  					return nil, err
   595  				}
   596  				pkScripts = append(pkScripts, pkScript)
   597  			}
   598  		}
   599  	}
   600  
   601  	recKey := keyTxRecord(&rec.Hash, block)
   602  	it := makeReadDebitIterator(ns, recKey)
   603  	for it.next() {
   604  		credKey := extractRawDebitCreditKey(it.cv)
   605  		index := extractRawCreditIndex(credKey)
   606  
   607  		credVal := existsRawCredit(ns, credKey)
   608  		if credVal == nil {
   609  			return nil, errors.E(errors.IO, errors.Errorf("missing credit val for key %x", credKey))
   610  		}
   611  
   612  		// Legacy credit output values may be of the wrong
   613  		// size.
   614  		scrPos := fetchRawCreditScriptOffset(credVal)
   615  		scrLen := fetchRawCreditScriptLength(credVal)
   616  
   617  		k := extractRawCreditTxRecordKey(credKey)
   618  		v := existsRawTxRecord(ns, k)
   619  		pkScript, err := fetchRawTxRecordPkScript(k, v, index,
   620  			scrPos, scrLen)
   621  		if err != nil {
   622  			return nil, err
   623  		}
   624  		pkScripts = append(pkScripts, pkScript)
   625  	}
   626  	if it.err != nil {
   627  		return nil, it.err
   628  	}
   629  
   630  	return pkScripts, nil
   631  }
   632  
   633  // Spender queries for the transaction and input index which spends a Credit.
   634  // If the output is not a Credit, an error with code ErrInput is returned.  If
   635  // the output is unspent, the ErrNoExist code is used.
   636  func (s *Store) Spender(dbtx walletdb.ReadTx, out *wire.OutPoint) (*wire.MsgTx, uint32, error) {
   637  	ns := dbtx.ReadBucket(wtxmgrBucketKey)
   638  
   639  	var spender wire.MsgTx
   640  	var spenderHash chainhash.Hash
   641  	var spenderIndex uint32
   642  
   643  	// Check mined txs
   644  	k, v := latestTxRecord(ns, out.Hash[:])
   645  	if v != nil {
   646  		var block Block
   647  		err := readRawTxRecordBlock(k, &block)
   648  		if err != nil {
   649  			return nil, 0, err
   650  		}
   651  		k = keyCredit(&out.Hash, out.Index, &block)
   652  		v = existsRawCredit(ns, k)
   653  		if v == nil {
   654  			return nil, 0, errors.E(errors.Invalid, "output is not a credit")
   655  		}
   656  		if extractRawCreditIsSpent(v) {
   657  			// Credit exists and is spent by a mined transaction.
   658  			k = extractRawCreditSpenderDebitKey(v)
   659  			copy(spenderHash[:], extractRawDebitHash(k))
   660  			spenderIndex = extractRawDebitInputIndex(k)
   661  			k = extractRawDebitTxRecordKey(k)
   662  			v = existsRawTxRecord(ns, k)
   663  			err = readRawTxRecordMsgTx(&spenderHash, v, &spender)
   664  			if err != nil {
   665  				return nil, 0, err
   666  			}
   667  			return &spender, spenderIndex, nil
   668  		}
   669  		// Credit is not spent by a mined transaction, but may still be spent by
   670  		// an unmined one.  Check whether it is spent by an unmined tx, and
   671  		// record the spender hash if spent.
   672  		k = canonicalOutPoint(&out.Hash, out.Index)
   673  		v = existsRawUnminedInput(ns, k)
   674  		if v == nil {
   675  			return nil, 0, errors.E(errors.NotExist, "credit is unspent")
   676  		}
   677  		readRawUnminedInputSpenderHash(v, &spenderHash)
   678  	}
   679  
   680  	// If a spender exists at this point, it must be an unmined transaction.
   681  	// The spender hash will not yet be known if the credit is also unmined, or
   682  	// if there is no credit.
   683  	if spenderHash == (chainhash.Hash{}) {
   684  		k = canonicalOutPoint(&out.Hash, out.Index)
   685  		v = existsRawUnminedCredit(ns, k)
   686  		if v == nil {
   687  			return nil, 0, errors.E(errors.Invalid, "output is not a credit")
   688  		}
   689  		v = existsRawUnminedInput(ns, k)
   690  		if v == nil {
   691  			return nil, 0, errors.E(errors.NotExist, "credit is unspent")
   692  		}
   693  		readRawUnminedInputSpenderHash(v, &spenderHash)
   694  	}
   695  
   696  	// Credit is spent by an unmined transaction.  Index is unknown so the
   697  	// spending tx must be searched for a matching previous outpoint.
   698  	v = existsRawUnmined(ns, spenderHash[:])
   699  	if v == nil {
   700  		return nil, 0, errors.E(errors.NotExist, "missing unmined spending tx")
   701  	}
   702  	err := spender.Deserialize(bytes.NewReader(extractRawUnminedTx(v)))
   703  	if err != nil {
   704  		return nil, 0, errors.E(errors.Bug, err)
   705  	}
   706  	found := false
   707  	for i, in := range spender.TxIn {
   708  		// Compare outpoints without comparing tree.
   709  		if out.Hash == in.PreviousOutPoint.Hash && out.Index == in.PreviousOutPoint.Index {
   710  			spenderIndex = uint32(i)
   711  			found = true
   712  			break
   713  		}
   714  	}
   715  	if !found {
   716  		return nil, 0, errors.E(errors.NotExist, "recorded spending tx does not spend credit")
   717  	}
   718  	return &spender, spenderIndex, nil
   719  }
   720  
   721  // RangeBlocks execute function `f` for all blocks within the given range of
   722  // blocks in the main chain.
   723  func (s *Store) RangeBlocks(ns walletdb.ReadBucket, begin, end int32,
   724  	f func(*Block) (bool, error)) error {
   725  
   726  	// Same convention as rangeTransactions: -1 means the full range.
   727  	if begin < 0 {
   728  		begin = int32(^uint32(0) >> 1)
   729  	}
   730  	if end < 0 {
   731  		end = int32(^uint32(0) >> 1)
   732  	}
   733  
   734  	var blockIter blockIterator
   735  	var advance func(*blockIterator) bool
   736  
   737  	if begin < end {
   738  		// Iterate in forwards order
   739  		blockIter = makeReadBlockIterator(ns, begin)
   740  		defer blockIter.close()
   741  		advance = func(it *blockIterator) bool {
   742  			if !it.next() {
   743  				return false
   744  			}
   745  			return it.elem.Height <= end
   746  		}
   747  	} else {
   748  		// Iterate in backwards order, from begin -> end.
   749  		blockIter = makeReadBlockIterator(ns, begin)
   750  		defer blockIter.close()
   751  		advance = func(it *blockIterator) bool {
   752  			if !it.prev() {
   753  				return false
   754  			}
   755  			return end <= it.elem.Height
   756  		}
   757  	}
   758  
   759  	for advance(&blockIter) {
   760  		block := &blockIter.elem
   761  
   762  		brk, err := f(&block.Block)
   763  		if err != nil || brk {
   764  			return err
   765  		}
   766  	}
   767  
   768  	return nil
   769  }