db.go raw

   1  package wtxmgr
   2  
   3  import (
   4  	"bytes"
   5  	"encoding/binary"
   6  	"fmt"
   7  	"github.com/p9c/p9/pkg/amt"
   8  	"time"
   9  	
  10  	"github.com/p9c/p9/pkg/chainhash"
  11  	"github.com/p9c/p9/pkg/walletdb"
  12  	"github.com/p9c/p9/pkg/wire"
  13  )
  14  
  15  // Naming
  16  //
  17  // The following variables are commonly used in this file and given reserved names:
  18  //
  19  //   ns: The namespace bucket for this package
  20  //   b:  The primary bucket being operated on
  21  //   k:  A single bucket key
  22  //   v:  A single bucket value
  23  //   c:  A bucket cursor
  24  //   ck: The current cursor key
  25  //   cv: The current cursor value
  26  //
  27  // Functions use the naming scheme `Op[Raw]Type[Field]`, which performs the operation `Op` on the type `Type`,
  28  // optionally dealing with raw keys and values if `Raw` is used. Fetch and extract operations may only need to read some
  29  // portion of a key or value, in which case `Field` describes the component being returned. The following operations are
  30  // used:
  31  //
  32  //   key:     return a db key for some data
  33  //   value:   return a db value for some data
  34  //   put:     insert or replace a value into a bucket
  35  //   fetch:   read and return a value
  36  //   read:    read a value into an out parameter
  37  //   exists:  return the raw (nil if not found) value for some data
  38  //   delete:  remove a k/v pair
  39  //   extract: perform an unchecked slice to extract a key or value
  40  //
  41  // Other operations which are specific to the types being operated on should be explained in a comment. Big endian is
  42  // the preferred byte order, due to cursor scans over integer keys iterating in order.
  43  var byteOrder = binary.BigEndian
  44  
  45  // Database versions. Versions start at 1 and increment for each database change.
  46  const (
  47  	// LatestVersion is the most recent store version.
  48  	LatestVersion = 1
  49  )
  50  
  51  var (
  52  	// This package makes assumptions that the width of a chainhash.Hash is always 32 bytes. If this is ever changed
  53  	// (unlikely for bitcoin, possible for alts), offsets have to be rewritten. Use a compile-time assertion that this
  54  	// assumption holds true.
  55  	_ [32]byte = chainhash.Hash{}
  56  	// Bucket names
  57  	bucketBlocks         = []byte("b")
  58  	bucketTxRecords      = []byte("t")
  59  	bucketCredits        = []byte("c")
  60  	bucketUnspent        = []byte("u")
  61  	bucketDebits         = []byte("d")
  62  	bucketUnmined        = []byte("m")
  63  	bucketUnminedCredits = []byte("mc")
  64  	bucketUnminedInputs  = []byte("mi")
  65  	// Root (namespace) bucket keys
  66  	rootCreateDate   = []byte("date")
  67  	rootVersion      = []byte("vers")
  68  	rootMinedBalance = []byte("bal")
  69  )
  70  
  71  // The root bucket's mined balance k/v pair records the total balance for all unspent credits from mined transactions.
  72  // This includes immature outputs, and outputs spent by mempool transactions, which must be considered when returning
  73  // the actual balance for a given number of block confirmations. The value is the amount serialized as a uint64.
  74  func fetchMinedBalance(ns walletdb.ReadBucket) (amt.Amount, error) {
  75  	v := ns.Get(rootMinedBalance)
  76  	if len(v) != 8 {
  77  		str := fmt.Sprintf(
  78  			"balance: short read (expected 8 bytes, "+
  79  				"read %v)", len(v),
  80  		)
  81  		return 0, storeError(ErrData, str, nil)
  82  	}
  83  	return amt.Amount(byteOrder.Uint64(v)), nil
  84  }
  85  func putMinedBalance(ns walletdb.ReadWriteBucket, amt amt.Amount) (e error) {
  86  	v := make([]byte, 8)
  87  	byteOrder.PutUint64(v, uint64(amt))
  88  	e = ns.Put(rootMinedBalance, v)
  89  	if e != nil {
  90  		str := "failed to put balance"
  91  		return storeError(ErrDatabase, str, e)
  92  	}
  93  	return nil
  94  }
  95  
  96  // Several data structures are given canonical serialization formats as either keys or values. These common formats
  97  // allow keys and values to be reused across different buckets.
  98  //
  99  // The canonical outpoint serialization format is:
 100  //
 101  //   [0:32]  Trasaction hash (32 bytes)
 102  //   [32:36] Output index (4 bytes)
 103  //
 104  // The canonical transaction hash serialization is simply the hash.
 105  func canonicalOutPoint(txHash *chainhash.Hash, index uint32) []byte {
 106  	k := make([]byte, 36)
 107  	copy(k, txHash[:])
 108  	byteOrder.PutUint32(k[32:36], index)
 109  	return k
 110  }
 111  func readCanonicalOutPoint(k []byte, op *wire.OutPoint) (e error) {
 112  	if len(k) < 36 {
 113  		str := "short canonical outpoint"
 114  		return storeError(ErrData, str, nil)
 115  	}
 116  	copy(op.Hash[:], k)
 117  	op.Index = byteOrder.Uint32(k[32:36])
 118  	return nil
 119  }
 120  
 121  // Details regarding blocks are saved as k/v pairs in the blocks bucket. blockRecords are keyed by their height. The
 122  // value is serialized as such:
 123  //
 124  //   [0:32]  Hash (32 bytes)
 125  //   [32:40] Unix time (8 bytes)
 126  //   [40:44] Number of transaction hashes (4 bytes)
 127  //   [44:]   For each transaction hash:
 128  //             Hash (32 bytes)
 129  func keyBlockRecord(height int32) []byte {
 130  	k := make([]byte, 4)
 131  	byteOrder.PutUint32(k, uint32(height))
 132  	return k
 133  }
 134  func valueBlockRecord(block *BlockMeta, txHash *chainhash.Hash) []byte {
 135  	v := make([]byte, 76)
 136  	copy(v, block.Hash[:])
 137  	byteOrder.PutUint64(v[32:40], uint64(block.Time.Unix()))
 138  	byteOrder.PutUint32(v[40:44], 1)
 139  	copy(v[44:76], txHash[:])
 140  	return v
 141  }
 142  
 143  // appendRawBlockRecord returns a new block record value with a transaction hash appended to the end and an incremented
 144  // number of transactions.
 145  func appendRawBlockRecord(v []byte, txHash *chainhash.Hash) ([]byte, error) {
 146  	if len(v) < 44 {
 147  		str := fmt.Sprintf(
 148  			"%s: short read (expected %d bytes, read %d)",
 149  			bucketBlocks, 44, len(v),
 150  		)
 151  		return nil, storeError(ErrData, str, nil)
 152  	}
 153  	newv := append(v[:len(v):len(v)], txHash[:]...)
 154  	n := byteOrder.Uint32(newv[40:44])
 155  	byteOrder.PutUint32(newv[40:44], n+1)
 156  	return newv, nil
 157  }
 158  func putRawBlockRecord(ns walletdb.ReadWriteBucket, k, v []byte) (e error) {
 159  	e = ns.NestedReadWriteBucket(bucketBlocks).Put(k, v)
 160  	if e != nil {
 161  		str := "failed to store block"
 162  		return storeError(ErrDatabase, str, e)
 163  	}
 164  	return nil
 165  }
 166  func putBlockRecord(ns walletdb.ReadWriteBucket, block *BlockMeta, txHash *chainhash.Hash) (e error) {
 167  	k := keyBlockRecord(block.Height)
 168  	v := valueBlockRecord(block, txHash)
 169  	return putRawBlockRecord(ns, k, v)
 170  }
 171  func fetchBlockTime(ns walletdb.ReadBucket, height int32) (time.Time, error) {
 172  	k := keyBlockRecord(height)
 173  	v := ns.NestedReadBucket(bucketBlocks).Get(k)
 174  	if len(v) < 44 {
 175  		str := fmt.Sprintf(
 176  			"%s: short read (expected %d bytes, read %d)",
 177  			bucketBlocks, 44, len(v),
 178  		)
 179  		return time.Time{}, storeError(ErrData, str, nil)
 180  	}
 181  	return time.Unix(int64(byteOrder.Uint64(v[32:40])), 0), nil
 182  }
 183  func existsBlockRecord(ns walletdb.ReadBucket, height int32) (k, v []byte) {
 184  	k = keyBlockRecord(height)
 185  	v = ns.NestedReadBucket(bucketBlocks).Get(k)
 186  	return
 187  }
 188  func readRawBlockRecord(k, v []byte, block *blockRecord) (e error) {
 189  	if len(k) < 4 {
 190  		str := fmt.Sprintf(
 191  			"%s: short key (expected %d bytes, read %d)",
 192  			bucketBlocks, 4, len(k),
 193  		)
 194  		return storeError(ErrData, str, nil)
 195  	}
 196  	if len(v) < 44 {
 197  		str := fmt.Sprintf(
 198  			"%s: short read (expected %d bytes, read %d)",
 199  			bucketBlocks, 44, len(v),
 200  		)
 201  		return storeError(ErrData, str, nil)
 202  	}
 203  	numTransactions := int(byteOrder.Uint32(v[40:44]))
 204  	expectedLen := 44 + chainhash.HashSize*numTransactions
 205  	if len(v) < expectedLen {
 206  		str := fmt.Sprintf(
 207  			"%s: short read (expected %d bytes, read %d)",
 208  			bucketBlocks, expectedLen, len(v),
 209  		)
 210  		return storeError(ErrData, str, nil)
 211  	}
 212  	block.Height = int32(byteOrder.Uint32(k))
 213  	copy(block.Hash[:], v)
 214  	block.Time = time.Unix(int64(byteOrder.Uint64(v[32:40])), 0)
 215  	block.transactions = make([]chainhash.Hash, numTransactions)
 216  	off := 44
 217  	for i := range block.transactions {
 218  		copy(block.transactions[i][:], v[off:])
 219  		off += chainhash.HashSize
 220  	}
 221  	return nil
 222  }
 223  
 224  type blockIterator struct {
 225  	c    walletdb.ReadWriteCursor
 226  	seek []byte
 227  	ck   []byte
 228  	cv   []byte
 229  	elem blockRecord
 230  	err  error
 231  }
 232  
 233  // func makeBlockIterator(ns walletdb.ReadWriteBucket, height int32) blockIterator {
 234  // 	seek := make([]byte, 4)
 235  // 	byteOrder.PutUint32(seek, uint32(height))
 236  // 	c := ns.NestedReadWriteBucket(bucketBlocks).ReadWriteCursor()
 237  // 	return blockIterator{c: c, seek: seek}
 238  // }
 239  func makeReadBlockIterator(ns walletdb.ReadBucket, height int32) blockIterator {
 240  	seek := make([]byte, 4)
 241  	byteOrder.PutUint32(seek, uint32(height))
 242  	c := ns.NestedReadBucket(bucketBlocks).ReadCursor()
 243  	return blockIterator{c: readCursor{c}, seek: seek}
 244  }
 245  
 246  // Works just like makeBlockIterator but will initially position the cursor at the last k/v pair. Use this with
 247  // blockIterator.prev.
 248  func makeReverseBlockIterator(ns walletdb.ReadWriteBucket) blockIterator {
 249  	seek := make([]byte, 4)
 250  	byteOrder.PutUint32(seek, ^uint32(0))
 251  	c := ns.NestedReadWriteBucket(bucketBlocks).ReadWriteCursor()
 252  	return blockIterator{c: c, seek: seek}
 253  }
 254  func makeReadReverseBlockIterator(ns walletdb.ReadBucket) blockIterator {
 255  	seek := make([]byte, 4)
 256  	byteOrder.PutUint32(seek, ^uint32(0))
 257  	c := ns.NestedReadBucket(bucketBlocks).ReadCursor()
 258  	return blockIterator{c: readCursor{c}, seek: seek}
 259  }
 260  func (it *blockIterator) next() bool {
 261  	if it.c == nil {
 262  		return false
 263  	}
 264  	if it.ck == nil {
 265  		it.ck, it.cv = it.c.Seek(it.seek)
 266  	} else {
 267  		it.ck, it.cv = it.c.Next()
 268  	}
 269  	if it.ck == nil {
 270  		it.c = nil
 271  		return false
 272  	}
 273  	e := readRawBlockRecord(it.ck, it.cv, &it.elem)
 274  	if e != nil {
 275  		it.c = nil
 276  		it.err = e
 277  		return false
 278  	}
 279  	return true
 280  }
 281  func (it *blockIterator) prev() bool {
 282  	if it.c == nil {
 283  		return false
 284  	}
 285  	if it.ck == nil {
 286  		it.ck, it.cv = it.c.Seek(it.seek)
 287  		// Seek positions the cursor at the next k/v pair if one with this prefix was not found. If this happened (the
 288  		// prefixes won't match in this case) move the cursor backward.
 289  		//
 290  		// This technically does not correct for multiple keys with matching prefixes by moving the cursor to the last
 291  		// matching key, but this doesn't need to be considered when dealing with block records since the key (and seek
 292  		// prefix) is just the block height.
 293  		if !bytes.HasPrefix(it.ck, it.seek) {
 294  			it.ck, it.cv = it.c.Prev()
 295  		}
 296  	} else {
 297  		it.ck, it.cv = it.c.Prev()
 298  	}
 299  	if it.ck == nil {
 300  		it.c = nil
 301  		return false
 302  	}
 303  	e := readRawBlockRecord(it.ck, it.cv, &it.elem)
 304  	if e != nil {
 305  		it.c = nil
 306  		it.err = e
 307  		return false
 308  	}
 309  	return true
 310  }
 311  
 312  // unavailable until https://github.com/boltdb/bolt/issues/620 is fixed.
 313  // func (it *blockIterator) delete() (e error) {
 314  // 	e := it.c.Delete()
 315  // 	if e != nil  {
 316  // DB// 		str := "failed to delete block record"
 317  // 		storeError(ErrDatabase, str, err)
 318  // 	}
 319  // 	return nil
 320  // }
 321  func (it *blockIterator) reposition(height int32) {
 322  	it.c.Seek(keyBlockRecord(height))
 323  }
 324  func deleteBlockRecord(ns walletdb.ReadWriteBucket, height int32) (e error) {
 325  	k := keyBlockRecord(height)
 326  	return ns.NestedReadWriteBucket(bucketBlocks).Delete(k)
 327  }
 328  
 329  // Transaction records are keyed as such:
 330  //
 331  //   [0:32]  Transaction hash (32 bytes)
 332  //   [32:36] Block height (4 bytes)
 333  //   [36:68] Block hash (32 bytes)
 334  //
 335  // The leading transaction hash allows to prefix filter for all records with a matching hash. The block height and hash
 336  // records a particular incidence of the transaction in the blockchain.
 337  //
 338  // The record value is serialized as such:
 339  //
 340  //   [0:8]   Received time (8 bytes)
 341  //   [8:]    Serialized transaction (varies)
 342  func keyTxRecord(txHash *chainhash.Hash, block *Block) []byte {
 343  	k := make([]byte, 68)
 344  	copy(k, txHash[:])
 345  	byteOrder.PutUint32(k[32:36], uint32(block.Height))
 346  	copy(k[36:68], block.Hash[:])
 347  	return k
 348  }
 349  func valueTxRecord(rec *TxRecord) ([]byte, error) {
 350  	var v []byte
 351  	if rec.SerializedTx == nil {
 352  		txSize := rec.MsgTx.SerializeSize()
 353  		v = make([]byte, 8, 8+txSize)
 354  		e := rec.MsgTx.Serialize(bytes.NewBuffer(v[8:]))
 355  		if e != nil {
 356  			str := fmt.Sprintf("unable to serialize transaction %v", rec.Hash)
 357  			return nil, storeError(ErrInput, str, e)
 358  		}
 359  		v = v[:cap(v)]
 360  	} else {
 361  		v = make([]byte, 8+len(rec.SerializedTx))
 362  		copy(v[8:], rec.SerializedTx)
 363  	}
 364  	byteOrder.PutUint64(v, uint64(rec.Received.Unix()))
 365  	return v, nil
 366  }
 367  func putTxRecord(ns walletdb.ReadWriteBucket, rec *TxRecord, block *Block) (e error) {
 368  	k := keyTxRecord(&rec.Hash, block)
 369  	v, e := valueTxRecord(rec)
 370  	if e != nil {
 371  		return e
 372  	}
 373  	e = ns.NestedReadWriteBucket(bucketTxRecords).Put(k, v)
 374  	if e != nil {
 375  		str := fmt.Sprintf("%s: put failed for %v", bucketTxRecords, rec.Hash)
 376  		return storeError(ErrDatabase, str, e)
 377  	}
 378  	return nil
 379  }
 380  
 381  // func putRawTxRecord(// 	ns walletdb.ReadWriteBucket, k, v []byte) (e error) {
 382  // 	e := ns.NestedReadWriteBucket(bucketTxRecords).Put(k, v)
 383  // 	if e != nil  {
 384  // DB// 		str := fmt.Sprintf("%s: put failed", bucketTxRecords)
 385  // 		return storeError(ErrDatabase, str, err)
 386  // 	}
 387  // 	return nil
 388  // }
 389  func readRawTxRecord(txHash *chainhash.Hash, v []byte, rec *TxRecord) (e error) {
 390  	if len(v) < 8 {
 391  		str := fmt.Sprintf(
 392  			"%s: short read (expected %d bytes, read %d)",
 393  			bucketTxRecords, 8, len(v),
 394  		)
 395  		return storeError(ErrData, str, nil)
 396  	}
 397  	rec.Hash = *txHash
 398  	rec.Received = time.Unix(int64(byteOrder.Uint64(v)), 0)
 399  	e = rec.MsgTx.Deserialize(bytes.NewReader(v[8:]))
 400  	if e != nil {
 401  		str := fmt.Sprintf(
 402  			"%s: failed to deserialize transaction %v",
 403  			bucketTxRecords, txHash,
 404  		)
 405  		return storeError(ErrData, str, e)
 406  	}
 407  	return nil
 408  }
 409  func readRawTxRecordBlock(k []byte, block *Block) (e error) {
 410  	if len(k) < 68 {
 411  		str := fmt.Sprintf(
 412  			"%s: short key (expected %d bytes, read %d)",
 413  			bucketTxRecords, 68, len(k),
 414  		)
 415  		return storeError(ErrData, str, nil)
 416  	}
 417  	block.Height = int32(byteOrder.Uint32(k[32:36]))
 418  	copy(block.Hash[:], k[36:68])
 419  	return nil
 420  }
 421  
 422  func fetchTxRecord(ns walletdb.ReadBucket, txHash *chainhash.Hash, block *Block) (rec *TxRecord, e error) {
 423  	k := keyTxRecord(txHash, block)
 424  	v := ns.NestedReadBucket(bucketTxRecords).Get(k)
 425  	rec = new(TxRecord)
 426  	e = readRawTxRecord(txHash, v, rec)
 427  	return rec, e
 428  }
 429  
 430  // TODO: This reads more than necessary. Pass the pkscript location instead to
 431  //  avoid the wire.MsgTx deserialization.
 432  func fetchRawTxRecordPkScript(k, v []byte, index uint32) ([]byte, error) {
 433  	var rec TxRecord
 434  	copy(rec.Hash[:], k) // Silly but need an array
 435  	e := readRawTxRecord(&rec.Hash, v, &rec)
 436  	if e != nil {
 437  		return nil, e
 438  	}
 439  	if int(index) >= len(rec.MsgTx.TxOut) {
 440  		str := "missing transaction output for credit index"
 441  		return nil, storeError(ErrData, str, nil)
 442  	}
 443  	return rec.MsgTx.TxOut[index].PkScript, nil
 444  }
 445  func existsTxRecord(ns walletdb.ReadBucket, txHash *chainhash.Hash, block *Block) (k, v []byte) {
 446  	k = keyTxRecord(txHash, block)
 447  	v = ns.NestedReadBucket(bucketTxRecords).Get(k)
 448  	return
 449  }
 450  
 451  func existsRawTxRecord(ns walletdb.ReadBucket, k []byte) (v []byte) {
 452  	return ns.NestedReadBucket(bucketTxRecords).Get(k)
 453  }
 454  
 455  func deleteTxRecord(ns walletdb.ReadWriteBucket, txHash *chainhash.Hash, block *Block) (e error) {
 456  	k := keyTxRecord(txHash, block)
 457  	return ns.NestedReadWriteBucket(bucketTxRecords).Delete(k)
 458  }
 459  
 460  // latestTxRecord searches for the newest recorded mined transaction record with a matching hash. In case of a hash
 461  // collision, the record from the newest block is returned. Returns (nil, nil) if no matching transactions are found.
 462  func latestTxRecord(ns walletdb.ReadBucket, txHash *chainhash.Hash) (k, v []byte) {
 463  	prefix := txHash[:]
 464  	c := ns.NestedReadBucket(bucketTxRecords).ReadCursor()
 465  	ck, cv := c.Seek(prefix)
 466  	var lastKey, lastVal []byte
 467  	for bytes.HasPrefix(ck, prefix) {
 468  		lastKey, lastVal = ck, cv
 469  		ck, cv = c.Next()
 470  	}
 471  	return lastKey, lastVal
 472  }
 473  
 474  // All transaction credits (outputs) are keyed as such:
 475  //
 476  //   [0:32]  Transaction hash (32 bytes)
 477  //   [32:36] Block height (4 bytes)
 478  //   [36:68] Block hash (32 bytes)
 479  //   [68:72] Output index (4 bytes)
 480  //
 481  // The first 68 bytes match the key for the transaction record and may be used as a prefix filter to iterate through all
 482  // credits in order.
 483  //
 484  // The credit value is serialized as such:
 485  //
 486  //   [0:8]   Amount (8 bytes)
 487  //   [8]     Flags (1 byte)
 488  //             0x01: Spent
 489  //             0x02: Change
 490  //   [9:81]  OPTIONAL Debit bucket key (72 bytes)
 491  //             [9:41]  Spender transaction hash (32 bytes)
 492  //             [41:45] Spender block height (4 bytes)
 493  //             [45:77] Spender block hash (32 bytes)
 494  //             [77:81] Spender transaction input index (4 bytes)
 495  //
 496  // The optional debits key is only included if the credit is spent by another
 497  // mined debit.
 498  func keyCredit(txHash *chainhash.Hash, index uint32, block *Block) []byte {
 499  	k := make([]byte, 72)
 500  	copy(k, txHash[:])
 501  	byteOrder.PutUint32(k[32:36], uint32(block.Height))
 502  	copy(k[36:68], block.Hash[:])
 503  	byteOrder.PutUint32(k[68:72], index)
 504  	return k
 505  }
 506  
 507  // valueUnspentCredit creates a new credit value for an unspent credit. All credits are created unspent, and are only
 508  // marked spent later, so there is no value function to create either spent or unspent credits.
 509  func valueUnspentCredit(cred *credit) []byte {
 510  	v := make([]byte, 9)
 511  	byteOrder.PutUint64(v, uint64(cred.amount))
 512  	if cred.change {
 513  		v[8] |= 1 << 1
 514  	}
 515  	return v
 516  }
 517  func putRawCredit(ns walletdb.ReadWriteBucket, k, v []byte) (e error) {
 518  	e = ns.NestedReadWriteBucket(bucketCredits).Put(k, v)
 519  	if e != nil {
 520  		str := "failed to put credit"
 521  		return storeError(ErrDatabase, str, e)
 522  	}
 523  	return nil
 524  }
 525  
 526  // putUnspentCredit puts a credit record for an unspent credit. It may only be used when the credit is already know to
 527  // be unspent, or spent by an unconfirmed transaction.
 528  func putUnspentCredit(ns walletdb.ReadWriteBucket, cred *credit) (e error) {
 529  	k := keyCredit(&cred.outPoint.Hash, cred.outPoint.Index, &cred.block)
 530  	v := valueUnspentCredit(cred)
 531  	return putRawCredit(ns, k, v)
 532  }
 533  func extractRawCreditTxRecordKey(k []byte) []byte {
 534  	return k[0:68]
 535  }
 536  func extractRawCreditIndex(k []byte) uint32 {
 537  	return byteOrder.Uint32(k[68:72])
 538  }
 539  
 540  // fetchRawCreditAmount returns the amount of the credit.
 541  func fetchRawCreditAmount(v []byte) (amt.Amount, error) {
 542  	if len(v) < 9 {
 543  		str := fmt.Sprintf(
 544  			"%s: short read (expected %d bytes, read %d)",
 545  			bucketCredits, 9, len(v),
 546  		)
 547  		return 0, storeError(ErrData, str, nil)
 548  	}
 549  	return amt.Amount(byteOrder.Uint64(v)), nil
 550  }
 551  
 552  // fetchRawCreditAmountSpent returns the amount of the credit and whether the credit is spent.
 553  func fetchRawCreditAmountSpent(v []byte) (amt.Amount, bool, error) {
 554  	if len(v) < 9 {
 555  		str := fmt.Sprintf(
 556  			"%s: short read (expected %d bytes, read %d)",
 557  			bucketCredits, 9, len(v),
 558  		)
 559  		return 0, false, storeError(ErrData, str, nil)
 560  	}
 561  	return amt.Amount(byteOrder.Uint64(v)), v[8]&(1<<0) != 0, nil
 562  }
 563  
 564  // fetchRawCreditAmountChange returns the amount of the credit and whether the credit is marked as change.
 565  func fetchRawCreditAmountChange(v []byte) (amt.Amount, bool, error) {
 566  	if len(v) < 9 {
 567  		str := fmt.Sprintf(
 568  			"%s: short read (expected %d bytes, read %d)",
 569  			bucketCredits, 9, len(v),
 570  		)
 571  		return 0, false, storeError(ErrData, str, nil)
 572  	}
 573  	return amt.Amount(byteOrder.Uint64(v)), v[8]&(1<<1) != 0, nil
 574  }
 575  
 576  // fetchRawCreditUnspentValue returns the unspent value for a raw credit key. This may be used to mark a credit as
 577  // unspent.
 578  func fetchRawCreditUnspentValue(k []byte) ([]byte, error) {
 579  	if len(k) < 72 {
 580  		str := fmt.Sprintf(
 581  			"%s: short key (expected %d bytes, read %d)",
 582  			bucketCredits, 72, len(k),
 583  		)
 584  		return nil, storeError(ErrData, str, nil)
 585  	}
 586  	return k[32:68], nil
 587  }
 588  
 589  // spendRawCredit marks the credit with a given key as mined at some particular block as spent by the input at some
 590  // transaction incidence. The debited amount is returned.
 591  func spendCredit(ns walletdb.ReadWriteBucket, k []byte, spender *indexedIncidence) (amt.Amount, error) {
 592  	v := ns.NestedReadBucket(bucketCredits).Get(k)
 593  	newv := make([]byte, 81)
 594  	copy(newv, v)
 595  	v = newv
 596  	v[8] |= 1 << 0
 597  	copy(v[9:41], spender.txHash[:])
 598  	byteOrder.PutUint32(v[41:45], uint32(spender.block.Height))
 599  	copy(v[45:77], spender.block.Hash[:])
 600  	byteOrder.PutUint32(v[77:81], spender.index)
 601  	return amt.Amount(byteOrder.Uint64(v[0:8])), putRawCredit(ns, k, v)
 602  }
 603  
 604  // unspendRawCredit rewrites the credit for the given key as unspent. The output amount of the credit is returned. It
 605  // returns without error if no credit exists for the key.
 606  func unspendRawCredit(ns walletdb.ReadWriteBucket, k []byte) (amt.Amount, error) {
 607  	b := ns.NestedReadWriteBucket(bucketCredits)
 608  	v := b.Get(k)
 609  	if v == nil {
 610  		return 0, nil
 611  	}
 612  	newv := make([]byte, 9)
 613  	copy(newv, v)
 614  	newv[8] &^= 1 << 0
 615  	e := b.Put(k, newv)
 616  	if e != nil {
 617  		str := "failed to put credit"
 618  		return 0, storeError(ErrDatabase, str, e)
 619  	}
 620  	return amt.Amount(byteOrder.Uint64(v[0:8])), nil
 621  }
 622  
 623  func existsCredit(ns walletdb.ReadBucket, txHash *chainhash.Hash, index uint32, block *Block) (k, v []byte) {
 624  	k = keyCredit(txHash, index, block)
 625  	v = ns.NestedReadBucket(bucketCredits).Get(k)
 626  	return
 627  }
 628  
 629  func existsRawCredit(ns walletdb.ReadBucket, k []byte) []byte {
 630  	return ns.NestedReadBucket(bucketCredits).Get(k)
 631  }
 632  
 633  func deleteRawCredit(ns walletdb.ReadWriteBucket, k []byte) (e error) {
 634  	e = ns.NestedReadWriteBucket(bucketCredits).Delete(k)
 635  	if e != nil {
 636  		str := "failed to delete credit"
 637  		return storeError(ErrDatabase, str, e)
 638  	}
 639  	return nil
 640  }
 641  
 642  // creditIterator allows for in-order iteration of all credit records for a mined transaction.
 643  //
 644  // Example usage:
 645  //
 646  //   prefix := keyTxRecord(txHash, block)
 647  //   it := makeCreditIterator(ns, prefix)
 648  //   for it.next() {
 649  //           // Use it.elem
 650  //           // If necessary, read additional details from it.ck, it.cv
 651  //   }
 652  //   if it.err != nil {
 653  //           // Handle error
 654  //   }
 655  //
 656  // The elem's Spent field is not set to true if the credit is spent by an unmined transaction. To check for this case:
 657  //
 658  //   k := canonicalOutPoint(&txHash, it.elem.Index)
 659  //   it.elem.Spent = existsRawUnminedInput(ns, k) != nil
 660  type creditIterator struct {
 661  	c      walletdb.ReadWriteCursor // Set to nil after final iteration
 662  	prefix []byte
 663  	ck     []byte
 664  	cv     []byte
 665  	elem   CreditRecord
 666  	err    error
 667  }
 668  
 669  // func makeCreditIterator(// 	ns walletdb.ReadWriteBucket, prefix []byte) creditIterator {
 670  // 	c := ns.NestedReadWriteBucket(bucketCredits).ReadWriteCursor()
 671  // 	return creditIterator{c: c, prefix: prefix}
 672  // }
 673  func makeReadCreditIterator(ns walletdb.ReadBucket, prefix []byte) creditIterator {
 674  	c := ns.NestedReadBucket(bucketCredits).ReadCursor()
 675  	return creditIterator{c: readCursor{c}, prefix: prefix}
 676  }
 677  func (it *creditIterator) readElem() (e error) {
 678  	if len(it.ck) < 72 {
 679  		str := fmt.Sprintf(
 680  			"%s: short key (expected %d bytes, read %d)",
 681  			bucketCredits, 72, len(it.ck),
 682  		)
 683  		return storeError(ErrData, str, nil)
 684  	}
 685  	if len(it.cv) < 9 {
 686  		str := fmt.Sprintf(
 687  			"%s: short read (expected %d bytes, read %d)",
 688  			bucketCredits, 9, len(it.cv),
 689  		)
 690  		return storeError(ErrData, str, nil)
 691  	}
 692  	it.elem.Index = byteOrder.Uint32(it.ck[68:72])
 693  	it.elem.Amount = amt.Amount(byteOrder.Uint64(it.cv))
 694  	it.elem.Spent = it.cv[8]&(1<<0) != 0
 695  	it.elem.Change = it.cv[8]&(1<<1) != 0
 696  	return nil
 697  }
 698  func (it *creditIterator) next() bool {
 699  	if it.c == nil {
 700  		return false
 701  	}
 702  	if it.ck == nil {
 703  		it.ck, it.cv = it.c.Seek(it.prefix)
 704  	} else {
 705  		it.ck, it.cv = it.c.Next()
 706  	}
 707  	if !bytes.HasPrefix(it.ck, it.prefix) {
 708  		it.c = nil
 709  		return false
 710  	}
 711  	e := it.readElem()
 712  	if e != nil {
 713  		it.err = e
 714  		return false
 715  	}
 716  	return true
 717  }
 718  
 719  // The unspent index records all outpoints for mined credits which are not spent by any other mined transaction records
 720  // (but may be spent by a mempool transaction).
 721  //
 722  // Keys are use the canonical outpoint serialization:
 723  //
 724  //   [0:32]  Transaction hash (32 bytes)
 725  //   [32:36] Output index (4 bytes)
 726  //
 727  // Values are serialized as such:
 728  //
 729  //   [0:4]   Block height (4 bytes)
 730  //   [4:36]  Block hash (32 bytes)
 731  func valueUnspent(block *Block) []byte {
 732  	v := make([]byte, 36)
 733  	byteOrder.PutUint32(v, uint32(block.Height))
 734  	copy(v[4:36], block.Hash[:])
 735  	return v
 736  }
 737  func putUnspent(ns walletdb.ReadWriteBucket, outPoint *wire.OutPoint, block *Block) (e error) {
 738  	k := canonicalOutPoint(&outPoint.Hash, outPoint.Index)
 739  	v := valueUnspent(block)
 740  	e = ns.NestedReadWriteBucket(bucketUnspent).Put(k, v)
 741  	if e != nil {
 742  		str := "cannot put unspent"
 743  		return storeError(ErrDatabase, str, e)
 744  	}
 745  	return nil
 746  }
 747  func putRawUnspent(ns walletdb.ReadWriteBucket, k, v []byte) (e error) {
 748  	e = ns.NestedReadWriteBucket(bucketUnspent).Put(k, v)
 749  	if e != nil {
 750  		str := "cannot put unspent"
 751  		return storeError(ErrDatabase, str, e)
 752  	}
 753  	return nil
 754  }
 755  func readUnspentBlock(v []byte, block *Block) (e error) {
 756  	if len(v) < 36 {
 757  		str := "short unspent value"
 758  		return storeError(ErrData, str, nil)
 759  	}
 760  	block.Height = int32(byteOrder.Uint32(v))
 761  	copy(block.Hash[:], v[4:36])
 762  	return nil
 763  }
 764  
 765  // existsUnspent returns the key for the unspent output and the corresponding key for the credits bucket. If there is no
 766  // unspent output recorded, the credit key is nil.
 767  func existsUnspent(ns walletdb.ReadBucket, outPoint *wire.OutPoint) (k, credKey []byte) {
 768  	k = canonicalOutPoint(&outPoint.Hash, outPoint.Index)
 769  	credKey = existsRawUnspent(ns, k)
 770  	return k, credKey
 771  }
 772  
 773  // existsRawUnspent returns the credit key if there exists an output recorded for the raw unspent key. It returns nil if
 774  // the k/v pair does not exist.
 775  func existsRawUnspent(ns walletdb.ReadBucket, k []byte) (credKey []byte) {
 776  	if len(k) < 36 {
 777  		return nil
 778  	}
 779  	v := ns.NestedReadBucket(bucketUnspent).Get(k)
 780  	if len(v) < 36 {
 781  		return nil
 782  	}
 783  	credKey = make([]byte, 72)
 784  	copy(credKey, k[:32])
 785  	copy(credKey[32:68], v)
 786  	copy(credKey[68:72], k[32:36])
 787  	return credKey
 788  }
 789  func deleteRawUnspent(ns walletdb.ReadWriteBucket, k []byte) (e error) {
 790  	e = ns.NestedReadWriteBucket(bucketUnspent).Delete(k)
 791  	if e != nil {
 792  		str := "failed to delete unspent"
 793  		return storeError(ErrDatabase, str, e)
 794  	}
 795  	return nil
 796  }
 797  
 798  // All transaction debits (inputs which spend credits) are keyed as such:
 799  //
 800  //   [0:32]  Transaction hash (32 bytes)
 801  //   [32:36] Block height (4 bytes)
 802  //   [36:68] Block hash (32 bytes)
 803  //   [68:72] Input index (4 bytes)
 804  //
 805  // The first 68 bytes match the key for the transaction record and may be used as a prefix filter to iterate through all
 806  // debits in order.
 807  //
 808  // The debit value is serialized as such:
 809  //
 810  //   [0:8]   Amount (8 bytes)
 811  //   [8:80]  Credits bucket key (72 bytes)
 812  //             [8:40]  Transaction hash (32 bytes)
 813  //             [40:44] Block height (4 bytes)
 814  //             [44:76] Block hash (32 bytes)
 815  //             [76:80] Output index (4 bytes)
 816  func keyDebit(txHash *chainhash.Hash, index uint32, block *Block) []byte {
 817  	k := make([]byte, 72)
 818  	copy(k, txHash[:])
 819  	byteOrder.PutUint32(k[32:36], uint32(block.Height))
 820  	copy(k[36:68], block.Hash[:])
 821  	byteOrder.PutUint32(k[68:72], index)
 822  	return k
 823  }
 824  
 825  func putDebit(
 826  	ns walletdb.ReadWriteBucket,
 827  	txHash *chainhash.Hash,
 828  	index uint32,
 829  	amount amt.Amount,
 830  	block *Block,
 831  	credKey []byte,
 832  ) (e error) {
 833  	k := keyDebit(txHash, index, block)
 834  	v := make([]byte, 80)
 835  	byteOrder.PutUint64(v, uint64(amount))
 836  	copy(v[8:80], credKey)
 837  	e = ns.NestedReadWriteBucket(bucketDebits).Put(k, v)
 838  	if e != nil {
 839  		str := fmt.Sprintf(
 840  			"failed to update debit %s input %d",
 841  			txHash, index,
 842  		)
 843  		return storeError(ErrDatabase, str, e)
 844  	}
 845  	return nil
 846  }
 847  
 848  func extractRawDebitCreditKey(v []byte) []byte {
 849  	return v[8:80]
 850  }
 851  
 852  // existsDebit checks for the existance of a debit. If found, the debit and previous credit keys are returned. If the
 853  // debit does not exist, both keys are nil.
 854  func existsDebit(ns walletdb.ReadBucket, txHash *chainhash.Hash, index uint32, block *Block) (
 855  	k, credKey []byte,
 856  	e error,
 857  ) {
 858  	k = keyDebit(txHash, index, block)
 859  	v := ns.NestedReadBucket(bucketDebits).Get(k)
 860  	if v == nil {
 861  		return nil, nil, nil
 862  	}
 863  	if len(v) < 80 {
 864  		str := fmt.Sprintf(
 865  			"%s: short read (expected 80 bytes, read %v)",
 866  			bucketDebits, len(v),
 867  		)
 868  		return nil, nil, storeError(ErrData, str, nil)
 869  	}
 870  	return k, v[8:80], nil
 871  }
 872  
 873  func deleteRawDebit(ns walletdb.ReadWriteBucket, k []byte) (e error) {
 874  	e = ns.NestedReadWriteBucket(bucketDebits).Delete(k)
 875  	if e != nil {
 876  		str := "failed to delete debit"
 877  		return storeError(ErrDatabase, str, e)
 878  	}
 879  	return nil
 880  }
 881  
 882  // debitIterator allows for in-order iteration of all debit records for a mined transaction.
 883  //
 884  // Example usage:
 885  //
 886  //   prefix := keyTxRecord(txHash, block)
 887  //   it := makeDebitIterator(ns, prefix)
 888  //   for it.next() {
 889  //           // Use it.elem
 890  //           // If necessary, read additional details from it.ck, it.cv
 891  //   }
 892  //   if it.err != nil {
 893  //           // Handle error
 894  //   }
 895  type debitIterator struct {
 896  	c      walletdb.ReadWriteCursor // Set to nil after final iteration
 897  	prefix []byte
 898  	ck     []byte
 899  	cv     []byte
 900  	elem   DebitRecord
 901  	err    error
 902  }
 903  
 904  // func makeDebitIterator(// 	ns walletdb.ReadWriteBucket, prefix []byte) debitIterator {
 905  // 	c := ns.NestedReadWriteBucket(bucketDebits).ReadWriteCursor()
 906  // 	return debitIterator{c: c, prefix: prefix}
 907  // }
 908  func makeReadDebitIterator(ns walletdb.ReadBucket, prefix []byte) debitIterator {
 909  	c := ns.NestedReadBucket(bucketDebits).ReadCursor()
 910  	return debitIterator{c: readCursor{c}, prefix: prefix}
 911  }
 912  
 913  func (it *debitIterator) readElem() (e error) {
 914  	if len(it.ck) < 72 {
 915  		str := fmt.Sprintf(
 916  			"%s: short key (expected %d bytes, read %d)",
 917  			bucketDebits, 72, len(it.ck),
 918  		)
 919  		return storeError(ErrData, str, nil)
 920  	}
 921  	if len(it.cv) < 80 {
 922  		str := fmt.Sprintf(
 923  			"%s: short read (expected %d bytes, read %d)",
 924  			bucketDebits, 80, len(it.cv),
 925  		)
 926  		return storeError(ErrData, str, nil)
 927  	}
 928  	it.elem.Index = byteOrder.Uint32(it.ck[68:72])
 929  	it.elem.Amount = amt.Amount(byteOrder.Uint64(it.cv))
 930  	return nil
 931  }
 932  
 933  func (it *debitIterator) next() bool {
 934  	if it.c == nil {
 935  		return false
 936  	}
 937  	if it.ck == nil {
 938  		it.ck, it.cv = it.c.Seek(it.prefix)
 939  	} else {
 940  		it.ck, it.cv = it.c.Next()
 941  	}
 942  	if !bytes.HasPrefix(it.ck, it.prefix) {
 943  		it.c = nil
 944  		return false
 945  	}
 946  	e := it.readElem()
 947  	if e != nil {
 948  		it.err = e
 949  		return false
 950  	}
 951  	return true
 952  }
 953  
 954  // All unmined transactions are saved in the unmined bucket keyed by the transaction hash. The value matches that of
 955  // mined transaction records:
 956  //
 957  //   [0:8]   Received time (8 bytes)
 958  //   [8:]    Serialized transaction (varies)
 959  func putRawUnmined(ns walletdb.ReadWriteBucket, k, v []byte) (e error) {
 960  	e = ns.NestedReadWriteBucket(bucketUnmined).Put(k, v)
 961  	if e != nil {
 962  		str := "failed to put unmined record"
 963  		return storeError(ErrDatabase, str, e)
 964  	}
 965  	return nil
 966  }
 967  
 968  func readRawUnminedHash(k []byte, txHash *chainhash.Hash) (e error) {
 969  	if len(k) < 32 {
 970  		str := "short unmined key"
 971  		return storeError(ErrData, str, nil)
 972  	}
 973  	copy(txHash[:], k)
 974  	return nil
 975  }
 976  
 977  func existsRawUnmined(ns walletdb.ReadBucket, k []byte) (v []byte) {
 978  	return ns.NestedReadBucket(bucketUnmined).Get(k)
 979  }
 980  
 981  func deleteRawUnmined(ns walletdb.ReadWriteBucket, k []byte) (e error) {
 982  	e = ns.NestedReadWriteBucket(bucketUnmined).Delete(k)
 983  	if e != nil {
 984  		str := "failed to delete unmined record"
 985  		return storeError(ErrDatabase, str, e)
 986  	}
 987  	return nil
 988  }
 989  
 990  // Unmined transaction credits use the canonical serialization format:
 991  //
 992  //  [0:32]   Transaction hash (32 bytes)
 993  //  [32:36]  Output index (4 bytes)
 994  //
 995  // The value matches the format used by mined credits, but the spent flag is never set and the optional debit record is
 996  // never included. The simplified format is thus:
 997  //
 998  //   [0:8]   Amount (8 bytes)
 999  //   [8]     Flags (1 byte)
