// loadManager returns a new stake manager that results from loading it from // the passed opened database. The public passphrase is required to decrypt the // public keys. func (s *StakeStore) loadOwnedSStxs(ns walletdb.ReadBucket) error { // Regenerate the list of tickets. // Perform all database lookups in a read-only view. ticketList := make(map[chainhash.Hash]struct{}) // Open the sstx records database. bucket := ns.NestedReadBucket(sstxRecordsBucketName) // Store each key sequentially. err := bucket.ForEach(func(k []byte, v []byte) error { var errNewHash error var hash *chainhash.Hash hash, errNewHash = chainhash.NewHash(k) if errNewHash != nil { return errNewHash } ticketList[*hash] = struct{}{} return nil }) if err != nil { return err } s.ownedSStxs = ticketList return nil }
// rangeUnminedTransactions executes the function f with TxDetails for every // unmined transaction. f is not executed if no unmined transactions exist. // Error returns from f (if any) are propigated to the caller. Returns true // (signaling breaking out of a RangeTransactions) iff f executes and returns // true. func (s *Store) rangeUnminedTransactions(ns walletdb.ReadBucket, f func([]TxDetails) (bool, error)) (bool, error) { var details []TxDetails err := ns.NestedReadBucket(bucketUnmined).ForEach(func(k, v []byte) error { if len(k) < 32 { str := fmt.Sprintf("%s: short key (expected %d "+ "bytes, read %d)", bucketUnmined, 32, len(k)) return storeError(ErrData, str, nil) } var txHash chainhash.Hash copy(txHash[:], k) detail, err := s.unminedTxDetails(ns, &txHash, v) if err != nil { return err } // Because the key was created while foreach-ing over the // bucket, it should be impossible for unminedTxDetails to ever // successfully return a nil details struct. details = append(details, *detail) return nil }) if err == nil && len(details) > 0 { return f(details) } return false, err }
func (s *Store) unminedTxHashes(ns walletdb.ReadBucket) ([]*chainhash.Hash, error) { var hashes []*chainhash.Hash err := ns.NestedReadBucket(bucketUnmined).ForEach(func(k, v []byte) error { hash := new(chainhash.Hash) err := readRawUnminedHash(k, hash) if err == nil { hashes = append(hashes, hash) } return err }) return hashes, err }
// fetchSStxRecord retrieves a tx record from the sstx records bucket // with the given hash. func fetchSStxRecord(ns walletdb.ReadBucket, hash *chainhash.Hash) (*sstxRecord, error) { bucket := ns.NestedReadBucket(sstxRecordsBucketName) key := hash.Bytes() val := bucket.Get(key) if val == nil { str := fmt.Sprintf("missing sstx record for hash '%s'", hash.String()) return nil, stakeStoreError(ErrSStxNotFound, str, nil) } return deserializeSStxRecord(val) }
// fetchMeta fetches a v from a k in the meta bucket. func fetchMeta(ns walletdb.ReadBucket, key []byte) (int32, error) { bucket := ns.NestedReadBucket(metaBucketName) val := bucket.Get(key) // Return 0 if the metadata is uninitialized if val == nil { return 0, nil } if val == nil { str := fmt.Sprintf("meta key not found %s", key) return 0, stakeStoreError(ErrDatabase, str, nil) } return int32(byteOrder.Uint32(val)), nil }
// dumpSSRtxTickets fetches the entire list of tickets spent as revocations // byt this wallet. func (s *StakeStore) dumpSSRtxTickets(ns walletdb.ReadBucket) ([]chainhash.Hash, error) { var ticketList []chainhash.Hash // Open the revocation records database. bucket := ns.NestedReadBucket(ssrtxRecordsBucketName) // Store each hash sequentially. err := bucket.ForEach(func(k []byte, v []byte) error { ticket, errDeser := chainhash.NewHash(k) if errDeser != nil { return errDeser } ticketList = append(ticketList, *ticket) return nil }) return ticketList, err }
// dumpSSRtxHashes fetches the entire list of revocations generated by this // wallet. func (s *StakeStore) dumpSSRtxHashes(ns walletdb.ReadBucket) ([]chainhash.Hash, error) { var revocationList []chainhash.Hash // Open the revocation records database. bucket := ns.NestedReadBucket(ssrtxRecordsBucketName) // Store each hash sequentially. err := bucket.ForEach(func(k []byte, v []byte) error { rec, errDeser := deserializeSSRtxRecord(v) if errDeser != nil { return errDeser } revocationList = append(revocationList, rec.txHash) return nil }) return revocationList, err }
// fetchStakePoolUserTickets retrieves pool user tickets from the meta bucket with // the given hash. func fetchStakePoolUserTickets(ns walletdb.ReadBucket, scriptHash [20]byte) ([]*PoolTicket, error) { bucket := ns.NestedReadBucket(metaBucketName) key := make([]byte, stakePoolTicketsPrefixSize+scriptHashSize) copy(key[0:stakePoolTicketsPrefixSize], stakePoolTicketsPrefix) copy(key[stakePoolTicketsPrefixSize:stakePoolTicketsPrefixSize+scriptHashSize], scriptHash[:]) val := bucket.Get(key) if val == nil { str := fmt.Sprintf("missing pool user ticket records for hash '%x'", scriptHash) return nil, stakeStoreError(ErrPoolUserTicketsNotFound, str, nil) } return deserializeUserTickets(val) }
// fetchSStxRecordVoteBits fetches an individual ticket's intended voteBits // which are used to override the default voteBits when voting. func fetchSStxRecordVoteBits(ns walletdb.ReadBucket, hash *chainhash.Hash) (bool, stake.VoteBits, error) { bucket := ns.NestedReadBucket(sstxRecordsBucketName) key := hash.Bytes() val := bucket.Get(key) if val == nil { str := fmt.Sprintf("missing sstx record for hash '%s'", hash.String()) return false, stake.VoteBits{}, stakeStoreError(ErrSStxNotFound, str, nil) } valLen := len(val) valCopy := make([]byte, valLen, valLen) copy(valCopy, val) // Move the cursor to the voteBits position and rewrite it. curPos := 0 curPos += int64Size curPos += int32Size // Read the intended votebits length (uint8). If it is unset, return now. // Check it for sanity. voteBitsLen := uint8(val[curPos]) if voteBitsLen == 0 { return false, stake.VoteBits{}, nil } if voteBitsLen < 2 || voteBitsLen > stake.MaxSingleBytePushLength { str := fmt.Sprintf("corrupt votebits length '%v'", voteBitsLen) return false, stake.VoteBits{}, stakeStoreError(ErrData, str, nil) } curPos += int8Size // Read the first two bytes for the intended votebits. voteBits := byteOrder.Uint16(valCopy[curPos : curPos+int16Size]) curPos += int16Size // Retrieve the extended vote bits. voteBitsExt := make([]byte, voteBitsLen-int16Size) copy(voteBitsExt[:], valCopy[curPos:(curPos+int(voteBitsLen)-int16Size)]) return true, stake.VoteBits{Bits: voteBits, ExtendedBits: voteBitsExt}, nil }
func (s *Store) unminedTxRecords(ns walletdb.ReadBucket) (map[chainhash.Hash]*TxRecord, error) { unmined := make(map[chainhash.Hash]*TxRecord) err := ns.NestedReadBucket(bucketUnmined).ForEach(func(k, v []byte) error { var txHash chainhash.Hash err := readRawUnminedHash(k, &txHash) if err != nil { return err } rec := new(TxRecord) err = readRawTxRecord(&txHash, v, rec) if err != nil { return err } unmined[rec.Hash] = rec return nil }) return unmined, err }
// dumpSSGenHashes fetches and returns the entire list of votes generated by // this wallet, including votes that were produced but were never included in // the blockchain. func (s *StakeStore) dumpSSGenHashes(ns walletdb.ReadBucket) ([]chainhash.Hash, error) { var voteList []chainhash.Hash // Open the vite records database. bucket := ns.NestedReadBucket(ssgenRecordsBucketName) // Store each hash sequentially. err := bucket.ForEach(func(k []byte, v []byte) error { recs, errDeser := deserializeSSGenRecords(v) if errDeser != nil { return errDeser } for _, rec := range recs { voteList = append(voteList, rec.txHash) } return nil }) return voteList, err }
// stakeStoreExists returns whether or not the stake store has already // been created in the given database namespace. func stakeStoreExists(ns walletdb.ReadBucket) bool { mainBucket := ns.NestedReadBucket(mainBucketName) return mainBucket != nil }
func (s *Store) debugBucketUnspentString(ns walletdb.ReadBucket, inclUnmined bool) (string, error) { var unspent []*unspentDebugData var op wire.OutPoint var block Block err := ns.NestedReadBucket(bucketUnspent).ForEach(func(k, v []byte) error { err := readCanonicalOutPoint(k, &op) if err != nil { return err } existsUnmined := false if existsRawUnminedInput(ns, k) != nil { // Skip including unmined if specified. if !inclUnmined { return nil } existsUnmined = true } err = readUnspentBlock(v, &block) if err != nil { return err } thisUnspentOutput := &unspentDebugData{ op, existsUnmined, block.Hash, block.Height, } unspent = append(unspent, thisUnspentOutput) return nil }) if err != nil { if _, ok := err.(Error); ok { return "", err } str := "failed iterating unspent bucket" return "", storeError(ErrDatabase, str, err) } sort.Sort(ByOutpoint(unspent)) var buffer bytes.Buffer str := fmt.Sprintf("Unspent outputs\n\n") buffer.WriteString(str) // Create a buffer, dump all the data into it, and hash. var thumbprintBuf bytes.Buffer for _, udd := range unspent { str = fmt.Sprintf("Hash: %v, Index: %v, Tree: %v, Unmined: %v, "+ "Block: %v, Block height: %v\n", udd.outPoint.Hash, udd.outPoint.Index, udd.outPoint.Tree, udd.unmined, udd.block, udd.blockHeight) buffer.WriteString(str) writeUnspentDebugDataToBuf(&thumbprintBuf, udd) } unspentHash := chainhash.HashFunc(thumbprintBuf.Bytes()) unspentThumbprint, err := chainhash.NewHash(unspentHash[:]) if err != nil { return "", err } str = fmt.Sprintf("\nUnspent outputs thumbprint: %v", unspentThumbprint) buffer.WriteString(str) return buffer.String(), nil }