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 }