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

     1  // Copyright (c) 2015 The btcsuite developers
     2  // Copyright (c) 2015-2019 The Decred developers
     3  // Use of this source code is governed by an ISC
     4  // license that can be found in the LICENSE file.
     5  
     6  package udb
     7  
     8  import (
     9  	"bytes"
    10  	"encoding/binary"
    11  	"runtime/debug"
    12  	"time"
    13  
    14  	"decred.org/dcrwallet/v3/errors"
    15  	"decred.org/dcrwallet/v3/wallet/walletdb"
    16  	"github.com/decred/dcrd/blockchain/stake/v5"
    17  	"github.com/decred/dcrd/chaincfg/chainhash"
    18  	"github.com/decred/dcrd/chaincfg/v3"
    19  	"github.com/decred/dcrd/crypto/ripemd160"
    20  	"github.com/decred/dcrd/dcrutil/v4"
    21  	"github.com/decred/dcrd/txscript/v4"
    22  	"github.com/decred/dcrd/wire"
    23  )
    24  
    25  // Naming
    26  //
    27  // The following variables are commonly used in this file and given
    28  // reserved names:
    29  //
    30  //   ns: The namespace bucket for this package
    31  //   b:  The primary bucket being operated on
    32  //   k:  A single bucket key
    33  //   v:  A single bucket value
    34  //   c:  A bucket cursor
    35  //   ck: The current cursor key
    36  //   cv: The current cursor value
    37  //
    38  // Functions use the naming scheme `Op[Raw]Type[Field]`, which performs the
    39  // operation `Op` on the type `Type`, optionally dealing with raw keys and
    40  // values if `Raw` is used.  Fetch and extract operations may only need to read
    41  // some portion of a key or value, in which case `Field` describes the component
    42  // being returned.  The following operations are used:
    43  //
    44  //   key:     return a db key for some data
    45  //   value:   return a db value for some data
    46  //   put:     insert or replace a value into a bucket
    47  //   fetch:   read and return a value
    48  //   read:    read a value into an out parameter
    49  //   exists:  return the raw (nil if not found) value for some data
    50  //   delete:  remove a k/v pair
    51  //   extract: perform an unchecked slice to extract a key or value
    52  //
    53  // Other operations which are specific to the types being operated on
    54  // should be explained in a comment.
    55  //
    56  // TODO Remove all magic numbers and replace them with cursors that are
    57  //      incremented by constants. Comments need to be filled in. Only
    58  //      about 1/2 of functions are properly commented.
    59  
    60  const (
    61  	// accountExistsMask is the bitmask for the accountExists bool in
    62  	// the encoded scriptType for credits.
    63  	accountExistsMask = uint8(0x80)
    64  )
    65  
    66  // scriptType indicates what type of script a pkScript is for the
    67  // purposes of the database. In the future this can allow for very
    68  // fast lookup of the 20-byte (or more) script/public key hash.
    69  // waddrmgr currently takes addresses instead of 20-byte hashes
    70  // for look up, so the script type is unused in favor of using
    71  // txscript to extract the address from a pkScript.
    72  type scriptType uint8
    73  
    74  const (
    75  	// scriptTypeNonexisting is the uint8 value representing an
    76  	// unset script type.
    77  	scriptTypeNonexisting = iota
    78  
    79  	// scriptTypeUnspecified is the uint8 value representing an
    80  	// unknown or unspecified type of script.
    81  	scriptTypeUnspecified
    82  
    83  	// scriptTypeP2PKH is the uint8 value representing a
    84  	// pay-to-public-key-hash script for a regular transaction.
    85  	scriptTypeP2PKH
    86  
    87  	// scriptTypeP2PK is the uint8 value representing a
    88  	// pay-to-public-key script for a regular transaction.
    89  	scriptTypeP2PK
    90  
    91  	// scriptTypeP2PKHAlt is the uint8 value representing a
    92  	// pay-to-public-key-hash script for a regular transaction
    93  	// with an alternative ECDSA.
    94  	scriptTypeP2PKHAlt
    95  
    96  	// scriptTypeP2PKAlt is the uint8 value representing a
    97  	// pay-to-public-key script for a regular transaction with
    98  	// an alternative ECDSA.
    99  	scriptTypeP2PKAlt
   100  
   101  	// scriptTypeP2SH is the uint8 value representing a
   102  	// pay-to-script-hash script for a regular transaction.
   103  	scriptTypeP2SH
   104  
   105  	// scriptTypeSP2PKH is the uint8 value representing a
   106  	// pay-to-public-key-hash script for a stake transaction.
   107  	scriptTypeSP2PKH
   108  
   109  	// scriptTypeP2SH is the uint8 value representing a
   110  	// pay-to-script-hash script for a stake transaction.
   111  	scriptTypeSP2SH
   112  )
   113  
   114  const (
   115  	// scriptLocNotStored is the offset value indicating that
   116  	// the output was stored as a legacy credit and that the
   117  	// script location was not stored.
   118  	scriptLocNotStored = 0
   119  )
   120  
   121  // Big endian is the preferred byte order, due to cursor scans over integer
   122  // keys iterating in order.
   123  var byteOrder = binary.BigEndian
   124  
   125  // This package makes assumptions that the width of a chainhash.Hash is always 32
   126  // bytes.  If this is ever changed (unlikely for bitcoin, possible for alts),
   127  // offsets have to be rewritten.  Use a compile-time assertion that this
   128  // assumption holds true.
   129  var _ [32]byte = chainhash.Hash{}
   130  
   131  // Bucket names
   132  var (
   133  	bucketBlocks                  = []byte("b")
   134  	bucketHeaders                 = []byte("h")
   135  	bucketTxRecords               = []byte("t")
   136  	bucketCredits                 = []byte("c")
   137  	bucketUnspent                 = []byte("u")
   138  	bucketDebits                  = []byte("d")
   139  	bucketUnmined                 = []byte("m")
   140  	bucketUnpublished             = []byte("up")
   141  	bucketUnminedCredits          = []byte("mc")
   142  	bucketUnminedInputs           = []byte("mi")
   143  	bucketTickets                 = []byte("tix")
   144  	bucketScripts                 = []byte("sc") // removed in db v14
   145  	bucketMultisig                = []byte("ms")
   146  	bucketMultisigUsp             = []byte("mu")
   147  	bucketStakeInvalidatedCredits = []byte("ic")
   148  	bucketStakeInvalidatedDebits  = []byte("id")
   149  	bucketCFilters                = []byte("cf")
   150  	bucketTicketCommitments       = []byte("cmt")
   151  	bucketTicketCommitmentsUsp    = []byte("cmu")
   152  )
   153  
   154  // Root (namespace) bucket keys
   155  var (
   156  	rootCreateDate   = []byte("date")
   157  	rootVersion      = []byte("vers")
   158  	rootMinedBalance = []byte("bal")
   159  	rootTipBlock     = []byte("tip")
   160  	rootHaveCFilters = []byte("havecfilters")
   161  	rootLastTxsBlock = []byte("lasttxsblock")
   162  	rootVSPHostIndex = []byte("vsphostindex")
   163  )
   164  
   165  // The root bucket's mined balance k/v pair records the total balance for all
   166  // unspent credits from mined transactions.  This includes immature outputs, and
   167  // outputs spent by mempool transactions, which must be considered when
   168  // returning the actual balance for a given number of block confirmations.  The
   169  // value is the amount serialized as a uint64.
   170  func fetchMinedBalance(ns walletdb.ReadBucket) (dcrutil.Amount, error) {
   171  	v := ns.Get(rootMinedBalance)
   172  	if len(v) != 8 {
   173  		return 0, errors.E(errors.IO, errors.Errorf("mined balance len %d", len(v)))
   174  	}
   175  	return dcrutil.Amount(byteOrder.Uint64(v)), nil
   176  }
   177  
   178  func putMinedBalance(ns walletdb.ReadWriteBucket, amt dcrutil.Amount) error {
   179  	v := make([]byte, 8)
   180  	byteOrder.PutUint64(v, uint64(amt))
   181  	err := ns.Put(rootMinedBalance, v)
   182  	if err != nil {
   183  		return errors.E(errors.IO, err)
   184  	}
   185  	return nil
   186  }
   187  
   188  // Several data structures are given canonical serialization formats as either
   189  // keys or values.  These common formats allow keys and values to be reused
   190  // across different buckets.
   191  //
   192  // The canonical outpoint serialization format is:
   193  //
   194  //   [0:32]  Trasaction hash (32 bytes)
   195  //   [32:36] Output index (4 bytes)
   196  //
   197  // The canonical transaction hash serialization is simply the hash.
   198  
   199  func canonicalOutPoint(txHash *chainhash.Hash, index uint32) []byte {
   200  	k := make([]byte, 36)
   201  	copy(k, txHash[:])
   202  	byteOrder.PutUint32(k[32:36], index)
   203  	return k
   204  }
   205  
   206  func readCanonicalOutPoint(k []byte, op *wire.OutPoint) error {
   207  	if len(k) < 36 {
   208  		return errors.E(errors.IO, errors.Errorf("outpoint len %d", len(k)))
   209  	}
   210  	copy(op.Hash[:], k)
   211  	op.Index = byteOrder.Uint32(k[32:36])
   212  	return nil
   213  }
   214  
   215  // Details regarding blocks are saved as k/v pairs in the blocks bucket.
   216  // blockRecords are keyed by their height.  The value is serialized as such:
   217  //
   218  // TODO: Unix time and vote bits are redundant now that headers are saved and
   219  // these can be removed from the block record in a future update.
   220  //
   221  //   [0:32]  Hash (32 bytes)
   222  //   [32:40] Unix time (8 bytes)
   223  //   [40:42] VoteBits (2 bytes/uint16)
   224  //   [42:43] Whether regular transactions are stake invalidated (1 byte, 0==false)
   225  //   [43:47] Number of transaction hashes (4 bytes)
   226  //   [47:]   For each transaction hash:
   227  //             Hash (32 bytes)
   228  
   229  func keyBlockRecord(height int32) []byte {
   230  	k := make([]byte, 4)
   231  	byteOrder.PutUint32(k, uint32(height))
   232  	return k
   233  }
   234  
   235  func valueBlockRecordEmptyFromHeader(blockHash []byte, header []byte) []byte {
   236  	v := make([]byte, 47)
   237  	copy(v, blockHash)
   238  	byteOrder.PutUint64(v[32:40], uint64(extractBlockHeaderUnixTime(header)))
   239  	byteOrder.PutUint16(v[40:42], extractBlockHeaderVoteBits(header))
   240  	byteOrder.PutUint32(v[43:47], 0)
   241  	return v
   242  }
   243  
   244  // valueBlockRecordStakeValidated returns a copy of the block record value with
   245  // stake validated byte set to zero.
   246  func valueBlockRecordStakeValidated(v []byte) []byte {
   247  	newv := make([]byte, len(v))
   248  	copy(newv, v[:42])
   249  	copy(newv[43:], v[43:])
   250  	return newv
   251  }
   252  
   253  // valueBlockRecordStakeInvalidated returns a copy of the block record value
   254  // with stake validated byte set to one.
   255  func valueBlockRecordStakeInvalidated(v []byte) []byte {
   256  	newv := make([]byte, len(v))
   257  	copy(newv, v[:42])
   258  	newv[42] = 1
   259  	copy(newv[43:], v[43:])
   260  	return newv
   261  }
   262  
   263  // appendRawBlockRecord returns a new block record value with a transaction
   264  // hash appended to the end and an incremented number of transactions.
   265  func appendRawBlockRecord(v []byte, txHash *chainhash.Hash) ([]byte, error) {
   266  	if len(v) < 47 {
   267  		return nil, errors.E(errors.IO, errors.Errorf("block record len %d", len(v)))
   268  	}
   269  	newv := append(v[:len(v):len(v)], txHash[:]...)
   270  	n := byteOrder.Uint32(newv[43:47])
   271  	byteOrder.PutUint32(newv[43:47], n+1)
   272  	return newv, nil
   273  }
   274  
   275  func putRawBlockRecord(ns walletdb.ReadWriteBucket, k, v []byte) error {
   276  	err := ns.NestedReadWriteBucket(bucketBlocks).Put(k, v)
   277  	if err != nil {
   278  		return errors.E(errors.IO, err)
   279  	}
   280  	return nil
   281  }
   282  
   283  func fetchBlockTime(ns walletdb.ReadBucket, height int32) (time.Time, error) {
   284  	k := keyBlockRecord(height)
   285  	v := ns.NestedReadBucket(bucketBlocks).Get(k)
   286  	if len(v) < 47 {
   287  		return time.Time{}, errors.E(errors.IO, errors.Errorf("block record len %d", len(v)))
   288  	}
   289  	return time.Unix(int64(byteOrder.Uint64(v[32:40])), 0), nil
   290  }
   291  
   292  func fetchBlockRecord(ns walletdb.ReadBucket, height int32) (*blockRecord, error) {
   293  	br := &blockRecord{}
   294  	k := keyBlockRecord(height)
   295  	v := ns.NestedReadBucket(bucketBlocks).Get(k)
   296  	err := readRawBlockRecord(k, v, br)
   297  
   298  	return br, err
   299  }
   300  
   301  func existsBlockRecord(ns walletdb.ReadBucket, height int32) (k, v []byte) {
   302  	k = keyBlockRecord(height)
   303  	v = ns.NestedReadBucket(bucketBlocks).Get(k)
   304  	return
   305  }
   306  
   307  func readRawBlockRecord(k, v []byte, block *blockRecord) error {
   308  	if len(k) < 4 {
   309  		return errors.E(errors.IO, errors.Errorf("block key len %d", len(k)))
   310  	}
   311  	if len(v) < 47 {
   312  		return errors.E(errors.IO, errors.Errorf("block record len %d", len(k)))
   313  	}
   314  
   315  	numTransactions := int(byteOrder.Uint32(v[43:47]))
   316  	expectedLen := 47 + chainhash.HashSize*numTransactions
   317  	if len(v) < expectedLen {
   318  		return errors.E(errors.IO, errors.Errorf("%d tx block record len %d",
   319  			numTransactions, len(v)))
   320  	}
   321  
   322  	block.Height = int32(byteOrder.Uint32(k))
   323  	copy(block.Hash[:], v)
   324  	block.Time = time.Unix(int64(byteOrder.Uint64(v[32:40])), 0)
   325  	block.VoteBits = byteOrder.Uint16(v[40:42])
   326  	block.transactions = make([]chainhash.Hash, numTransactions)
   327  	off := 47
   328  	for i := range block.transactions {
   329  		copy(block.transactions[i][:], v[off:])
   330  		off += chainhash.HashSize
   331  	}
   332  
   333  	return nil
   334  }
   335  
   336  func extractRawBlockRecordHash(v []byte) []byte {
   337  	return v[:32]
   338  }
   339  
   340  func extractRawBlockRecordStakeInvalid(v []byte) bool {
   341  	return v[42] != 0
   342  }
   343  
   344  type blockIterator struct {
   345  	c    walletdb.ReadWriteCursor
   346  	seek []byte
   347  	ck   []byte
   348  	cv   []byte
   349  	elem blockRecord
   350  	err  error
   351  }
   352  
   353  func makeReadBlockIterator(ns walletdb.ReadBucket, height int32) blockIterator {
   354  	seek := make([]byte, 4)
   355  	byteOrder.PutUint32(seek, uint32(height))
   356  	c := ns.NestedReadBucket(bucketBlocks).ReadCursor()
   357  	return blockIterator{c: readCursor{c}, seek: seek}
   358  }
   359  
   360  // Works just like makeBlockIterator but will initially position the cursor at
   361  // the last k/v pair.  Use this with blockIterator.prev.
   362  func makeReverseBlockIterator(ns walletdb.ReadWriteBucket) blockIterator {
   363  	seek := make([]byte, 4)
   364  	byteOrder.PutUint32(seek, ^uint32(0))
   365  	c := ns.NestedReadWriteBucket(bucketBlocks).ReadWriteCursor()
   366  	return blockIterator{c: c, seek: seek}
   367  }
   368  
   369  func (it *blockIterator) next() bool {
   370  	if it.c == nil {
   371  		return false
   372  	}
   373  
   374  	if it.ck == nil {
   375  		it.ck, it.cv = it.c.Seek(it.seek)
   376  	} else {
   377  		it.ck, it.cv = it.c.Next()
   378  	}
   379  	if it.ck == nil {
   380  		it.c.Close()
   381  		it.c = nil
   382  		return false
   383  	}
   384  
   385  	err := readRawBlockRecord(it.ck, it.cv, &it.elem)
   386  	if err != nil {
   387  		it.c = nil
   388  		it.err = err
   389  		return false
   390  	}
   391  
   392  	return true
   393  }
   394  
   395  func (it *blockIterator) prev() bool {
   396  	if it.c == nil {
   397  		return false
   398  	}
   399  
   400  	if it.ck == nil {
   401  		it.ck, it.cv = it.c.Seek(it.seek)
   402  		// Seek positions the cursor at the next k/v pair if one with
   403  		// this prefix was not found.  If this happened (the prefixes
   404  		// won't match in this case) move the cursor backward.
   405  		//
   406  		// This technically does not correct for multiple keys with
   407  		// matching prefixes by moving the cursor to the last matching
   408  		// key, but this doesn't need to be considered when dealing with
   409  		// block records since the key (and seek prefix) is just the
   410  		// block height.
   411  		if !bytes.HasPrefix(it.ck, it.seek) {
   412  			it.ck, it.cv = it.c.Prev()
   413  		}
   414  	} else {
   415  		it.ck, it.cv = it.c.Prev()
   416  	}
   417  	if it.ck == nil {
   418  		it.c.Close()
   419  		it.c = nil
   420  		return false
   421  	}
   422  
   423  	err := readRawBlockRecord(it.ck, it.cv, &it.elem)
   424  	if err != nil {
   425  		it.c.Close()
   426  		it.c = nil
   427  		it.err = err
   428  		return false
   429  	}
   430  
   431  	return true
   432  }
   433  
   434  func (it *blockIterator) close() {
   435  	if it.c == nil {
   436  		return
   437  	}
   438  	it.c.Close()
   439  }
   440  
   441  // unavailable until https://github.com/boltdb/bolt/issues/620 is fixed.
   442  // func (it *blockIterator) delete() error {
   443  // 	err := it.c.Delete()
   444  // 	if err != nil {
   445  // 		return errors.E(errors.IO, err)
   446  // 	}
   447  // 	return nil
   448  // }
   449  
   450  func (it *blockIterator) reposition(height int32) {
   451  	it.c.Seek(keyBlockRecord(height))
   452  }
   453  
   454  func deleteBlockRecord(ns walletdb.ReadWriteBucket, height int32) error {
   455  	k := keyBlockRecord(height)
   456  	return ns.NestedReadWriteBucket(bucketBlocks).Delete(k)
   457  }
   458  
   459  // Block headers are saved as k/v pairs in the headers bucket.  Block headers
   460  // are keyed by their block hashes.  The value is the serialized block header.
   461  
   462  func keyBlockHeader(blockHash *chainhash.Hash) []byte { return blockHash[:] }
   463  
   464  func putRawBlockHeader(ns walletdb.ReadWriteBucket, k, v []byte) error {
   465  	err := ns.NestedReadWriteBucket(bucketHeaders).Put(k, v)
   466  	if err != nil {
   467  		return errors.E(errors.IO, err)
   468  	}
   469  	return nil
   470  }
   471  
   472  func fetchRawBlockHeader(ns walletdb.ReadBucket, k []byte) ([]byte, error) {
   473  	v := ns.NestedReadBucket(bucketHeaders).Get(k)
   474  	if v == nil {
   475  		return nil, errors.E(errors.NotExist, "block header")
   476  	}
   477  	vcopy := make([]byte, len(v))
   478  	copy(vcopy, v)
   479  	return vcopy, nil
   480  }
   481  
   482  func existsBlockHeader(ns walletdb.ReadBucket, k []byte) []byte {
   483  	return ns.NestedReadBucket(bucketHeaders).Get(k)
   484  }
   485  
   486  // Transaction records are keyed as such:
   487  //
   488  //   [0:32]  Transaction hash (32 bytes)
   489  //   [32:36] Block height (4 bytes)
   490  //   [36:68] Block hash (32 bytes)
   491  //
   492  // The leading transaction hash allows to prefix filter for all records with
   493  // a matching hash.  The block height and hash records a particular incidence
   494  // of the transaction in the blockchain.
   495  //
   496  // The record value is serialized as such:
   497  //
   498  //   [0:8]   Received time (8 bytes)
   499  //   [8:]    Serialized transaction (varies)
   500  
   501  func keyTxRecord(txHash *chainhash.Hash, block *Block) []byte {
   502  	k := make([]byte, 68)
   503  	copy(k, txHash[:])
   504  	byteOrder.PutUint32(k[32:36], uint32(block.Height))
   505  	copy(k[36:68], block.Hash[:])
   506  	return k
   507  }
   508  
   509  func valueTxRecord(rec *TxRecord) ([]byte, error) {
   510  	var v []byte
   511  	if rec.SerializedTx == nil {
   512  		txSize := rec.MsgTx.SerializeSize()
   513  		v = make([]byte, 8, 8+txSize)
   514  		err := rec.MsgTx.Serialize(bytes.NewBuffer(v[8:]))
   515  		if err != nil {
   516  			return nil, errors.E(errors.Invalid, err)
   517  		}
   518  		v = v[:cap(v)]
   519  	} else {
   520  		v = make([]byte, 8+len(rec.SerializedTx))
   521  		copy(v[8:], rec.SerializedTx)
   522  	}
   523  	byteOrder.PutUint64(v, uint64(rec.Received.Unix()))
   524  	return v, nil
   525  }
   526  
   527  func putTxRecord(ns walletdb.ReadWriteBucket, rec *TxRecord, block *Block) error {
   528  	k := keyTxRecord(&rec.Hash, block)
   529  	v, err := valueTxRecord(rec)
   530  	if err != nil {
   531  		return err
   532  	}
   533  	err = ns.NestedReadWriteBucket(bucketTxRecords).Put(k, v)
   534  	if err != nil {
   535  		return errors.E(errors.IO, err)
   536  	}
   537  	return nil
   538  }
   539  
   540  func putRawTxRecord(ns walletdb.ReadWriteBucket, k, v []byte) error {
   541  	err := ns.NestedReadWriteBucket(bucketTxRecords).Put(k, v)
   542  	if err != nil {
   543  		return errors.E(errors.IO, err)
   544  	}
   545  	return nil
   546  }
   547  
   548  func readRawTxRecordMsgTx(txHash *chainhash.Hash, v []byte, msgTx *wire.MsgTx) error {
   549  	if len(v) < 8 {
   550  		return errors.E(errors.IO, errors.Errorf("tx record len %d", len(v)))
   551  	}
   552  	err := msgTx.Deserialize(bytes.NewReader(v[8:]))
   553  	if err != nil {
   554  		return errors.E(errors.IO, err)
   555  	}
   556  
   557  	return nil
   558  }
   559  
   560  func readRawTxRecord(txHash *chainhash.Hash, v []byte, rec *TxRecord) error {
   561  	if len(v) < 8 {
   562  		return errors.E(errors.IO, errors.Errorf("tx record len %d", len(v)))
   563  	}
   564  	rec.Hash = *txHash
   565  	rec.Received = time.Unix(int64(byteOrder.Uint64(v)), 0)
   566  	err := rec.MsgTx.Deserialize(bytes.NewReader(v[8:]))
   567  	if err != nil {
   568  		return errors.E(errors.IO, err)
   569  	}
   570  
   571  	// Calculate the stake TxType from the MsgTx.
   572  	rec.TxType = stake.DetermineTxType(&rec.MsgTx)
   573  
   574  	return nil
   575  }
   576  
   577  func readRawTxRecordHash(k []byte, hash *chainhash.Hash) error {
   578  	if len(k) < 68 {
   579  		debug.PrintStack()
   580  		return errors.E(errors.IO, errors.Errorf("tx record key len %d", len(k)))
   581  	}
   582  	copy(hash[:], k[:32])
   583  	return nil
   584  }
   585  
   586  func readRawTxRecordBlockHeight(k []byte, height *int32) error {
   587  	if len(k) < 68 {
   588  		debug.PrintStack()
   589  		return errors.E(errors.IO, errors.Errorf("tx record key len %d", len(k)))
   590  	}
   591  	*height = int32(byteOrder.Uint32(k[32:36]))
   592  	return nil
   593  }
   594  
   595  func readRawTxRecordBlock(k []byte, block *Block) error {
   596  	if len(k) < 68 {
   597  		debug.PrintStack()
   598  		return errors.E(errors.IO, errors.Errorf("tx record key len %d", len(k)))
   599  	}
   600  	block.Height = int32(byteOrder.Uint32(k[32:36]))
   601  	copy(block.Hash[:], k[36:68])
   602  	return nil
   603  }
   604  
   605  func fetchRawTxRecordPkScript(k, v []byte, index uint32, scrLoc uint32, scrLen uint32) ([]byte, error) {
   606  	var pkScript []byte
   607  
   608  	var txHash chainhash.Hash
   609  	err := readRawTxRecordHash(k, &txHash)
   610  	if err != nil {
   611  		return nil, err
   612  	}
   613  
   614  	// The script isn't stored (legacy credits). Deserialize the
   615  	// entire transaction.
   616  	if scrLoc == scriptLocNotStored {
   617  		var rec TxRecord
   618  		err = readRawTxRecord(&txHash, v, &rec)
   619  		if err != nil {
   620  			return nil, err
   621  		}
   622  		if int(index) >= len(rec.MsgTx.TxOut) {
   623  			return nil, errors.E(errors.IO, "missing transaction output for credit index")
   624  		}
   625  		pkScript = rec.MsgTx.TxOut[index].PkScript
   626  	} else {
   627  		// We have the location and script length stored. Just
   628  		// copy the script. Offset the script location for the
   629  		// timestamp that prefixes it.
   630  		scrLocInt := int(scrLoc) + 8
   631  		scrLenInt := int(scrLen)
   632  
   633  		// Check the bounds to make sure the we don't read beyond
   634  		// the end of the serialized transaction value, which
   635  		// would cause a panic.
   636  		if scrLocInt > len(v)-1 || scrLocInt+scrLenInt > len(v) {
   637  			return nil, errors.E(errors.IO, errors.Errorf(
   638  				"invalid script offset %d for tx %v", scrLocInt, &txHash))
   639  		}
   640  
   641  		pkScript = make([]byte, scrLenInt)
   642  		copy(pkScript, v[scrLocInt:scrLocInt+scrLenInt])
   643  	}
   644  
   645  	return pkScript, nil
   646  }
   647  
   648  func fetchRawTxRecordReceived(v []byte) time.Time {
   649  	return time.Unix(int64(byteOrder.Uint64(v)), 0)
   650  }
   651  
   652  func existsTxRecord(ns walletdb.ReadBucket, txHash *chainhash.Hash, block *Block) (k, v []byte) {
   653  	k = keyTxRecord(txHash, block)
   654  	v = ns.NestedReadBucket(bucketTxRecords).Get(k)
   655  	return
   656  }
   657  
   658  func existsRawTxRecord(ns walletdb.ReadBucket, k []byte) (v []byte) {
   659  	return ns.NestedReadBucket(bucketTxRecords).Get(k)
   660  }
   661  
   662  func deleteTxRecord(ns walletdb.ReadWriteBucket, txHash *chainhash.Hash, block *Block) error {
   663  	k := keyTxRecord(txHash, block)
   664  	err := ns.NestedReadWriteBucket(bucketTxRecords).Delete(k)
   665  	if err != nil {
   666  		return errors.E(errors.IO, err)
   667  	}
   668  	return nil
   669  }
   670  
   671  // latestTxRecord searches for the newest recorded mined transaction record with
   672  // a matching hash.  In case of a hash collision, the record from the newest
   673  // block is returned.  Returns (nil, nil) if no matching transactions are found.
   674  func latestTxRecord(ns walletdb.ReadBucket, txHash []byte) (k, v []byte) {
   675  	c := ns.NestedReadBucket(bucketTxRecords).ReadCursor()
   676  	ck, cv := c.Seek(txHash)
   677  	var lastKey, lastVal []byte
   678  	for bytes.HasPrefix(ck, txHash) {
   679  		lastKey, lastVal = ck, cv
   680  		ck, cv = c.Next()
   681  	}
   682  	c.Close()
   683  	return lastKey, lastVal
   684  }
   685  
   686  // All transaction credits (outputs) are keyed as such:
   687  //
   688  //   [0:32]  Transaction hash (32 bytes)
   689  //   [32:36] Block height (4 bytes)
   690  //   [36:68] Block hash (32 bytes)
   691  //   [68:72] Output index (4 bytes)
   692  //
   693  // The first 68 bytes match the key for the transaction record and may be used
   694  // as a prefix filter to iterate through all credits in order.
   695  //
   696  // The credit value is serialized as such:
   697  //
   698  //   [0:8]   Amount (8 bytes)
   699  //   [8]     Flags (1 byte)
   700  //             0x01: Spent
   701  //             0x02: Change
   702  //             0x1c: P2PKH stake flag
   703  //                 0x00: None (translates to OP_NOP10)
   704  //                 0x04: OP_SSTX
   705  //                 0x08: OP_SSGEN
   706  //                 0x0c: OP_SSRTX
   707  //                 0x10: OP_SSTXCHANGE
   708  //                 0x1c: OP_TGEN
   709  //             0x20: IsCoinbase
   710  //             0x40: HasExpiry
   711  //   [9:81]  OPTIONAL Debit bucket key (72 bytes)
   712  //             [9:41]  Spender transaction hash (32 bytes)
   713  //             [41:45] Spender block height (4 bytes)
   714  //             [45:77] Spender block hash (32 bytes)
   715  //             [77:81] Spender transaction input index (4 bytes)
   716  //   [81:86] OPTIONAL scriptPk location in the transaction output (5 bytes)
   717  //             [81] Script type (P2PKH, P2SH, etc) and accountExists
   718  //             [82:86] Byte index (4 bytes, uint32)
   719  //             [86:90] Length of script (4 bytes, uint32)
   720  //             [90:94] Account (4 bytes, uint32)
   721  //
   722  // The optional debits key is only included if the credit is spent by another
   723  // mined debit.
   724  
   725  const (
   726  	// creditKeySize is the total size of a credit key in bytes.
   727  	creditKeySize = 72
   728  
   729  	// creditValueSize is the total size of a credit value in bytes.
   730  	creditValueSize = 94
   731  )
   732  
   733  func keyCredit(txHash *chainhash.Hash, index uint32, block *Block) []byte {
   734  	k := make([]byte, creditKeySize)
   735  	copy(k, txHash[:])
   736  	byteOrder.PutUint32(k[32:36], uint32(block.Height))
   737  	copy(k[36:68], block.Hash[:])
   738  	byteOrder.PutUint32(k[68:72], index)
   739  	return k
   740  }
   741  
   742  func condenseOpCode(opCode uint8) byte {
   743  	switch {
   744  	case opCode == txscript.OP_TGEN:
   745  		return 0x1c
   746  	default:
   747  		// Original behavior. Compresses the txscript OP_SS* opcode to
   748  		// an appropriate flag value.
   749  		return (opCode - 0xb9) << 2
   750  	}
   751  }
   752  
   753  func expandOpCode(opCodeFlag byte) uint8 {
   754  	// Bits used by the stake opcode flag.
   755  	mask := byte(0x1c)
   756  
   757  	switch {
   758  	case opCodeFlag&mask == 0x1c:
   759  		return txscript.OP_TGEN
   760  	default:
   761  		// Original behavior. This cashes out to one of the OP_SS***
   762  		// opcode constants.
   763  		return ((opCodeFlag >> 2) & 0x07) + 0xb9
   764  	}
   765  }
   766  
   767  // valueUnspentCredit creates a new credit value for an unspent credit.  All
   768  // credits are created unspent, and are only marked spent later, so there is no
   769  // value function to create either spent or unspent credits.
   770  func valueUnspentCredit(cred *credit, scrType scriptType, scrLoc uint32,
   771  	scrLen uint32, account uint32, dbVersion uint32) []byte {
   772  	v := make([]byte, creditValueSize)
   773  	byteOrder.PutUint64(v, uint64(cred.amount))
   774  	v[8] = condenseOpCode(cred.opCode)
   775  	if cred.change {
   776  		v[8] |= 1 << 1
   777  	}
   778  	if cred.isCoinbase {
   779  		v[8] |= 1 << 5
   780  	}
   781  	if cred.hasExpiry {
   782  		switch {
   783  		case dbVersion >= hasExpiryFixedVersion:
   784  			v[8] |= 1 << 6
   785  		case dbVersion >= hasExpiryVersion:
   786  			v[8] |= 1 << 4
   787  		}
   788  	}
   789  
   790  	v[81] = byte(scrType)
   791  	v[81] |= accountExistsMask
   792  	byteOrder.PutUint32(v[82:86], scrLoc)
   793  	byteOrder.PutUint32(v[86:90], scrLen)
   794  	byteOrder.PutUint32(v[90:94], account)
   795  
   796  	return v
   797  }
   798  
   799  func putRawCredit(ns walletdb.ReadWriteBucket, k, v []byte) error {
   800  	err := ns.NestedReadWriteBucket(bucketCredits).Put(k, v)
   801  	if err != nil {
   802  		return errors.E(errors.IO, err)
   803  	}
   804  	return nil
   805  }
   806  
   807  // putUnspentCredit puts a credit record for an unspent credit.  It may only be
   808  // used when the credit is already know to be unspent, or spent by an
   809  // unconfirmed transaction.
   810  func putUnspentCredit(ns walletdb.ReadWriteBucket, cred *credit, scrType scriptType,
   811  	scrLoc uint32, scrLen uint32, account uint32, dbVersion uint32) error {
   812  	k := keyCredit(&cred.outPoint.Hash, cred.outPoint.Index, &cred.block)
   813  	v := valueUnspentCredit(cred, scrType, scrLoc, scrLen, account, dbVersion)
   814  	return putRawCredit(ns, k, v)
   815  }
   816  
   817  func extractRawCreditTxHash(k []byte) chainhash.Hash {
   818  	hash, _ := chainhash.NewHash(k[0:32])
   819  	return *hash
   820  }
   821  
   822  func extractRawCreditTxRecordKey(k []byte) []byte {
   823  	return k[0:68]
   824  }
   825  
   826  func extractRawCreditHeight(k []byte) int32 {
   827  	return int32(byteOrder.Uint32(k[32:36]))
   828  }
   829  
   830  func extractRawCreditIndex(k []byte) uint32 {
   831  	return byteOrder.Uint32(k[68:72])
   832  }
   833  
   834  func extractRawUnminedCreditTxHash(k []byte) []byte {
   835  	return k[:32]
   836  }
   837  
   838  func extractRawCreditIsSpent(v []byte) bool {
   839  	return v[8]&1<<0 != 0
   840  }
   841  
   842  func extractRawCreditSpenderDebitKey(v []byte) []byte {
   843  	return v[9:81]
   844  }
   845  
   846  // fetchRawCreditAmount returns the amount of the credit.
   847  func fetchRawCreditAmount(v []byte) (dcrutil.Amount, error) {
   848  	if len(v) < 9 {
   849  		return 0, errors.E(errors.IO, errors.Errorf("credit len %d", len(v)))
   850  	}
   851  	return dcrutil.Amount(byteOrder.Uint64(v)), nil
   852  }
   853  
   854  // fetchRawCreditAmountSpent returns the amount of the credit and whether the
   855  // credit is spent.
   856  func fetchRawCreditAmountSpent(v []byte) (dcrutil.Amount, bool, error) {
   857  	if len(v) < 9 {
   858  		return 0, false, errors.E(errors.IO, errors.Errorf("credit len %d", len(v)))
   859  	}
   860  	return dcrutil.Amount(byteOrder.Uint64(v)), v[8]&(1<<0) != 0, nil
   861  }
   862  
   863  // fetchRawCreditAmountChange returns the amount of the credit and whether the
   864  // credit is marked as change.
   865  func fetchRawCreditAmountChange(v []byte) (dcrutil.Amount, bool, error) {
   866  	if len(v) < 9 {
   867  		return 0, false, errors.E(errors.IO, errors.Errorf("credit len %d", len(v)))
   868  	}
   869  	return dcrutil.Amount(byteOrder.Uint64(v)), v[8]&(1<<1) != 0, nil
   870  }
   871  
   872  // fetchRawCreditUnspentValue returns the unspent value for a raw credit key.
   873  // This may be used to mark a credit as unspent.
   874  func fetchRawCreditUnspentValue(k []byte) ([]byte, error) {
   875  	if len(k) < 72 {
   876  		return nil, errors.E(errors.IO, errors.Errorf("credit key len %d", len(k)))
   877  	}
   878  	return k[32:68], nil
   879  }
   880  
   881  // fetchRawCreditTagOpCode fetches the compressed OP code for a transaction.
   882  func fetchRawCreditTagOpCode(v []byte) uint8 {
   883  	return expandOpCode(v[8])
   884  }
   885  
   886  // fetchRawCreditIsCoinbase returns whether or not the credit is a coinbase
   887  // output or not.
   888  func fetchRawCreditIsCoinbase(v []byte) bool {
   889  	return v[8]&(1<<5) != 0
   890  }
   891  
   892  // fetchRawCreditHasExpiry returns whether or not the credit has an expiry
   893  // set or not.
   894  func fetchRawCreditHasExpiry(v []byte, dbVersion uint32) bool {
   895  	switch {
   896  	case dbVersion >= hasExpiryFixedVersion:
   897  		return v[8]&(1<<6) != 0
   898  	case dbVersion >= hasExpiryVersion:
   899  		return v[8]&(1<<4) != 0
   900  	default:
   901  		return false
   902  	}
   903  }
   904  
   905  // fetchRawCreditScriptOffset returns the ScriptOffset for the pkScript of this
   906  // credit.
   907  func fetchRawCreditScriptOffset(v []byte) uint32 {
   908  	if len(v) < creditValueSize {
   909  		return 0
   910  	}
   911  	return byteOrder.Uint32(v[82:86])
   912  }
   913  
   914  // fetchRawCreditScriptLength returns the ScriptOffset for the pkScript of this
   915  // credit.
   916  func fetchRawCreditScriptLength(v []byte) uint32 {
   917  	if len(v) < creditValueSize {
   918  		return 0
   919  	}
   920  	return byteOrder.Uint32(v[86:90])
   921  }
   922  
   923  // fetchRawCreditAccount returns the account for the pkScript of this
   924  // credit.
   925  func fetchRawCreditAccount(v []byte) (uint32, error) {
   926  	if len(v) < creditValueSize {
   927  		return 0, errors.E(errors.IO, errors.Errorf("credit len %d", len(v)))
   928  	}
   929  
   930  	// Was the account ever set?
   931  	if v[81]&accountExistsMask != accountExistsMask {
   932  		return 0, errors.E(errors.IO, "credit account unset")
   933  	}
   934  
   935  	return byteOrder.Uint32(v[90:94]), nil
   936  }
   937  
   938  // spendRawCredit marks the credit with a given key as mined at some particular
   939  // block as spent by the input at some transaction incidence.  The debited
   940  // amount is returned.
   941  func spendCredit(ns walletdb.ReadWriteBucket, k []byte, spender *indexedIncidence) (dcrutil.Amount, error) {
   942  	v := ns.NestedReadWriteBucket(bucketCredits).Get(k)
   943  	newv := make([]byte, creditValueSize)
   944  	copy(newv, v)
   945  	v = newv
   946  	v[8] |= 1 << 0
   947  	copy(v[9:41], spender.txHash[:])
   948  	byteOrder.PutUint32(v[41:45], uint32(spender.block.Height))
   949  	copy(v[45:77], spender.block.Hash[:])
   950  	byteOrder.PutUint32(v[77:81], spender.index)
   951  
   952  	return dcrutil.Amount(byteOrder.Uint64(v[0:8])), putRawCredit(ns, k, v)
   953  }
   954  
   955  // unspendRawCredit rewrites the credit for the given key as unspent.  The
   956  // output amount of the credit is returned.  It returns without error if no
   957  // credit exists for the key.
   958  func unspendRawCredit(ns walletdb.ReadWriteBucket, k []byte) (dcrutil.Amount, error) {
   959  	b := ns.NestedReadWriteBucket(bucketCredits)
   960  	v := b.Get(k)
   961  	if v == nil {
   962  		return 0, nil
   963  	}
   964  	newv := make([]byte, creditValueSize)
   965  	copy(newv, v)
   966  	newv[8] &^= 1 << 0
   967  
   968  	err := b.Put(k, newv)
   969  	if err != nil {
   970  		return 0, errors.E(errors.IO, err)
   971  	}
   972  	return dcrutil.Amount(byteOrder.Uint64(v[0:8])), nil
   973  }
   974  
   975  func existsCredit(ns walletdb.ReadBucket, txHash *chainhash.Hash, index uint32, block *Block) (k, v []byte) {
   976  	k = keyCredit(txHash, index, block)
   977  	v = ns.NestedReadBucket(bucketCredits).Get(k)
   978  	return
   979  }
   980  
   981  func existsRawCredit(ns walletdb.ReadBucket, k []byte) []byte {
   982  	return ns.NestedReadBucket(bucketCredits).Get(k)
   983  }
   984  
   985  func existsInvalidatedCredit(ns walletdb.ReadBucket, txHash *chainhash.Hash, index uint32, block *Block) (k, v []byte) {
   986  	k = keyCredit(txHash, index, block)
   987  	v = ns.NestedReadBucket(bucketStakeInvalidatedCredits).Get(k)
   988  	return
   989  }
   990  
   991  func deleteRawCredit(ns walletdb.ReadWriteBucket, k []byte) error {
   992  	err := ns.NestedReadWriteBucket(bucketCredits).Delete(k)
   993  	if err != nil {
   994  		return errors.E(errors.IO, err)
   995  	}
   996  	return nil
   997  }
   998  
   999  // creditIterator allows for in-order iteration of all credit records for a
  1000  // mined transaction.
  1001  //
  1002  // Example usage:
  1003  //
  1004  //	prefix := keyTxRecord(txHash, block)
  1005  //	it := makeCreditIterator(ns, prefix)
  1006  //	for it.next() {
  1007  //	        // Use it.elem
  1008  //	        // If necessary, read additional details from it.ck, it.cv
  1009  //	}
  1010  //	if it.err != nil {
  1011  //	        // Handle error
  1012  //	}
  1013  //
  1014  // The elem's Spent field is not set to true if the credit is spent by an
  1015  // unmined transaction.  To check for this case:
  1016  //
  1017  //	k := canonicalOutPoint(&txHash, it.elem.Index)
  1018  //	it.elem.Spent = existsRawUnminedInput(ns, k) != nil
  1019  type creditIterator struct {
  1020  	c         walletdb.ReadWriteCursor // Set to nil after final iteration
  1021  	dbVersion uint32
  1022  	prefix    []byte
  1023  	ck        []byte
  1024  	cv        []byte
  1025  	elem      CreditRecord
  1026  	err       error
  1027  }
  1028  
  1029  func makeReadCreditIterator(ns walletdb.ReadBucket, prefix []byte, dbVersion uint32) creditIterator {
  1030  	c := ns.NestedReadBucket(bucketCredits).ReadCursor()
  1031  	return creditIterator{c: readCursor{c}, prefix: prefix, dbVersion: dbVersion}
  1032  }
  1033  
  1034  func (it *creditIterator) readElem() error {
  1035  	if len(it.ck) < 72 {
  1036  		return errors.E(errors.IO, errors.Errorf("credit key len %d", len(it.ck)))
  1037  	}
  1038  	if len(it.cv) < 9 {
  1039  		return errors.E(errors.IO, errors.Errorf("credit len %d", len(it.cv)))
  1040  	}
  1041  	it.elem.Index = byteOrder.Uint32(it.ck[68:72])
  1042  	it.elem.Amount = dcrutil.Amount(byteOrder.Uint64(it.cv))
  1043  	it.elem.Spent = it.cv[8]&(1<<0) != 0
  1044  	it.elem.Change = it.cv[8]&(1<<1) != 0
  1045  	it.elem.OpCode = fetchRawCreditTagOpCode(it.cv)
  1046  	it.elem.IsCoinbase = fetchRawCreditIsCoinbase(it.cv)
  1047  	it.elem.HasExpiry = fetchRawCreditHasExpiry(it.cv, it.dbVersion)
  1048  
  1049  	return nil
  1050  }
  1051  
  1052  func (it *creditIterator) next() bool {
  1053  	if it.c == nil {
  1054  		return false
  1055  	}
  1056  
  1057  	if it.ck == nil {
  1058  		it.ck, it.cv = it.c.Seek(it.prefix)
  1059  	} else {
  1060  		it.ck, it.cv = it.c.Next()
  1061  	}
  1062  	if !bytes.HasPrefix(it.ck, it.prefix) {
  1063  		it.c.Close()
  1064  		it.c = nil
  1065  		return false
  1066  	}
  1067  
  1068  	err := it.readElem()
  1069  	if err != nil {
  1070  		it.err = err
  1071  		return false
  1072  	}
  1073  	return true
  1074  }
  1075  
  1076  func (it *creditIterator) close() {
  1077  	if it.c == nil {
  1078  		return
  1079  	}
  1080  	it.c.Close()
  1081  }
  1082  
  1083  // The unspent index records all outpoints for mined credits which are not spent
  1084  // by any other mined transaction records (but may be spent by a mempool
  1085  // transaction).
  1086  //
  1087  // Keys are use the canonical outpoint serialization:
  1088  //
  1089  //   [0:32]  Transaction hash (32 bytes)
  1090  //   [32:36] Output index (4 bytes)
  1091  //
  1092  // Values are serialized as such:
  1093  //
  1094  //   [0:4]   Block height (4 bytes)
  1095  //   [4:36]  Block hash (32 bytes)
  1096  
  1097  func valueUnspent(block *Block) []byte {
  1098  	v := make([]byte, 36)
  1099  	byteOrder.PutUint32(v, uint32(block.Height))
  1100  	copy(v[4:36], block.Hash[:])
  1101  	return v
  1102  }
  1103  
  1104  func putUnspent(ns walletdb.ReadWriteBucket, outPoint *wire.OutPoint, block *Block) error {
  1105  	k := canonicalOutPoint(&outPoint.Hash, outPoint.Index)
  1106  	v := valueUnspent(block)
  1107  	err := ns.NestedReadWriteBucket(bucketUnspent).Put(k, v)
  1108  	if err != nil {
  1109  		return errors.E(errors.IO, err)
  1110  	}
  1111  	return nil
  1112  }
  1113  
  1114  func putRawUnspent(ns walletdb.ReadWriteBucket, k, v []byte) error {
  1115  	err := ns.NestedReadWriteBucket(bucketUnspent).Put(k, v)
  1116  	if err != nil {
  1117  		return errors.E(errors.IO, err)
  1118  	}
  1119  	return nil
  1120  }
  1121  
  1122  func readUnspentBlock(v []byte, block *Block) error {
  1123  	if len(v) < 36 {
  1124  		return errors.E(errors.IO, errors.Errorf("unspent len %d", len(v)))
  1125  	}
  1126  	block.Height = int32(byteOrder.Uint32(v))
  1127  	copy(block.Hash[:], v[4:36])
  1128  	return nil
  1129  }
  1130  
  1131  // existsUnspent returns the key for the unspent output and the corresponding
  1132  // key for the credits bucket.  If there is no unspent output recorded, the
  1133  // credit key is nil.
  1134  func existsUnspent(ns walletdb.ReadBucket, outPoint *wire.OutPoint) (k, credKey []byte) {
  1135  	k = canonicalOutPoint(&outPoint.Hash, outPoint.Index)
  1136  	credKey = existsRawUnspent(ns, k)
  1137  	return k, credKey
  1138  }
  1139  
  1140  // existsRawUnspent returns the credit key if there exists an output recorded
  1141  // for the raw unspent key.  It returns nil if the k/v pair does not exist.
  1142  func existsRawUnspent(ns walletdb.ReadBucket, k []byte) (credKey []byte) {
  1143  	if len(k) < 36 {
  1144  		return nil
  1145  	}
  1146  	v := ns.NestedReadBucket(bucketUnspent).Get(k)
  1147  	if len(v) < 36 {
  1148  		return nil
  1149  	}
  1150  	credKey = make([]byte, 72)
  1151  	copy(credKey, k[:32])
  1152  	copy(credKey[32:68], v)
  1153  	copy(credKey[68:72], k[32:36])
  1154  	return credKey
  1155  }
  1156  
  1157  func deleteRawUnspent(ns walletdb.ReadWriteBucket, k []byte) error {
  1158  	err := ns.NestedReadWriteBucket(bucketUnspent).Delete(k)
  1159  	if err != nil {
  1160  		return errors.E(errors.IO, err)
  1161  	}
  1162  	return nil
  1163  }
  1164  
  1165  // All transaction debits (inputs which spend credits) are keyed as such:
  1166  //
  1167  //   [0:32]  Transaction hash (32 bytes)
  1168  //   [32:36] Block height (4 bytes)
  1169  //   [36:68] Block hash (32 bytes)
  1170  //   [68:72] Input index (4 bytes)
  1171  //
  1172  // The first 68 bytes match the key for the transaction record and may be used
  1173  // as a prefix filter to iterate through all debits in order.
  1174  //
  1175  // The debit value is serialized as such:
  1176  //
  1177  //   [0:8]   Amount (8 bytes)
  1178  //   [8:80]  Credits bucket key (72 bytes)
  1179  //             [8:40]  Transaction hash (32 bytes)
  1180  //             [40:44] Block height (4 bytes)
  1181  //             [44:76] Block hash (32 bytes)
  1182  //             [76:80] Output index (4 bytes)
  1183  
  1184  func keyDebit(txHash *chainhash.Hash, index uint32, block *Block) []byte {
  1185  	k := make([]byte, 72)
  1186  	copy(k, txHash[:])
  1187  	byteOrder.PutUint32(k[32:36], uint32(block.Height))
  1188  	copy(k[36:68], block.Hash[:])
  1189  	byteOrder.PutUint32(k[68:72], index)
  1190  	return k
  1191  }
  1192  
  1193  func valueDebit(amount dcrutil.Amount, credKey []byte) []byte {
  1194  	v := make([]byte, 80)
  1195  	byteOrder.PutUint64(v, uint64(amount))
  1196  	copy(v[8:80], credKey)
  1197  	return v
  1198  }
  1199  
  1200  func putDebit(ns walletdb.ReadWriteBucket, txHash *chainhash.Hash, index uint32, amount dcrutil.Amount, block *Block, credKey []byte) error {
  1201  	k := keyDebit(txHash, index, block)
  1202  	v := valueDebit(amount, credKey)
  1203  
  1204  	err := ns.NestedReadWriteBucket(bucketDebits).Put(k, v)
  1205  	if err != nil {
  1206  		return errors.E(errors.IO, err)
  1207  	}
  1208  	return nil
  1209  }
  1210  
  1211  func putRawDebit(ns walletdb.ReadWriteBucket, k, v []byte) error {
  1212  	err := ns.NestedReadWriteBucket(bucketDebits).Put(k, v)
  1213  	if err != nil {
  1214  		return errors.E(errors.IO, err)
  1215  	}
  1216  	return nil
  1217  }
  1218  
  1219  func extractRawDebitHash(k []byte) []byte {
  1220  	return k[:32]
  1221  }
  1222  
  1223  func extractRawDebitTxRecordKey(k []byte) []byte {
  1224  	return k[:68]
  1225  }
  1226  
  1227  func extractRawDebitInputIndex(k []byte) uint32 {
  1228  	return byteOrder.Uint32(k[68:72])
  1229  }
  1230  
  1231  func extractRawDebitAmount(v []byte) dcrutil.Amount {
  1232  	return dcrutil.Amount(byteOrder.Uint64(v[:8]))
  1233  }
  1234  
  1235  func extractRawDebitCreditKey(v []byte) []byte {
  1236  	return v[8:80]
  1237  }
  1238  
  1239  func extractRawDebitUnspentValue(v []byte) []byte {
  1240  	return v[40:76]
  1241  }
  1242  
  1243  // existsDebit checks for the existence of a debit.  If found, the debit and
  1244  // previous credit keys are returned.  If the debit does not exist, both keys
  1245  // are nil.
  1246  func existsDebit(ns walletdb.ReadBucket, txHash *chainhash.Hash, index uint32, block *Block) (k, credKey []byte, err error) {
  1247  	k = keyDebit(txHash, index, block)
  1248  	v := ns.NestedReadBucket(bucketDebits).Get(k)
  1249  	if v == nil {
  1250  		return nil, nil, nil
  1251  	}
  1252  	if len(v) < 80 {
  1253  		return nil, nil, errors.E(errors.IO, errors.Errorf("debit len %d", len(v)))
  1254  	}
  1255  	return k, v[8:80], nil
  1256  }
  1257  
  1258  func existsInvalidatedDebit(ns walletdb.ReadBucket, txHash *chainhash.Hash, index uint32,
  1259  	block *Block) (k, credKey []byte, err error) {
  1260  	k = keyDebit(txHash, index, block)
  1261  	v := ns.NestedReadBucket(bucketStakeInvalidatedDebits).Get(k)
  1262  	if v == nil {
  1263  		return nil, nil, nil
  1264  	}
  1265  	if len(v) < 80 {
  1266  		return nil, nil, errors.E(errors.IO, errors.Errorf("debit len %d", len(v)))
  1267  	}
  1268  	return k, v[8:80], nil
  1269  }
  1270  
  1271  func deleteRawDebit(ns walletdb.ReadWriteBucket, k []byte) error {
  1272  	err := ns.NestedReadWriteBucket(bucketDebits).Delete(k)
  1273  	if err != nil {
  1274  		return errors.E(errors.IO, err)
  1275  	}
  1276  	return nil
  1277  }
  1278  
  1279  // debitIterator allows for in-order iteration of all debit records for a
  1280  // mined transaction.
  1281  //
  1282  // Example usage:
  1283  //
  1284  //	prefix := keyTxRecord(txHash, block)
  1285  //	it := makeDebitIterator(ns, prefix)
  1286  //	for it.next() {
  1287  //	        // Use it.elem
  1288  //	        // If necessary, read additional details from it.ck, it.cv
  1289  //	}
  1290  //	if it.err != nil {
  1291  //	        // Handle error
  1292  //	}
  1293  type debitIterator struct {
  1294  	c      walletdb.ReadWriteCursor // Set to nil after final iteration
  1295  	prefix []byte
  1296  	ck     []byte
  1297  	cv     []byte
  1298  	elem   DebitRecord
  1299  	err    error
  1300  }
  1301  
  1302  func makeReadDebitIterator(ns walletdb.ReadBucket, prefix []byte) debitIterator {
  1303  	c := ns.NestedReadBucket(bucketDebits).ReadCursor()
  1304  	return debitIterator{c: readCursor{c}, prefix: prefix}
  1305  }
  1306  
  1307  func (it *debitIterator) readElem() error {
  1308  	if len(it.ck) < 72 {
  1309  		return errors.E(errors.IO, errors.Errorf("debit key len %d", len(it.ck)))
  1310  	}
  1311  	if len(it.cv) < 80 {
  1312  		return errors.E(errors.IO, errors.Errorf("debit len %d", len(it.cv)))
  1313  	}
  1314  	it.elem.Index = byteOrder.Uint32(it.ck[68:72])
  1315  	it.elem.Amount = dcrutil.Amount(byteOrder.Uint64(it.cv))
  1316  	return nil
  1317  }
  1318  
  1319  func (it *debitIterator) next() bool {
  1320  	if it.c == nil {
  1321  		return false
  1322  	}
  1323  
  1324  	if it.ck == nil {
  1325  		it.ck, it.cv = it.c.Seek(it.prefix)
  1326  	} else {
  1327  		it.ck, it.cv = it.c.Next()
  1328  	}
  1329  	if !bytes.HasPrefix(it.ck, it.prefix) {
  1330  		it.c.Close()
  1331  		it.c = nil
  1332  		return false
  1333  	}
  1334  
  1335  	err := it.readElem()
  1336  	if err != nil {
  1337  		it.err = err
  1338  		return false
  1339  	}
  1340  	return true
  1341  }
  1342  
  1343  func (it *debitIterator) close() {
  1344  	if it.c == nil {
  1345  		return
  1346  	}
  1347  	it.c.Close()
  1348  }
  1349  
  1350  // All unmined transactions are saved in the unmined bucket keyed by the
  1351  // transaction hash.  The value matches that of mined transaction records:
  1352  //
  1353  //   [0:8]   Received time (8 bytes)
  1354  //   [8:]    Serialized transaction (varies)
  1355  
  1356  func putRawUnmined(ns walletdb.ReadWriteBucket, k, v []byte) error {
  1357  	err := ns.NestedReadWriteBucket(bucketUnmined).Put(k, v)
  1358  	if err != nil {
  1359  		return errors.E(errors.IO, err)
  1360  	}
  1361  	return nil
  1362  }
  1363  
  1364  func readRawUnminedHash(k []byte, txHash *chainhash.Hash) error {
  1365  	if len(k) < 32 {
  1366  		return errors.E(errors.IO, errors.Errorf("unmined key len %d", len(k)))
  1367  	}
  1368  	copy(txHash[:], k)
  1369  	return nil
  1370  }
  1371  
  1372  func existsRawUnmined(ns walletdb.ReadBucket, k []byte) (v []byte) {
  1373  	return ns.NestedReadBucket(bucketUnmined).Get(k)
  1374  }
  1375  
  1376  func deleteRawUnmined(ns walletdb.ReadWriteBucket, k []byte) error {
  1377  	err := ns.NestedReadWriteBucket(bucketUnmined).Delete(k)
  1378  	if err != nil {
  1379  		return errors.E(errors.IO, err)
  1380  	}
  1381  	return nil
  1382  }
  1383  
  1384  func fetchRawUnminedReceiveTime(v []byte) (int64, error) {
  1385  	if len(v) < 8 {
  1386  		return 0, errors.E(errors.IO, errors.Errorf("unmined len %d", len(v)))
  1387  	}
  1388  	return int64(byteOrder.Uint64(v[:8])), nil
  1389  }
  1390  
  1391  func extractRawUnminedTx(v []byte) []byte {
  1392  	return v[8:]
  1393  }
  1394  
  1395  // Unmined transactions which have been saved in an unpublished state are
  1396  // recorded as such in the unpublished bucket keyed by the transaction hash.
  1397  // The value is is a single non-zero byte if the transaction is unpublished, or
  1398  // zero or missing from the bucket when published.
  1399  
  1400  func putUnpublished(ns walletdb.ReadWriteBucket, k []byte) error {
  1401  	err := ns.NestedReadWriteBucket(bucketUnpublished).Put(k, []byte{1})
  1402  	if err != nil {
  1403  		return errors.E(errors.IO, err)
  1404  	}
  1405  	return nil
  1406  }
  1407  
  1408  func existsUnpublished(ns walletdb.ReadBucket, k []byte) bool {
  1409  	v := ns.NestedReadBucket(bucketUnpublished).Get(k)
  1410  	return len(v) == 1 && v[0] != 0
  1411  }
  1412  
  1413  func deleteUnpublished(ns walletdb.ReadWriteBucket, k []byte) error {
  1414  	err := ns.NestedReadWriteBucket(bucketUnpublished).Delete(k)
  1415  	if err != nil {
  1416  		return errors.E(errors.IO, err)
  1417  	}
  1418  	return nil
  1419  }
  1420  
  1421  // Unmined transaction credits use the canonical serialization format:
  1422  //
  1423  //	[0:32]   Transaction hash (32 bytes)
  1424  //	[32:36]  Output index (4 bytes)
  1425  //
  1426  // The value matches the format used by mined credits, but the spent flag is
  1427  // never set and the optional debit record is never included.  The simplified
  1428  // format is thus:
  1429  //
  1430  //	[0:8]   Amount (8 bytes)
  1431  //	[8]     Flags (1 byte)
  1432  //	          0x01: Unused
  1433  //	          0x02: Change
  1434  //	          0x1c: P2PKH stake flag
  1435  //	              0x00: None (translates to OP_NOP10)
  1436  //	              0x04: OP_SSTX
  1437  //	              0x08: OP_SSGEN
  1438  //	              0x0c: OP_SSRTX
  1439  //	              0x10: OP_SSTXCHANGE
  1440  //	          0x20: IsCoinbase
  1441  //	          0x40: HasExpiry
  1442  //	[9] Script type (P2PKH, P2SH, etc) and bit flag for account stored
  1443  //	[10:14] Byte index (4 bytes, uint32)
  1444  //	[14:18] Length of script (4 bytes, uint32)
  1445  //	[18:22] Account (4 bytes, uint32)
  1446  const (
  1447  	// unconfCreditKeySize is the total size of an unconfirmed credit
  1448  	// key in bytes.
  1449  	unconfCreditKeySize = 36
  1450  
  1451  	// unconfValueSizeLegacy is the total size of an unconfirmed legacy
  1452  	// credit value in bytes (version 1).
  1453  	unconfValueSizeLegacy = 9
  1454  
  1455  	// unconfValueSize is the total size of an unconfirmed credit
  1456  	// value in bytes (version 2).
  1457  	unconfValueSize = 22
  1458  )
  1459  
  1460  func valueUnminedCredit(amount dcrutil.Amount, change bool, opCode uint8,
  1461  	isCoinbase, hasExpiry bool, scrType scriptType, scrLoc, scrLen,
  1462  	account, dbVersion uint32) []byte {
  1463  
  1464  	v := make([]byte, unconfValueSize)
  1465  	byteOrder.PutUint64(v, uint64(amount))
  1466  	v[8] = condenseOpCode(opCode)
  1467  	if change {
  1468  		v[8] |= 1 << 1
  1469  	}
  1470  	if hasExpiry {
  1471  		switch {
  1472  		case dbVersion >= hasExpiryFixedVersion:
  1473  			v[8] |= 1 << 6
  1474  		case dbVersion >= hasExpiryVersion:
  1475  			v[8] |= 1 << 4
  1476  		}
  1477  	}
  1478  	if isCoinbase {
  1479  		v[8] |= 1 << 5
  1480  	}
  1481  
  1482  	v[9] = byte(scrType)
  1483  	v[9] |= accountExistsMask
  1484  	byteOrder.PutUint32(v[10:14], scrLoc)
  1485  	byteOrder.PutUint32(v[14:18], scrLen)
  1486  	byteOrder.PutUint32(v[18:22], account)
  1487  
  1488  	return v
  1489  }
  1490  
  1491  func putRawUnminedCredit(ns walletdb.ReadWriteBucket, k, v []byte) error {
  1492  	err := ns.NestedReadWriteBucket(bucketUnminedCredits).Put(k, v)
  1493  	if err != nil {
  1494  		return errors.E(errors.IO, err)
  1495  	}
  1496  	return nil
  1497  }
  1498  
  1499  func fetchRawUnminedCreditIndex(k []byte) (uint32, error) {
  1500  	if len(k) < unconfCreditKeySize {
  1501  		return 0, errors.E(errors.IO, errors.Errorf("unmined credit key len %d", len(k)))
  1502  	}
  1503  	return byteOrder.Uint32(k[32:36]), nil
  1504  }
  1505  
  1506  func fetchRawUnminedCreditAmount(v []byte) (dcrutil.Amount, error) {
  1507  	if len(v) < unconfValueSizeLegacy {
  1508  		return 0, errors.E(errors.IO, errors.Errorf("unmined credit len %d", len(v)))
  1509  	}
  1510  	return dcrutil.Amount(byteOrder.Uint64(v)), nil
  1511  }
  1512  
  1513  func fetchRawUnminedCreditAmountChange(v []byte) (dcrutil.Amount, bool, error) {
  1514  	if len(v) < unconfValueSizeLegacy {
  1515  		return 0, false, errors.E(errors.IO, errors.Errorf("unmined credit len %d", len(v)))
  1516  	}
  1517  	amt := dcrutil.Amount(byteOrder.Uint64(v))
  1518  	change := v[8]&(1<<1) != 0
  1519  	return amt, change, nil
  1520  }
  1521  
  1522  func fetchRawUnminedCreditTagOpCode(v []byte) uint8 {
  1523  	return expandOpCode(v[8])
  1524  }
  1525  
  1526  func fetchRawUnminedCreditTagIsCoinbase(v []byte) bool {
  1527  	return v[8]&(1<<5) != 0
  1528  }
  1529  
  1530  func fetchRawUnminedCreditScriptType(v []byte) scriptType {
  1531  	if len(v) < unconfValueSize {
  1532  		return scriptTypeNonexisting
  1533  	}
  1534  	return scriptType(v[9] & ^accountExistsMask)
  1535  }
  1536  
  1537  func fetchRawUnminedCreditScriptOffset(v []byte) uint32 {
  1538  	if len(v) < unconfValueSize {
  1539  		return 0
  1540  	}
  1541  	return byteOrder.Uint32(v[10:14])
  1542  }
  1543  
  1544  func fetchRawUnminedCreditScriptLength(v []byte) uint32 {
  1545  	if len(v) < unconfValueSize {
  1546  		return 0
  1547  	}
  1548  	return byteOrder.Uint32(v[14:18])
  1549  }
  1550  
  1551  func fetchRawUnminedCreditAccount(v []byte) (uint32, error) {
  1552  	if len(v) < unconfValueSize {
  1553  		return 0, errors.E(errors.IO, errors.Errorf("unmined credit len %d", len(v)))
  1554  	}
  1555  
  1556  	// Was the account ever set?
  1557  	if v[9]&accountExistsMask != accountExistsMask {
  1558  		return 0, errors.E(errors.IO, "unmined credit account unset")
  1559  	}
  1560  
  1561  	return byteOrder.Uint32(v[18:22]), nil
  1562  }
  1563  
  1564  func existsRawUnminedCredit(ns walletdb.ReadBucket, k []byte) []byte {
  1565  	return ns.NestedReadBucket(bucketUnminedCredits).Get(k)
  1566  }
  1567  
  1568  func deleteRawUnminedCredit(ns walletdb.ReadWriteBucket, k []byte) error {
  1569  	err := ns.NestedReadWriteBucket(bucketUnminedCredits).Delete(k)
  1570  	if err != nil {
  1571  		return errors.E(errors.IO, err)
  1572  	}
  1573  	return nil
  1574  }
  1575  
  1576  // unminedCreditIterator allows for cursor iteration over all credits, in order,
  1577  // from a single unmined transaction.
  1578  //
  1579  //	Example usage:
  1580  //
  1581  //	 it := makeUnminedCreditIterator(ns, txHash)
  1582  //	 for it.next() {
  1583  //	         // Use it.elem, it.ck and it.cv
  1584  //	         // Optionally, use it.delete() to remove this k/v pair
  1585  //	 }
  1586  //	 if it.err != nil {
  1587  //	         // Handle error
  1588  //	 }
  1589  //
  1590  // The spentness of the credit is not looked up for performance reasons (because
  1591  // for unspent credits, it requires another lookup in another bucket).  If this
  1592  // is needed, it may be checked like this:
  1593  //
  1594  //	spent := existsRawUnminedInput(ns, it.ck) != nil
  1595  type unminedCreditIterator struct {
  1596  	c         walletdb.ReadWriteCursor
  1597  	dbVersion uint32
  1598  	prefix    []byte
  1599  	ck        []byte
  1600  	cv        []byte
  1601  	elem      CreditRecord
  1602  	err       error
  1603  }
  1604  
  1605  type readCursor struct {
  1606  	walletdb.ReadCursor
  1607  }
  1608  
  1609  func (r readCursor) Delete() error {
  1610  	return errors.E(errors.IO, "delete called from read-only cursor")
  1611  }
  1612  
  1613  func makeReadUnminedCreditIterator(ns walletdb.ReadBucket, txHash *chainhash.Hash, dbVersion uint32) unminedCreditIterator {
  1614  	c := ns.NestedReadBucket(bucketUnminedCredits).ReadCursor()
  1615  	return unminedCreditIterator{c: readCursor{c}, prefix: txHash[:], dbVersion: dbVersion}
  1616  }
  1617  
  1618  func (it *unminedCreditIterator) readElem() error {
  1619  	index, err := fetchRawUnminedCreditIndex(it.ck)
  1620  	if err != nil {
  1621  		return err
  1622  	}
  1623  	amount, change, err := fetchRawUnminedCreditAmountChange(it.cv)
  1624  	if err != nil {
  1625  		return err
  1626  	}
  1627  
  1628  	it.elem.Index = index
  1629  	it.elem.Amount = amount
  1630  	it.elem.Change = change
  1631  	it.elem.HasExpiry = fetchRawCreditHasExpiry(it.cv, it.dbVersion)
  1632  	// Spent intentionally not set
  1633  
  1634  	return nil
  1635  }
  1636  
  1637  func (it *unminedCreditIterator) next() bool {
  1638  	if it.c == nil {
  1639  		return false
  1640  	}
  1641  
  1642  	if it.ck == nil {
  1643  		it.ck, it.cv = it.c.Seek(it.prefix)
  1644  	} else {
  1645  		it.ck, it.cv = it.c.Next()
  1646  	}
  1647  	if !bytes.HasPrefix(it.ck, it.prefix) {
  1648  		it.c.Close()
  1649  		it.c = nil
  1650  		return false
  1651  	}
  1652  
  1653  	err := it.readElem()
  1654  	if err != nil {
  1655  		it.err = err
  1656  		return false
  1657  	}
  1658  	return true
  1659  }
  1660  
  1661  // unavailable until https://github.com/boltdb/bolt/issues/620 is fixed.
  1662  // func (it *unminedCreditIterator) delete() error {
  1663  // 	err := it.c.Delete()
  1664  // 	if err != nil {
  1665  // 		return errors.E(errors.IO, err)
  1666  // 	}
  1667  // 	return nil
  1668  // }
  1669  
  1670  func (it *unminedCreditIterator) close() {
  1671  	if it.c == nil {
  1672  		return
  1673  	}
  1674  	it.c.Close()
  1675  }
  1676  
  1677  // OutPoints spent by unmined transactions are saved in the unmined inputs
  1678  // bucket.  This bucket maps between each previous output spent, for both mined
  1679  // and unmined transactions, to the hash of the unmined transaction.
  1680  //
  1681  // The key is serialized as such:
  1682  //
  1683  //   [0:32]   Transaction hash (32 bytes)
  1684  //   [32:36]  Output index (4 bytes)
  1685  //
  1686  // The value is serialized as such:
  1687  //
  1688  //   [0:32]   Transaction hash (32 bytes)
  1689  
  1690  func putRawUnminedInput(ns walletdb.ReadWriteBucket, k, v []byte) error {
  1691  	err := ns.NestedReadWriteBucket(bucketUnminedInputs).Put(k, v)
  1692  	if err != nil {
  1693  		return errors.E(errors.IO, err)
  1694  	}
  1695  	return nil
  1696  }
  1697  
  1698  func existsRawUnminedInput(ns walletdb.ReadBucket, k []byte) (v []byte) {
  1699  	return ns.NestedReadBucket(bucketUnminedInputs).Get(k)
  1700  }
  1701  
  1702  func deleteRawUnminedInput(ns walletdb.ReadWriteBucket, k []byte) error {
  1703  	err := ns.NestedReadWriteBucket(bucketUnminedInputs).Delete(k)
  1704  	if err != nil {
  1705  		return errors.E(errors.IO, err)
  1706  	}
  1707  	return nil
  1708  }
  1709  
  1710  func readRawUnminedInputSpenderHash(v []byte, hash *chainhash.Hash) {
  1711  	copy(hash[:], v[:32])
  1712  }
  1713  
  1714  // Ticket purchase metadata is recorded in the tickets bucket.  The bucket key
  1715  // is the ticket purchase transaction hash.  The value is serialized as such:
  1716  //
  1717  //   [0:4]		Block height ticket was picked (-1 if not picked)
  1718  
  1719  func valueTicketRecord(pickedHeight int32) []byte {
  1720  	v := make([]byte, 4)
  1721  	byteOrder.PutUint32(v, uint32(pickedHeight))
  1722  	return v
  1723  }
  1724  
  1725  func putRawTicketRecord(ns walletdb.ReadWriteBucket, k, v []byte) error {
  1726  	err := ns.NestedReadWriteBucket(bucketTickets).Put(k, v)
  1727  	if err != nil {
  1728  		return errors.E(errors.IO, err)
  1729  	}
  1730  	return nil
  1731  }
  1732  
  1733  func putTicketRecord(ns walletdb.ReadWriteBucket, ticketHash *chainhash.Hash, pickedHeight int32) error {
  1734  	k := ticketHash[:]
  1735  	v := valueTicketRecord(pickedHeight)
  1736  	return putRawTicketRecord(ns, k, v)
  1737  }
  1738  
  1739  func existsRawTicketRecord(ns walletdb.ReadBucket, k []byte) (v []byte) {
  1740  	return ns.NestedReadBucket(bucketTickets).Get(k)
  1741  }
  1742  
  1743  func extractRawTicketPickedHeight(v []byte) int32 {
  1744  	return int32(byteOrder.Uint32(v))
  1745  }
  1746  
  1747  // The multisig bucket stores utxos that are P2SH output scripts to the user.
  1748  // These are handled separately and less efficiently than the more typical
  1749  // P2PKH types.
  1750  // Transactions with multisig outputs are keyed to serialized outpoints:
  1751  // [0:32]    Hash (32 bytes)
  1752  // [32:36]   Index (uint32)
  1753  //
  1754  // The value is the following:
  1755  // [0:20]    P2SH Hash (20 bytes)
  1756  // [20]      m (in m-of-n) (uint8)
  1757  // [21]      n (in m-of-n) (uint8)
  1758  // [22]      Flags (1 byte)
  1759  //
  1760  //	[0]: Spent
  1761  //	[1]: Tree
  1762  //
  1763  // [23:55]   Block hash (32 byte hash)
  1764  // [55:59]   Block height (uint32)
  1765  // [59:67]   Amount (int64)
  1766  // [67:99]   SpentBy (32 byte hash)
  1767  // [99:103]  SpentByIndex (uint32)
  1768  // [103:135] TxHash (32 byte hash)
  1769  //
  1770  // The structure is set up so that the user may easily spend from any unspent
  1771  // P2SH multisig outpoints they own an address in.
  1772  func keyMultisigOut(hash chainhash.Hash, index uint32) []byte {
  1773  	return canonicalOutPoint(&hash, index)
  1774  }
  1775  
  1776  func valueMultisigOut(sh [ripemd160.Size]byte, m uint8, n uint8,
  1777  	spent bool, tree int8, blockHash chainhash.Hash,
  1778  	blockHeight uint32, amount dcrutil.Amount, spentBy chainhash.Hash,
  1779  	sbi uint32, txHash chainhash.Hash) []byte {
  1780  	v := make([]byte, 135)
  1781  
  1782  	copy(v[0:20], sh[0:20])
  1783  	v[20] = m
  1784  	v[21] = n
  1785  	v[22] = uint8(0)
  1786  
  1787  	if spent {
  1788  		v[22] |= 1 << 0
  1789  	}
  1790  
  1791  	if tree == wire.TxTreeStake {
  1792  		v[22] |= 1 << 1
  1793  	}
  1794  
  1795  	copy(v[23:55], blockHash[:])
  1796  	byteOrder.PutUint32(v[55:59], blockHeight)
  1797  	byteOrder.PutUint64(v[59:67], uint64(amount))
  1798  
  1799  	copy(v[67:99], spentBy[:])
  1800  	byteOrder.PutUint32(v[99:103], sbi)
  1801  
  1802  	copy(v[103:135], txHash[:])
  1803  
  1804  	return v
  1805  }
  1806  
  1807  func fetchMultisigOut(k, v []byte) (*MultisigOut, error) {
  1808  	if len(k) != 36 {
  1809  		return nil, errors.E(errors.IO, "multisig output key len %d", len(k))
  1810  	}
  1811  	if len(v) != 135 {
  1812  		return nil, errors.E(errors.IO, "multisig output len %d", len(v))
  1813  	}
  1814  
  1815  	var mso MultisigOut
  1816  
  1817  	var op wire.OutPoint
  1818  	err := readCanonicalOutPoint(k, &op)
  1819  	if err != nil {
  1820  		return nil, err
  1821  	}
  1822  	mso.OutPoint = &op
  1823  	mso.OutPoint.Tree = wire.TxTreeRegular
  1824  
  1825  	copy(mso.ScriptHash[0:20], v[0:20])
  1826  
  1827  	mso.M = v[20]
  1828  	mso.N = v[21]
  1829  	mso.Spent = v[22]&(1<<0) != 0
  1830  	mso.Tree = 0
  1831  	isStakeTree := v[22]&(1<<1) != 0
  1832  	if isStakeTree {
  1833  		mso.Tree = 1
  1834  	}
  1835  
  1836  	copy(mso.BlockHash[0:32], v[23:55])
  1837  	mso.BlockHeight = byteOrder.Uint32(v[55:59])
  1838  	mso.Amount = dcrutil.Amount(byteOrder.Uint64(v[59:67]))
  1839  
  1840  	copy(mso.SpentBy[0:32], v[67:99])
  1841  	mso.SpentByIndex = byteOrder.Uint32(v[99:103])
  1842  
  1843  	copy(mso.TxHash[0:32], v[103:135])
  1844  
  1845  	return &mso, nil
  1846  }
  1847  
  1848  func fetchMultisigOutScrHash(v []byte) [ripemd160.Size]byte {
  1849  	var sh [ripemd160.Size]byte
  1850  	copy(sh[0:20], v[0:20])
  1851  	return sh
  1852  }
  1853  
  1854  func fetchMultisigOutMN(v []byte) (uint8, uint8) {
  1855  	return v[20], v[21]
  1856  }
  1857  
  1858  func fetchMultisigOutSpent(v []byte) bool {
  1859  	spent := v[22]&(1<<0) != 0
  1860  
  1861  	return spent
  1862  }
  1863  
  1864  func fetchMultisigOutTree(v []byte) int8 {
  1865  	isStakeTree := v[22]&(1<<1) != 0
  1866  	tree := wire.TxTreeRegular
  1867  	if isStakeTree {
  1868  		tree = wire.TxTreeStake
  1869  	}
  1870  
  1871  	return tree
  1872  }
  1873  
  1874  func fetchMultisigOutSpentVerbose(v []byte) (bool, chainhash.Hash, uint32) {
  1875  	spent := v[22]&(1<<0) != 0
  1876  	spentBy := chainhash.Hash{}
  1877  	copy(spentBy[0:32], v[67:99])
  1878  	spentIndex := byteOrder.Uint32(v[99:103])
  1879  
  1880  	return spent, spentBy, spentIndex
  1881  }
  1882  
  1883  func fetchMultisigOutMined(v []byte) (chainhash.Hash, uint32) {
  1884  	blockHash := chainhash.Hash{}
  1885  	copy(blockHash[0:32], v[23:55])
  1886  	blockHeight := byteOrder.Uint32(v[55:59])
  1887  
  1888  	return blockHash, blockHeight
  1889  }
  1890  
  1891  func fetchMultisigOutAmount(v []byte) dcrutil.Amount {
  1892  	return dcrutil.Amount(byteOrder.Uint64(v[59:67]))
  1893  }
  1894  
  1895  func setMultisigOutSpent(v []byte, spendHash chainhash.Hash, spendIndex uint32) {
  1896  	spentByte := uint8(0)
  1897  	spentByte |= 1 << 0
  1898  	v[22] = spentByte
  1899  	copy(v[67:99], spendHash[:])
  1900  	byteOrder.PutUint32(v[99:103], spendIndex)
  1901  }
  1902  
  1903  func setMultisigOutUnSpent(v []byte) {
  1904  	empty := chainhash.Hash{}
  1905  	spentByte := uint8(0)
  1906  	v[22] = spentByte
  1907  	copy(v[67:98], empty[:])
  1908  	byteOrder.PutUint32(v[99:103], 0xFFFFFFFF)
  1909  }
  1910  
  1911  func setMultisigOutMined(v []byte, blockHash chainhash.Hash,
  1912  	blockHeight uint32) {
  1913  	copy(v[23:55], blockHash[:])
  1914  	byteOrder.PutUint32(v[55:59], blockHeight)
  1915  }
  1916  
  1917  func setMultisigOutUnmined(v []byte) {
  1918  	empty := chainhash.Hash{}
  1919  	copy(v[23:55], empty[:])
  1920  	byteOrder.PutUint32(v[55:59], 0)
  1921  }
  1922  
  1923  func putMultisigOutRawValues(ns walletdb.ReadWriteBucket, k []byte, v []byte) error {
  1924  	err := ns.NestedReadWriteBucket(bucketMultisig).Put(k, v)
  1925  	if err != nil {
  1926  		return errors.E(errors.IO, err)
  1927  	}
  1928  	return nil
  1929  }
  1930  
  1931  func existsMultisigOut(ns walletdb.ReadBucket, k []byte) []byte {
  1932  	return ns.NestedReadBucket(bucketMultisig).Get(k)
  1933  }
  1934  
  1935  func existsMultisigOutCopy(ns walletdb.ReadBucket, k []byte) []byte {
  1936  	vOrig := ns.NestedReadBucket(bucketMultisig).Get(k)
  1937  	if vOrig == nil {
  1938  		return nil
  1939  	}
  1940  	v := make([]byte, 135)
  1941  	copy(v, vOrig)
  1942  	return v
  1943  }
  1944  
  1945  func putMultisigOutUS(ns walletdb.ReadWriteBucket, k []byte) error {
  1946  	blank := []byte{0x00}
  1947  	err := ns.NestedReadWriteBucket(bucketMultisigUsp).Put(k, blank)
  1948  	if err != nil {
  1949  		return errors.E(errors.IO, err)
  1950  	}
  1951  	return nil
  1952  }
  1953  
  1954  func deleteMultisigOutUS(ns walletdb.ReadWriteBucket, k []byte) error {
  1955  	err := ns.NestedReadWriteBucket(bucketMultisigUsp).Delete(k)
  1956  	if err != nil {
  1957  		return errors.E(errors.IO, err)
  1958  	}
  1959  	return nil
  1960  }
  1961  
  1962  func existsMultisigOutUS(ns walletdb.ReadBucket, k []byte) bool {
  1963  	v := ns.NestedReadBucket(bucketMultisigUsp).Get(k)
  1964  	return v != nil
  1965  }
  1966  
  1967  // The compact filter bucket stores serialized regular compact filters for
  1968  // blocks.  This bucket was added during a database upgrade, but the actual
  1969  // filters are not saved during the upgrade and an additional step to save all
  1970  // compact filters for main chain blocks is required before any additional
  1971  // blocks can be processed.
  1972  //
  1973  // Compact filters are keyed by their block hash.  The value is the serialized
  1974  // as such:
  1975  //
  1976  // 	[0:16]	Key used to search for values in the filter (i.e. the
  1977  // 		merkle root of the block).
  1978  // 	[16:]	The data for the filter.
  1979  
  1980  func valueRawCFilter2(key [16]byte, data []byte) []byte {
  1981  	v := make([]byte, 16+len(data))
  1982  	copy(v, key[:])
  1983  	copy(v[16:], data)
  1984  	return v
  1985  }
  1986  
  1987  func putRawCFilter(ns walletdb.ReadWriteBucket, k, v []byte) error {
  1988  	return ns.NestedReadWriteBucket(bucketCFilters).Put(k, v)
  1989  }
  1990  
  1991  func fetchRawCFilter2(ns walletdb.ReadBucket, k []byte) ([16]byte, []byte, error) {
  1992  	var bcf2Key [16]byte
  1993  	v := ns.NestedReadBucket(bucketCFilters).Get(k)
  1994  	if v == nil {
  1995  		var hash chainhash.Hash
  1996  		copy(hash[:], k)
  1997  		return bcf2Key, nil, errors.E(errors.NotExist, errors.Errorf("no cfilter saved for block %v", &hash))
  1998  	}
  1999  	if len(v) < 16 {
  2000  		return bcf2Key, nil, errors.E(errors.IO, errors.Errorf("cfilter data len: %d", len(v)))
  2001  	}
  2002  	copy(bcf2Key[:], v)
  2003  	return bcf2Key, v[16:], nil
  2004  }
  2005  
  2006  // The ticket commitments bucket stores serialized information about ticket
  2007  // commitment outputs which belong to the wallet.
  2008  //
  2009  // The keys in this bucket use the canonicalOutPoint format (that is,
  2010  // transaction hash and output index) of the corresponding ticket commitment.
  2011  //
  2012  //   [0:32]  Transaction hash (32 bytes)
  2013  //   [32:36] Output index (4 bytes)
  2014  //
  2015  // Values in this bucket are serialized using the following format:
  2016  //
  2017  //   [0:8]   Amount (8 bytes)
  2018  //   [8:12]  Account Index (4 bytes)
  2019  
  2020  func keyTicketCommitment(ticketHash chainhash.Hash, index uint32) []byte {
  2021  	return canonicalOutPoint(&ticketHash, index)
  2022  }
  2023  
  2024  func valueTicketCommitment(amount dcrutil.Amount, account uint32) []byte {
  2025  	v := make([]byte, 12)
  2026  	byteOrder.PutUint64(v, uint64(amount))
  2027  	byteOrder.PutUint32(v[8:], account)
  2028  	return v
  2029  }
  2030  
  2031  func existsRawTicketCommitment(ns walletdb.ReadBucket, k []byte) []byte {
  2032  	return ns.NestedReadBucket(bucketTicketCommitments).Get(k)
  2033  }
  2034  
  2035  func putRawTicketCommitment(ns walletdb.ReadWriteBucket, k, v []byte) error {
  2036  	err := ns.NestedReadWriteBucket(bucketTicketCommitments).Put(k, v)
  2037  	if err != nil {
  2038  		return errors.E(errors.IO, err)
  2039  	}
  2040  	return nil
  2041  }
  2042  
  2043  func fetchRawTicketCommitmentAmount(v []byte) (dcrutil.Amount, error) {
  2044  	if len(v) < 8 {
  2045  		return 0, errors.E(errors.IO, errors.Errorf("ticket commitment amount %d", len(v)))
  2046  	}
  2047  	return dcrutil.Amount(byteOrder.Uint64(v)), nil
  2048  }
  2049  
  2050  func fetchRawTicketCommitmentAccount(v []byte) (uint32, error) {
  2051  	if len(v) < 12 {
  2052  		return 0, errors.E(errors.IO, errors.Errorf("ticket commitment acount %d", len(v)))
  2053  	}
  2054  	return byteOrder.Uint32(v[8:]), nil
  2055  }
  2056  
  2057  func deleteRawTicketCommitment(ns walletdb.ReadWriteBucket, k []byte) error {
  2058  	err := ns.NestedReadWriteBucket(bucketTicketCommitments).Delete(k)
  2059  	if err != nil {
  2060  		return errors.E(errors.IO, err)
  2061  	}
  2062  	return nil
  2063  }
  2064  
  2065  // The Unspent Ticket Commitment bucket stores serialized information about
  2066  // ticket commitments owned by the wallet that are still outstanding in live
  2067  // tickets. This is meant to work as an index for fast balance calculations and
  2068  // to be used in concert with the ticket commitment bucket.
  2069  //
  2070  // The keys in this bucket use the same keys as the corresponding element in the
  2071  // bucketTicketCommitment.
  2072  //
  2073  // Values in this bucket are serialized using the following format:
  2074  //
  2075  //   [0]  Flags (1 byte)
  2076  //             0x01: UnminedSpent (whether there is an unmined tx redeeming this commitment)
  2077  
  2078  func valueUnspentTicketCommitment(unminedSpent bool) []byte {
  2079  	flags := uint8(0)
  2080  	if unminedSpent {
  2081  		flags |= 0x01
  2082  	}
  2083  
  2084  	v := make([]byte, 1)
  2085  	v[0] = flags
  2086  
  2087  	return v
  2088  }
  2089  
  2090  func putRawUnspentTicketCommitment(ns walletdb.ReadWriteBucket, k, v []byte) error {
  2091  	err := ns.NestedReadWriteBucket(bucketTicketCommitmentsUsp).Put(k, v)
  2092  	if err != nil {
  2093  		return errors.E(errors.IO, err)
  2094  	}
  2095  	return nil
  2096  }
  2097  
  2098  func deleteRawUnspentTicketCommitment(ns walletdb.ReadWriteBucket, k []byte) error {
  2099  	err := ns.NestedReadWriteBucket(bucketTicketCommitmentsUsp).Delete(k)
  2100  	if err != nil {
  2101  		return errors.E(errors.IO, err)
  2102  	}
  2103  	return nil
  2104  }
  2105  
  2106  type unspentTicketCommitsIterator struct {
  2107  	c  walletdb.ReadCursor
  2108  	ns walletdb.ReadBucket
  2109  	ck []byte
  2110  
  2111  	unminedSpent bool
  2112  	amount       dcrutil.Amount
  2113  	account      uint32
  2114  
  2115  	err error
  2116  }
  2117  
  2118  func makeUnspentTicketCommitsIterator(ns walletdb.ReadBucket) *unspentTicketCommitsIterator {
  2119  	c := ns.NestedReadBucket(bucketTicketCommitmentsUsp).ReadCursor()
  2120  	return &unspentTicketCommitsIterator{c: c, ns: ns}
  2121  }
  2122  
  2123  func (it *unspentTicketCommitsIterator) next() bool {
  2124  	if it.c == nil {
  2125  		return false
  2126  	}
  2127  
  2128  	var v []byte
  2129  
  2130  	if it.ck == nil {
  2131  		it.ck, v = it.c.Seek(nil)
  2132  	} else {
  2133  		it.ck, v = it.c.Next()
  2134  	}
  2135  
  2136  	if it.ck == nil {
  2137  		it.c.Close()
  2138  		it.c = nil
  2139  		return false
  2140  	}
  2141  
  2142  	if len(v) < 1 {
  2143  		it.err = errors.E(errors.IO, errors.Errorf("wrong unspent ticket commitment len %d", len(v)))
  2144  		return false
  2145  	}
  2146  
  2147  	it.unminedSpent = v[0]&0x01 == 0x01
  2148  
  2149  	// Fetch the original commitment amount and account.
  2150  	v = existsRawTicketCommitment(it.ns, it.ck)
  2151  	it.account, it.err = fetchRawTicketCommitmentAccount(v)
  2152  	if it.err != nil {
  2153  		return false
  2154  	}
  2155  	it.amount, it.err = fetchRawTicketCommitmentAmount(v)
  2156  
  2157  	return it.err == nil
  2158  }
  2159  
  2160  func (it *unspentTicketCommitsIterator) close() {
  2161  	if it.c == nil {
  2162  		return
  2163  	}
  2164  	it.c.Close()
  2165  }
  2166  
  2167  // createStore creates the tx store (with the latest db version) in the passed
  2168  // namespace.
  2169  func createStore(ns walletdb.ReadWriteBucket, chainParams *chaincfg.Params) error {
  2170  	// Ensure that nothing currently exists in the namespace bucket.
  2171  	c := ns.ReadCursor()
  2172  	defer c.Close()
  2173  	ck, cv := c.First()
  2174  	if ck != nil || cv != nil {
  2175  		return errors.E(errors.IO, "bucket is not empty")
  2176  	}
  2177  
  2178  	// Save the creation date of the store.
  2179  	v := make([]byte, 8)
  2180  	byteOrder.PutUint64(v, uint64(time.Now().Unix()))
  2181  	err := ns.Put(rootCreateDate, v)
  2182  	if err != nil {
  2183  		return errors.E(errors.IO, err)
  2184  	}
  2185  
  2186  	// Write a zero balance.
  2187  	v = make([]byte, 8)
  2188  	err = ns.Put(rootMinedBalance, v)
  2189  	if err != nil {
  2190  		return errors.E(errors.IO, err)
  2191  	}
  2192  
  2193  	_, err = ns.CreateBucket(bucketBlocks)
  2194  	if err != nil {
  2195  		return errors.E(errors.IO, err)
  2196  	}
  2197  
  2198  	_, err = ns.CreateBucket(bucketHeaders)
  2199  	if err != nil {
  2200  		return errors.E(errors.IO, err)
  2201  	}
  2202  
  2203  	_, err = ns.CreateBucket(bucketTxRecords)
  2204  	if err != nil {
  2205  		return errors.E(errors.IO, err)
  2206  	}
  2207  
  2208  	_, err = ns.CreateBucket(bucketCredits)
  2209  	if err != nil {
  2210  		return errors.E(errors.IO, err)
  2211  	}
  2212  
  2213  	_, err = ns.CreateBucket(bucketDebits)
  2214  	if err != nil {
  2215  		return errors.E(errors.IO, err)
  2216  	}
  2217  
  2218  	_, err = ns.CreateBucket(bucketUnspent)
  2219  	if err != nil {
  2220  		return errors.E(errors.IO, err)
  2221  	}
  2222  
  2223  	_, err = ns.CreateBucket(bucketUnmined)
  2224  	if err != nil {
  2225  		return errors.E(errors.IO, err)
  2226  	}
  2227  
  2228  	_, err = ns.CreateBucket(bucketUnminedCredits)
  2229  	if err != nil {
  2230  		return errors.E(errors.IO, err)
  2231  	}
  2232  
  2233  	_, err = ns.CreateBucket(bucketUnminedInputs)
  2234  	if err != nil {
  2235  		return errors.E(errors.IO, err)
  2236  	}
  2237  
  2238  	_, err = ns.CreateBucket(bucketScripts)
  2239  	if err != nil {
  2240  		return errors.E(errors.IO, err)
  2241  	}
  2242  
  2243  	_, err = ns.CreateBucket(bucketMultisig)
  2244  	if err != nil {
  2245  		return errors.E(errors.IO, err)
  2246  	}
  2247  
  2248  	_, err = ns.CreateBucket(bucketMultisigUsp)
  2249  	if err != nil {
  2250  		return errors.E(errors.IO, err)
  2251  	}
  2252  
  2253  	_, err = ns.CreateBucket(bucketStakeInvalidatedCredits)
  2254  	if err != nil {
  2255  		return errors.E(errors.IO, err)
  2256  	}
  2257  	_, err = ns.CreateBucket(bucketStakeInvalidatedDebits)
  2258  	if err != nil {
  2259  		return errors.E(errors.IO, err)
  2260  	}
  2261  
  2262  	// Insert the genesis block header.
  2263  	var serializedGenesisBlock RawBlockHeader
  2264  	buf := bytes.NewBuffer(serializedGenesisBlock[:0])
  2265  	err = chainParams.GenesisBlock.Header.Serialize(buf)
  2266  	if err != nil {
  2267  		// we have bigger problems.
  2268  		panic(err)
  2269  	}
  2270  	err = putRawBlockHeader(ns, keyBlockHeader(&chainParams.GenesisHash),
  2271  		serializedGenesisBlock[:])
  2272  	if err != nil {
  2273  		return err
  2274  	}
  2275  
  2276  	// Insert block record for the genesis block.
  2277  	genesisBlockKey := keyBlockRecord(0)
  2278  	genesisBlockVal := valueBlockRecordEmptyFromHeader(
  2279  		chainParams.GenesisHash[:], serializedGenesisBlock[:])
  2280  	err = putRawBlockRecord(ns, genesisBlockKey, genesisBlockVal)
  2281  	if err != nil {
  2282  		return err
  2283  	}
  2284  
  2285  	// Mark the genesis block as the tip block.
  2286  	err = ns.Put(rootTipBlock, chainParams.GenesisHash[:])
  2287  	if err != nil {
  2288  		return errors.E(errors.IO, err)
  2289  	}
  2290  
  2291  	return nil
  2292  }
  2293  
  2294  // upgradeTxDB performs any necessary upgrades to the transaction history
  2295  // contained in the wallet database, namespaced by the top level bucket key
  2296  // namespaceKey.
  2297  func upgradeTxDB(ns walletdb.ReadWriteBucket, chainParams *chaincfg.Params) error {
  2298  	v := ns.Get(rootVersion)
  2299  	if len(v) != 4 {
  2300  		return errors.E(errors.IO, "no transaction store version")
  2301  	}
  2302  	version := byteOrder.Uint32(v)
  2303  
  2304  	// Versions start at 1, 0 is an error.
  2305  	if version == 0 {
  2306  		return errors.E(errors.IO, "invalid transaction store version 0")
  2307  	}
  2308  
  2309  	// Perform version upgrades as necessary.
  2310  	for {
  2311  		var err error
  2312  		switch version {
  2313  		case 1:
  2314  			err = upgradeToVersion2(ns)
  2315  		case 2:
  2316  			err = upgradeToVersion3(ns, chainParams)
  2317  		default: // >= 3
  2318  			return nil
  2319  		}
  2320  		if err != nil {
  2321  			return err
  2322  		}
  2323  		version++
  2324  	}
  2325  }
  2326  
  2327  // upgradeToVersion2 upgrades the transaction store from version 1 to version 2.
  2328  // This must only be called after the caller has asserted the database is
  2329  // currently at version 1.  This upgrade is only a version bump as the new DB
  2330  // format is forwards compatible with version 1, but old software that does not
  2331  // know about version 2 should not be opening the upgraded DBs.
  2332  func upgradeToVersion2(ns walletdb.ReadWriteBucket) error {
  2333  	versionBytes := make([]byte, 4)
  2334  	byteOrder.PutUint32(versionBytes, 2)
  2335  	err := ns.Put(rootVersion, versionBytes)
  2336  	if err != nil {
  2337  		return errors.E(errors.IO, err)
  2338  	}
  2339  	return nil
  2340  }
  2341  
  2342  // upgradeToVersion3 performs an upgrade from version 2 to 3.  The store must
  2343  // already be at version 2.
  2344  //
  2345  // This update adds a new nested bucket in the namespace bucket for block
  2346  // headers and a new namespace k/v pair for the current tip block.
  2347  //
  2348  // Headers, except for the genesis block, are not immediately filled in during
  2349  // the upgrade (the information is not available) but should be inserted by the
  2350  // caller along with setting the best block.  Some features now require headers
  2351  // to be saved, so if this step is skipped the store will not operate correctly.
  2352  //
  2353  // In addition to the headers, an additional byte is added to the block record
  2354  // values at position 42, between the vote bits and the number of
  2355  // transactions.  This byte is used as a boolean and records whether or not the
  2356  // block has been stake invalidated by the next block in the main chain.
  2357  func upgradeToVersion3(ns walletdb.ReadWriteBucket, chainParams *chaincfg.Params) error {
  2358  	versionBytes := make([]byte, 4)
  2359  	byteOrder.PutUint32(versionBytes, 3)
  2360  	err := ns.Put(rootVersion, versionBytes)
  2361  	if err != nil {
  2362  		return errors.E(errors.IO, err)
  2363  	}
  2364  
  2365  	_, err = ns.CreateBucket(bucketHeaders)
  2366  	if err != nil {
  2367  		return errors.E(errors.IO, err)
  2368  	}
  2369  	_, err = ns.CreateBucket(bucketStakeInvalidatedCredits)
  2370  	if err != nil {
  2371  		return errors.E(errors.IO, err)
  2372  	}
  2373  	_, err = ns.CreateBucket(bucketStakeInvalidatedDebits)
  2374  	if err != nil {
  2375  		return errors.E(errors.IO, err)
  2376  	}
  2377  
  2378  	// For all block records, add the byte for marking stake invalidation.  The
  2379  	// function passed to ForEach may not modify the bucket, so record all
  2380  	// values and write the updates outside the ForEach.
  2381  	type kvpair struct{ k, v []byte }
  2382  	var blockRecsToUpgrade []kvpair
  2383  	blockRecordsBucket := ns.NestedReadWriteBucket(bucketBlocks)
  2384  	err = blockRecordsBucket.ForEach(func(k, v []byte) error {
  2385  		blockRecsToUpgrade = append(blockRecsToUpgrade, kvpair{k, v})
  2386  		return nil
  2387  	})
  2388  	if err != nil {
  2389  		return errors.E(errors.IO, err)
  2390  	}
  2391  	for _, kvp := range blockRecsToUpgrade {
  2392  		v := make([]byte, len(kvp.v)+1)
  2393  		copy(v, kvp.v[:42])
  2394  		copy(v[43:], kvp.v[42:])
  2395  		err = blockRecordsBucket.Put(kvp.k, v)
  2396  		if err != nil {
  2397  			return errors.E(errors.IO, err)
  2398  		}
  2399  	}
  2400  
  2401  	// Insert the genesis block header.
  2402  	var serializedGenesisBlock RawBlockHeader
  2403  	buf := bytes.NewBuffer(serializedGenesisBlock[:0])
  2404  	err = chainParams.GenesisBlock.Header.Serialize(buf)
  2405  	if err != nil {
  2406  		// we have bigger problems.
  2407  		panic(err)
  2408  	}
  2409  	err = putRawBlockHeader(ns, keyBlockHeader(&chainParams.GenesisHash),
  2410  		serializedGenesisBlock[:])
  2411  	if err != nil {
  2412  		return err
  2413  	}
  2414  
  2415  	// Insert block record for the genesis block if one doesn't yet exist.
  2416  	genesisBlockKey, genesisBlockVal := existsBlockRecord(ns, 0)
  2417  	if genesisBlockVal == nil {
  2418  		genesisBlockVal = valueBlockRecordEmptyFromHeader(
  2419  			chainParams.GenesisHash[:], serializedGenesisBlock[:])
  2420  		err = putRawBlockRecord(ns, genesisBlockKey, genesisBlockVal)
  2421  		if err != nil {
  2422  			return err
  2423  		}
  2424  	}
  2425  
  2426  	// Mark the genesis block as the tip block.  It would not be a good idea
  2427  	// to find a newer tip block from the mined blocks bucket since headers
  2428  	// are still missing and the latest recorded block is unlikely to be the
  2429  	// actual block the wallet was marked in sync with anyways (that
  2430  	// information was saved in waddrmgr).
  2431  	err = ns.Put(rootTipBlock, chainParams.GenesisHash[:])
  2432  	if err != nil {
  2433  		return errors.E(errors.IO, err)
  2434  	}
  2435  
  2436  	return nil
  2437  }