// TicketDbThumbprint takes all the tickets in the respective ticket db, // sorts them, hashes their contents into a list, and then hashes that list. // The resultant hash is the thumbprint of the ticket database, and should // be the same across all clients that are synced to the same block. Returns // an array of hashes len 3, containing (1) live tickets (2) spent tickets // and (3) missed tickets. // Do NOT use on mainnet or in production. For debug use only! Make sure // the blockchain is frozen when you call this function. func TicketDbThumbprint(tmdb *stake.TicketDB, chainParams *chaincfg.Params) ([]*chainhash.Hash, error) { // Container for the three master hashes to go into. dbThumbprints := make([]*chainhash.Hash, 3, 3) // (1) Live tickets. allLiveTickets := stake.NewTicketDataSliceEmpty() for i := 0; i < stake.BucketsSize; i++ { bucketTickets, err := tmdb.DumpLiveTickets(uint8(i)) if err != nil { return nil, err } for _, td := range bucketTickets { allLiveTickets = append(allLiveTickets, td) } } // Sort by the number data hash, since we already have this implemented // and it's also unique. sort.Sort(allLiveTickets) // Create a buffer, dump all the data into it, and hash. var buf bytes.Buffer for _, td := range allLiveTickets { writeTicketDataToBuf(&buf, td) } liveHash := chainhash.HashFunc(buf.Bytes()) liveThumbprint, err := chainhash.NewHash(liveHash[:]) if err != nil { return nil, err } dbThumbprints[0] = liveThumbprint // (2) Spent tickets. height := tmdb.GetTopBlock() allSpentTickets := stake.NewTicketDataSliceEmpty() for i := int64(chainParams.StakeEnabledHeight); i <= height; i++ { bucketTickets, err := tmdb.DumpSpentTickets(i) if err != nil { return nil, err } for _, td := range bucketTickets { allSpentTickets = append(allSpentTickets, td) } } sort.Sort(allSpentTickets) buf.Reset() // Flush buffer for _, td := range allSpentTickets { writeTicketDataToBuf(&buf, td) } spentHash := chainhash.HashFunc(buf.Bytes()) spentThumbprint, err := chainhash.NewHash(spentHash[:]) if err != nil { return nil, err } dbThumbprints[1] = spentThumbprint // (3) Missed tickets. allMissedTickets := stake.NewTicketDataSliceEmpty() missedTickets, err := tmdb.DumpMissedTickets() if err != nil { return nil, err } for _, td := range missedTickets { allMissedTickets = append(allMissedTickets, td) } sort.Sort(allMissedTickets) buf.Reset() // Flush buffer missedHash := chainhash.HashFunc(buf.Bytes()) missedThumbprint, err := chainhash.NewHash(missedHash[:]) if err != nil { return nil, err } dbThumbprints[2] = missedThumbprint return dbThumbprints, 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 }