1000  //             0x02: Change
1001  func valueUnminedCredit(amount amt.Amount, change bool) []byte {
1002  	v := make([]byte, 9)
1003  	byteOrder.PutUint64(v, uint64(amount))
1004  	if change {
1005  		v[8] = 1 << 1
1006  	}
1007  	return v
1008  }
1009  func putRawUnminedCredit(ns walletdb.ReadWriteBucket, k, v []byte) (e error) {
1010  	e = ns.NestedReadWriteBucket(bucketUnminedCredits).Put(k, v)
1011  	if e != nil {
1012  		str := "cannot put unmined credit"
1013  		return storeError(ErrDatabase, str, e)
1014  	}
1015  	return nil
1016  }
1017  func fetchRawUnminedCreditIndex(k []byte) (uint32, error) {
1018  	if len(k) < 36 {
1019  		str := "short unmined credit key"
1020  		return 0, storeError(ErrData, str, nil)
1021  	}
1022  	return byteOrder.Uint32(k[32:36]), nil
1023  }
1024  func fetchRawUnminedCreditAmount(v []byte) (amt.Amount, error) {
1025  	if len(v) < 9 {
1026  		str := "short unmined credit value"
1027  		return 0, storeError(ErrData, str, nil)
1028  	}
1029  	return amt.Amount(byteOrder.Uint64(v)), nil
1030  }
1031  func fetchRawUnminedCreditAmountChange(v []byte) (amt.Amount, bool, error) {
1032  	if len(v) < 9 {
1033  		str := "short unmined credit value"
1034  		return 0, false, storeError(ErrData, str, nil)
1035  	}
1036  	amt := amt.Amount(byteOrder.Uint64(v))
1037  	change := v[8]&(1<<1) != 0
1038  	return amt, change, nil
1039  }
1040  func existsRawUnminedCredit(ns walletdb.ReadBucket, k []byte) []byte {
1041  	return ns.NestedReadBucket(bucketUnminedCredits).Get(k)
1042  }
1043  func deleteRawUnminedCredit(ns walletdb.ReadWriteBucket, k []byte) (e error) {
1044  	e = ns.NestedReadWriteBucket(bucketUnminedCredits).Delete(k)
1045  	if e != nil {
1046  		str := "failed to delete unmined credit"
1047  		return storeError(ErrDatabase, str, e)
1048  	}
1049  	return nil
1050  }
1051  
1052  // unminedCreditIterator allows for cursor iteration over all credits, in order, from a single unmined transaction.
1053  //
1054  //  Example usage:
1055  //
1056  //   it := makeUnminedCreditIterator(ns, txHash)
1057  //   for it.next() {
1058  //           // Use it.elem, it.ck and it.cv
1059  //           // Optionally, use it.delete() to remove this k/v pair
1060  //   }
1061  //   if it.err != nil {
1062  //           // Handle error
1063  //   }
1064  //
1065  // The spentness of the credit is not looked up for performance reasons (because for unspent credits, it requires
1066  // another lookup in another bucket). If this is needed, it may be checked like this:
1067  //
1068  //   spent := existsRawUnminedInput(ns, it.ck) != nil
1069  type unminedCreditIterator struct {
1070  	c      walletdb.ReadWriteCursor
1071  	prefix []byte
1072  	ck     []byte
1073  	cv     []byte
1074  	elem   CreditRecord
1075  	err    error
1076  }
1077  
1078  type readCursor struct {
1079  	walletdb.ReadCursor
1080  }
1081  
1082  // Delete ...
1083  func (r readCursor) Delete() (e error) {
1084  	str := "failed to delete current cursor item from read-only cursor"
1085  	return storeError(ErrDatabase, str, walletdb.ErrTxNotWritable)
1086  }
1087  
1088  func makeUnminedCreditIterator(ns walletdb.ReadWriteBucket, txHash *chainhash.Hash) unminedCreditIterator {
1089  	c := ns.NestedReadWriteBucket(bucketUnminedCredits).ReadWriteCursor()
1090  	return unminedCreditIterator{c: c, prefix: txHash[:]}
1091  }
1092  
1093  func makeReadUnminedCreditIterator(ns walletdb.ReadBucket, txHash *chainhash.Hash) unminedCreditIterator {
1094  	c := ns.NestedReadBucket(bucketUnminedCredits).ReadCursor()
1095  	return unminedCreditIterator{c: readCursor{c}, prefix: txHash[:]}
1096  }
1097  
1098  func (it *unminedCreditIterator) readElem() (e error) {
1099  	index, e := fetchRawUnminedCreditIndex(it.ck)
1100  	if e != nil {
1101  		return e
1102  	}
1103  	amount, change, e := fetchRawUnminedCreditAmountChange(it.cv)
1104  	if e != nil {
1105  		return e
1106  	}
1107  	it.elem.Index = index
1108  	it.elem.Amount = amount
1109  	it.elem.Change = change
1110  	// Spent intentionally not set
1111  	return nil
1112  }
1113  
1114  func (it *unminedCreditIterator) next() bool {
1115  	if it.c == nil {
1116  		return false
1117  	}
1118  	if it.ck == nil {
1119  		it.ck, it.cv = it.c.Seek(it.prefix)
1120  	} else {
1121  		it.ck, it.cv = it.c.Next()
1122  	}
1123  	if !bytes.HasPrefix(it.ck, it.prefix) {
1124  		it.c = nil
1125  		return false
1126  	}
1127  	e := it.readElem()
1128  	if e != nil {
1129  		it.err = e
1130  		return false
1131  	}
1132  	return true
1133  }
1134  
1135  // // unavailable until https://github.com/boltdb/bolt/issues/620 is fixed.
1136  // // func (it *unminedCreditIterator) delete() (e error) {
1137  // // 	e := it.c.Delete()
1138  // // 	if e != nil  {
1139  // DB// // 		str := "failed to delete unmined credit"
1140  // // 		return storeError(ErrDatabase, str, err)
1141  // // 	}
1142  // // 	return nil
1143  // // }
1144  // func (it *unminedCreditIterator) reposition(txHash *chainhash.Hash, index uint32) {
1145  // 	it.c.Seek(canonicalOutPoint(txHash, index))
1146  // }
1147  
1148  // Outpoints spent by unmined transactions are saved in the unmined inputs bucket. This bucket maps between each
1149  // previous output spent, for both mined and unmined transactions, to the hash of the unmined transaction.
1150  //
1151  // The key is serialized as such:
1152  //
1153  //   [0:32]   Transaction hash (32 bytes)
1154  //   [32:36]  Output index (4 bytes)
1155  //
1156  // The value is serialized as such:
1157  //
1158  //   [0:32]   Transaction hash (32 bytes)
1159  
1160  // putRawUnminedInput maintains a list of unmined transaction hashes that have spent an outpoint. Each entry in the
1161  // bucket is keyed by the outpoint being spent.
1162  func putRawUnminedInput(ns walletdb.ReadWriteBucket, k, v []byte) (e error) {
1163  	spendTxHashes := ns.NestedReadBucket(bucketUnminedInputs).Get(k)
1164  	spendTxHashes = append(spendTxHashes, v...)
1165  	e = ns.NestedReadWriteBucket(bucketUnminedInputs).Put(k, spendTxHashes)
1166  	if e != nil {
1167  		str := "failed to put unmined input"
1168  		return storeError(ErrDatabase, str, e)
1169  	}
1170  	return nil
1171  }
1172  
1173  func existsRawUnminedInput(ns walletdb.ReadBucket, k []byte) (v []byte) {
1174  	return ns.NestedReadBucket(bucketUnminedInputs).Get(k)
1175  }
1176  
1177  // fetchUnminedInputSpendTxHashes fetches the list of unmined transactions that spend the serialized outpoint.
1178  func fetchUnminedInputSpendTxHashes(ns walletdb.ReadBucket, k []byte) []chainhash.Hash {
1179  	rawSpendTxHashes := ns.NestedReadBucket(bucketUnminedInputs).Get(k)
1180  	if rawSpendTxHashes == nil {
1181  		return nil
1182  	}
1183  	// Each transaction hash is 32 bytes.
1184  	spendTxHashes := make([]chainhash.Hash, 0, len(rawSpendTxHashes)/32)
1185  	for len(rawSpendTxHashes) > 0 {
1186  		var spendTxHash chainhash.Hash
1187  		copy(spendTxHash[:], rawSpendTxHashes[:32])
1188  		spendTxHashes = append(spendTxHashes, spendTxHash)
1189  		rawSpendTxHashes = rawSpendTxHashes[32:]
1190  	}
1191  	return spendTxHashes
1192  }
1193  
1194  func deleteRawUnminedInput(ns walletdb.ReadWriteBucket, k []byte) (e error) {
1195  	e = ns.NestedReadWriteBucket(bucketUnminedInputs).Delete(k)
1196  	if e != nil {
1197  		str := "failed to delete unmined input"
1198  		return storeError(ErrDatabase, str, e)
1199  	}
1200  	return nil
1201  }
1202  
1203  // openStore opens an existing transaction store from the passed namespace.
1204  func openStore(ns walletdb.ReadBucket) (e error) {
1205  	v := ns.Get(rootVersion)
1206  	if len(v) != 4 {
1207  		str := "no transaction store exists in namespace"
1208  		return storeError(ErrNoExists, str, nil)
1209  	}
1210  	version := byteOrder.Uint32(v)
1211  	if version < LatestVersion {
1212  		str := fmt.Sprintf(
1213  			"a database upgrade is required to upgrade "+
1214  				"wtxmgr from recorded version %d to the latest version %d",
1215  			version, LatestVersion,
1216  		)
1217  		return storeError(ErrNeedsUpgrade, str, nil)
1218  	}
1219  	if version > LatestVersion {
1220  		str := fmt.Sprintf(
1221  			"version recorded version %d is newer that latest "+
1222  				"understood version %d", version, LatestVersion,
1223  		)
1224  		return storeError(ErrUnknownVersion, str, nil)
1225  	}
1226  	// Upgrade the tx store as needed, one version at a time, until LatestVersion is reached. Versions are not skipped
1227  	// when performing database upgrades, and each upgrade is done in its own transaction.
1228  	//
1229  	// No upgrades yet.
1230  	// if version < LatestVersion {
1231  	//	e := scopedUpdate(namespace, func(ns walletdb.Bucket) (e error) {
1232  	//	})
1233  	//	if e != nil  {
1234  	//	DB	//		// Handle err
1235  	//	}
1236  	// }
1237  	return nil
1238  }
1239  
1240  // createStore creates the tx store (with the latest db version) in the passed namespace. If a store already exists,
1241  // ErrAlreadyExists is returned.
1242  func createStore(ns walletdb.ReadWriteBucket) (e error) {
1243  	// Ensure that nothing currently exists in the namespace bucket.
1244  	ck, cv := ns.ReadCursor().First()
1245  	if ck != nil || cv != nil {
1246  		const str = "namespace is not empty"
1247  		return storeError(ErrAlreadyExists, str, nil)
1248  	}
1249  	// Write the latest store version.
1250  	v := make([]byte, 4)
1251  	byteOrder.PutUint32(v, LatestVersion)
1252  	e = ns.Put(rootVersion, v)
1253  	if e != nil {
1254  		str := "failed to store latest database version"
1255  		return storeError(ErrDatabase, str, e)
1256  	}
1257  	// Save the creation date of the store.
1258  	v = make([]byte, 8)
1259  	byteOrder.PutUint64(v, uint64(time.Now().Unix()))
1260  	e = ns.Put(rootCreateDate, v)
1261  	if e != nil {
1262  		str := "failed to store database creation time"
1263  		return storeError(ErrDatabase, str, e)
1264  	}
1265  	// Write a zero balance.
1266  	v = make([]byte, 8)
1267  	e = ns.Put(rootMinedBalance, v)
1268  	if e != nil {
1269  		str := "failed to write zero balance"
1270  		return storeError(ErrDatabase, str, e)
1271  	}
1272  	_, e = ns.CreateBucket(bucketBlocks)
1273  	if e != nil {
1274  		str := "failed to create blocks bucket"
1275  		return storeError(ErrDatabase, str, e)
1276  	}
1277  	_, e = ns.CreateBucket(bucketTxRecords)
1278  	if e != nil {
1279  		str := "failed to create tx records bucket"
1280  		return storeError(ErrDatabase, str, e)
1281  	}
1282  	_, e = ns.CreateBucket(bucketCredits)
1283  	if e != nil {
1284  		str := "failed to create credits bucket"
1285  		return storeError(ErrDatabase, str, e)
1286  	}
1287  	_, e = ns.CreateBucket(bucketDebits)
1288  	if e != nil {
1289  		str := "failed to create debits bucket"
1290  		return storeError(ErrDatabase, str, e)
1291  	}
1292  	_, e = ns.CreateBucket(bucketUnspent)
1293  	if e != nil {
1294  		str := "failed to create unspent bucket"
1295  		return storeError(ErrDatabase, str, e)
1296  	}
1297  	_, e = ns.CreateBucket(bucketUnmined)
1298  	if e != nil {
1299  		str := "failed to create unmined bucket"
1300  		return storeError(ErrDatabase, str, e)
1301  	}
1302  	_, e = ns.CreateBucket(bucketUnminedCredits)
1303  	if e != nil {
1304  		str := "failed to create unmined credits bucket"
1305  		return storeError(ErrDatabase, str, e)
1306  	}
1307  	_, e = ns.CreateBucket(bucketUnminedInputs)
1308  	if e != nil {
1309  		str := "failed to create unmined inputs bucket"
1310  		return storeError(ErrDatabase, str, e)
1311  	}
1312  	return nil
1313  }
1314  
1315  // func scopedUpdate(// 	db walletdb.DB, namespaceKey []byte, f func(walletdb.ReadWriteBucket) error) (e error) {
1316  // 	tx, e := db.BeginReadWriteTx()
1317  // 	if e != nil  {
1318  // DB// 		str := "cannot begin update"
1319  // 		return storeError(ErrDatabase, str, err)
1320  // 	}
1321  // 	e = f(tx.ReadWriteBucket(namespaceKey))
1322  // 	if e != nil  {
1323  // 	DB// 		rollbackErr := tx.Rollback()
1324  // 		if rollbackErr != nil {
1325  // 			const desc = "rollback failed"
1326  // 			serr, ok := err.(DBError)
1327  // 			if !ok {
1328  // 				// This really shouldn't happen.
1329  // 				return storeError(ErrDatabase, desc, rollbackErr)
1330  // 			}
1331  // 			serr.Desc = desc + ": " + serr.Desc
1332  // 			return serr
1333  // 		}
1334  // 		return e
1335  // 	}
1336  // 	e = tx.Commit()
1337  // 	if e != nil  {
1338  //		DB// 		str := "commit failed"
1339  // 		return storeError(ErrDatabase, str, err)
1340  // 	}
1341  // 	return nil
1342  // }
1343  // func scopedView(// 	db walletdb.DB, namespaceKey []byte, f func(walletdb.ReadBucket) error) (e error) {
1344  // 	tx, e := db.BeginReadTx()
1345  // 	if e != nil  {
1346  //		DB// 		str := "cannot begin view"
1347  // 		return storeError(ErrDatabase, str, err)
1348  // 	}
1349  // 	e = f(tx.ReadBucket(namespaceKey))
1350  // 	rollbackErr := tx.Rollback()
1351  // 	if e != nil  {
1352  //		DB// 		return e
1353  // 	}
1354  // 	if rollbackErr != nil {
1355  // 		str := "cannot close view"
1356  // 		return storeError(ErrDatabase, str, rollbackErr)
1357  // 	}
1358  // 	return nil
1359  // }
1360