Example #1
0
// BUGS:
// - MinimumRecentTransactions is ignored.
// - Wrong error codes when a block height or hash is not recognized
func (s *walletServer) GetTransactions(ctx context.Context, req *pb.GetTransactionsRequest) (
	resp *pb.GetTransactionsResponse, err error) {

	var startBlock, endBlock *wallet.BlockIdentifier
	if req.StartingBlockHash != nil && req.StartingBlockHeight != 0 {
		return nil, errors.New(
			"starting block hash and height may not be specified simultaneously")
	} else if req.StartingBlockHash != nil {
		startBlockHash, err := chainhash.NewHash(req.StartingBlockHash)
		if err != nil {
			return nil, grpc.Errorf(codes.InvalidArgument, "%s", err.Error())
		}
		startBlock = wallet.NewBlockIdentifierFromHash(startBlockHash)
	} else if req.StartingBlockHeight != 0 {
		startBlock = wallet.NewBlockIdentifierFromHeight(req.StartingBlockHeight)
	}

	if req.EndingBlockHash != nil && req.EndingBlockHeight != 0 {
		return nil, grpc.Errorf(codes.InvalidArgument,
			"ending block hash and height may not be specified simultaneously")
	} else if req.EndingBlockHash != nil {
		endBlockHash, err := chainhash.NewHash(req.EndingBlockHash)
		if err != nil {
			return nil, grpc.Errorf(codes.InvalidArgument, "%s", err.Error())
		}
		endBlock = wallet.NewBlockIdentifierFromHash(endBlockHash)
	} else if req.EndingBlockHeight != 0 {
		endBlock = wallet.NewBlockIdentifierFromHeight(req.EndingBlockHeight)
	}

	var minRecentTxs int
	if req.MinimumRecentTransactions != 0 {
		if endBlock != nil {
			return nil, grpc.Errorf(codes.InvalidArgument,
				"ending block and minimum number of recent transactions "+
					"may not be specified simultaneously")
		}
		minRecentTxs = int(req.MinimumRecentTransactions)
		if minRecentTxs < 0 {
			return nil, grpc.Errorf(codes.InvalidArgument,
				"minimum number of recent transactions may not be negative")
		}
	}

	_ = minRecentTxs

	gtr, err := s.wallet.GetTransactions(startBlock, endBlock, ctx.Done())
	if err != nil {
		return nil, translateError(err)
	}
	return marshalGetTransactionsResult(gtr)
}
Example #2
0
// deserializeTicketHashes deserializes a list of ticket hashes. Empty but
// non-nil slices are deserialized empty.
func deserializeTicketHashes(b []byte) (TicketHashes, error) {
	if b != nil && len(b) == 0 {
		return make(TicketHashes, 0), nil
	}

	if len(b) < chainhash.HashSize {
		return nil, ticketDBError(ErrTicketHashesShortRead, "short read when "+
			"deserializing ticket hashes")
	}

	if len(b)%chainhash.HashSize != 0 {
		return nil, ticketDBError(ErrTicketHashesCorrupt, "corrupt data found "+
			"when deserializing ticket hashes")
	}

	entries := len(b) / chainhash.HashSize
	ths := make(TicketHashes, entries)

	offset := 0
	for i := 0; i < entries; i++ {
		hash, err := chainhash.NewHash(
			b[offset : offset+chainhash.HashSize])
		if err != nil {
			return nil, ticketDBError(ErrUndoDataCorrupt, "corrupt hash found "+
				"when deserializing block undo data")
		}
		offset += chainhash.HashSize

		ths[i] = *hash
	}

	return ths, nil
}
Example #3
0
// 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
}
Example #4
0
// DbLoadAllTickets loads all the live tickets from the database into a treap.
func DbLoadAllTickets(dbTx database.Tx, ticketBucket []byte) (*tickettreap.Immutable, error) {
	meta := dbTx.Metadata()
	bucket := meta.Bucket(ticketBucket)

	treap := tickettreap.NewImmutable()
	err := bucket.ForEach(func(k []byte, v []byte) error {
		if len(v) < 5 {
			return ticketDBError(ErrLoadAllTickets, fmt.Sprintf("short "+
				"read for ticket key %x when loading tickets", k))
		}

		h, err := chainhash.NewHash(k)
		if err != nil {
			return err
		}
		treapKey := tickettreap.Key(*h)
		missed, revoked, spent, expired := undoBitFlagsFromByte(v[4])
		treapValue := &tickettreap.Value{
			Height:  dbnamespace.ByteOrder.Uint32(v[0:4]),
			Missed:  missed,
			Revoked: revoked,
			Spent:   spent,
			Expired: expired,
		}

		treap = treap.Put(treapKey, treapValue)
		return nil
	})
	if err != nil {
		return nil, ticketDBError(ErrLoadAllTickets, fmt.Sprintf("failed to "+
			"load all tickets for the bucket %s", string(ticketBucket)))
	}

	return treap, nil
}
Example #5
0
// deserializeUserInvalTickets deserializes the passed serialized pool
// users invalid tickets information.
func deserializeUserInvalTickets(serializedTickets []byte) ([]*chainhash.Hash,
	error) {

	// Cursory check to make sure that the number of records
	// makes sense.
	if len(serializedTickets)%chainhash.HashSize != 0 {
		err := io.ErrUnexpectedEOF
		return nil, err
	}

	numRecords := len(serializedTickets) / chainhash.HashSize

	records := make([]*chainhash.Hash, numRecords)

	// Loop through all the ssgen records, deserialize them, and
	// store them.
	for i := 0; i < numRecords; i++ {
		start := i * chainhash.HashSize
		end := (i + 1) * chainhash.HashSize
		h, err := chainhash.NewHash(serializedTickets[start:end])
		if err != nil {
			str := "problem deserializing stake pool invalid user tickets"
			return nil, stakeStoreError(ErrDatabase, str, err)
		}

		records[i] = h
	}

	return records, nil
}
Example #6
0
// SSGenBlockVotedOn takes an SSGen tx and returns the block voted on in the
// first OP_RETURN by hash and height.
//
// This function is only safe to be called on a transaction that
// has passed IsSSGen.
func SSGenBlockVotedOn(tx *wire.MsgTx) (chainhash.Hash, uint32, error) {
	// Get the block header hash.
	blockSha, err := chainhash.NewHash(tx.TxOut[0].PkScript[2:34])
	if err != nil {
		return chainhash.Hash{}, 0, err
	}

	// Get the block height.
	height := binary.LittleEndian.Uint32(tx.TxOut[0].PkScript[34:38])

	return *blockSha, height, nil
}
Example #7
0
func NewCoin(index int64, value dcrutil.Amount, numConfs int64) coinset.Coin {
	h := fastsha256.New()
	h.Write([]byte(fmt.Sprintf("%d", index)))
	hash, _ := chainhash.NewHash(h.Sum(nil))
	c := &TestCoin{
		TxHash:     hash,
		TxIndex:    0,
		TxValue:    value,
		TxNumConfs: numConfs,
	}
	return coinset.Coin(c)
}
Example #8
0
/* convert target come from getwork to big integer
   "ffffffffffffffffffffffffffffffffffffffffffffffffffffff3f00000000"
*/
func TargetStrToDiff(targetHex string) *big.Int {
	hashbytes, err := hex.DecodeString(targetHex)
	if err != nil {
		return big.NewInt(0)
	}
	hash, err := chainhash.NewHash(hashbytes)
	if err != nil {
		return big.NewInt(0)
	}
	targetdiff := blockchain.ShaHashToBig(hash)
	if targetdiff.Cmp(big.NewInt(0)) != 0 {
		targetdiff.Div(PowLimit, targetdiff)
	}
	return targetdiff
}
Example #9
0
// deserializeBlockUndoData deserializes a list of UndoTicketData for an entire
// block. Empty but non-nil slices are deserialized empty.
func deserializeBlockUndoData(b []byte) ([]UndoTicketData, error) {
	if b != nil && len(b) == 0 {
		return make([]UndoTicketData, 0), nil
	}

	if len(b) < undoTicketDataSize {
		return nil, ticketDBError(ErrUndoDataShortRead, "short read when "+
			"deserializing block undo data")
	}

	if len(b)%undoTicketDataSize != 0 {
		return nil, ticketDBError(ErrUndoDataCorrupt, "corrupt data found "+
			"when deserializing block undo data")
	}

	entries := len(b) / undoTicketDataSize
	utds := make([]UndoTicketData, entries)

	offset := 0
	for i := 0; i < entries; i++ {
		hash, err := chainhash.NewHash(
			b[offset : offset+chainhash.HashSize])
		if err != nil {
			return nil, ticketDBError(ErrUndoDataCorrupt, "corrupt hash found "+
				"when deserializing block undo data")
		}
		offset += chainhash.HashSize

		height := dbnamespace.ByteOrder.Uint32(b[offset : offset+4])
		offset += 4

		missed, revoked, spent, expired := undoBitFlagsFromByte(b[offset])
		offset++

		utds[i] = UndoTicketData{
			TicketHash:   *hash,
			TicketHeight: height,
			Missed:       missed,
			Revoked:      revoked,
			Spent:        spent,
			Expired:      expired,
		}
	}

	return utds, nil
}
Example #10
0
// 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
}
Example #11
0
// BenchmarkMruInventoryList performs basic benchmarks on the most recently
// used inventory handling.
func BenchmarkMruInventoryList(b *testing.B) {
	// Create a bunch of fake inventory vectors to use in benchmarking
	// the mru inventory code.
	b.StopTimer()
	numInvVects := 100000
	invVects := make([]*wire.InvVect, 0, numInvVects)
	for i := 0; i < numInvVects; i++ {
		hashBytes := make([]byte, chainhash.HashSize)
		rand.Read(hashBytes)
		hash, _ := chainhash.NewHash(hashBytes)
		iv := wire.NewInvVect(wire.InvTypeBlock, hash)
		invVects = append(invVects, iv)
	}
	b.StartTimer()

	// Benchmark the add plus evicition code.
	limit := 20000
	mruInvMap := NewMruInventoryMap(uint(limit))
	for i := 0; i < b.N; i++ {
		mruInvMap.Add(invVects[i%numInvVects])
	}
}
Example #12
0
// NewHash256PRNG creates a pointer to a newly created hash256PRNG.
func NewHash256PRNG(seed []byte) *Hash256PRNG {
	// idx and lastHash are automatically initialized
	// as 0. We initialize the seed by appending a constant
	// to it and hashing to give 32 bytes. This ensures
	// that regardless of the input, the PRNG is always
	// doing a short number of rounds because it only
	// has to hash < 64 byte messages. The constant is
	// derived from the hexadecimal representation of
	// pi.
	cst := []byte{0x24, 0x3F, 0x6A, 0x88,
		0x85, 0xA3, 0x08, 0xD3}
	hp := new(Hash256PRNG)
	hp.seed = chainhash.HashFuncB(append(seed, cst...))
	initLH, err := chainhash.NewHash(hp.seed)
	if err != nil {
		return nil
	}
	hp.seedState = *initLH
	hp.lastHash = *initLH
	hp.idx = 0
	return hp
}
Example #13
0
func TestBlockHeaderHashing(t *testing.T) {
	dummyHeader := "0000000049e0b48ade043f729d60095ed92642d96096fe6aba42f2eda" +
		"632d461591a152267dc840ff27602ce1968a81eb30a43423517207617a0150b56c4f72" +
		"b803e497f00000000000000000000000000000000000000000000000000000000000000" +
		"00010000000000000000000000b7000000ffff7f20204e0000000000005800000060010" +
		"0008b990956000000000000000000000000000000000000000000000000000000000000" +
		"0000000000000000ABCD"
	// This hash has reversed endianness compared to what chainhash spits out.
	hashStr := "0d40d58703482d81d711be0ffc1b313788d3c3937e1617e4876661d33a8c4c41"
	hashB, _ := hex.DecodeString(hashStr)
	hash, _ := chainhash.NewHash(hashB)

	vecH, _ := hex.DecodeString(dummyHeader)
	r := bytes.NewReader(vecH)
	var bh wire.BlockHeader
	bh.Deserialize(r)
	hash2 := bh.BlockSha()

	if !hash2.IsEqual(hash) {
		t.Errorf("wrong block sha returned (want %v, got %v)",
			hash,
			hash2)
	}
}
Example #14
0
// 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
}
Example #15
0
// BUGS:
// - MinimumRecentTransactions is ignored.
// - Wrong error codes when a block height or hash is not recognized
func (s *walletServer) GetTransactions(req *pb.GetTransactionsRequest,
	server pb.WalletService_GetTransactionsServer) error {

	var startBlock, endBlock *wallet.BlockIdentifier
	if req.StartingBlockHash != nil && req.StartingBlockHeight != 0 {
		return grpc.Errorf(codes.InvalidArgument,
			"starting block hash and height may not be specified simultaneously")
	} else if req.StartingBlockHash != nil {
		startBlockHash, err := chainhash.NewHash(req.StartingBlockHash)
		if err != nil {
			return grpc.Errorf(codes.InvalidArgument, "%s", err.Error())
		}
		startBlock = wallet.NewBlockIdentifierFromHash(startBlockHash)
	} else if req.StartingBlockHeight != 0 {
		startBlock = wallet.NewBlockIdentifierFromHeight(req.StartingBlockHeight)
	}

	if req.EndingBlockHash != nil && req.EndingBlockHeight != 0 {
		return grpc.Errorf(codes.InvalidArgument,
			"ending block hash and height may not be specified simultaneously")
	} else if req.EndingBlockHash != nil {
		endBlockHash, err := chainhash.NewHash(req.EndingBlockHash)
		if err != nil {
			return grpc.Errorf(codes.InvalidArgument, "%s", err.Error())
		}
		endBlock = wallet.NewBlockIdentifierFromHash(endBlockHash)
	} else if req.EndingBlockHeight != 0 {
		endBlock = wallet.NewBlockIdentifierFromHeight(req.EndingBlockHeight)
	}

	var minRecentTxs int
	if req.MinimumRecentTransactions != 0 {
		if endBlock != nil {
			return grpc.Errorf(codes.InvalidArgument,
				"ending block and minimum number of recent transactions "+
					"may not be specified simultaneously")
		}
		minRecentTxs = int(req.MinimumRecentTransactions)
		if minRecentTxs < 0 {
			return grpc.Errorf(codes.InvalidArgument,
				"minimum number of recent transactions may not be negative")
		}
	}

	_ = minRecentTxs

	gtr, err := s.wallet.GetTransactions(startBlock, endBlock, server.Context().Done())
	if err != nil {
		return translateError(err)
	}
	for i := range gtr.MinedTransactions {
		resp := &pb.GetTransactionsResponse{
			MinedTransactions: marshalBlock(&gtr.MinedTransactions[i]),
		}
		err = server.Send(resp)
		if err != nil {
			return err
		}
	}
	if len(gtr.UnminedTransactions) > 0 {
		resp := &pb.GetTransactionsResponse{
			UnminedTransactions: marshalTransactionDetails(gtr.UnminedTransactions),
		}
		err = server.Send(resp)
		if err != nil {
			return err
		}
	}
	return nil
}
Example #16
0
// TestMerkleBlock tests the MsgMerkleBlock API.
func TestMerkleBlock(t *testing.T) {
	pver := ProtocolVersion

	// Test block header.
	bh := NewBlockHeader(
		int32(pver),
		&testBlock.Header.PrevBlock,                 // PrevHash
		&testBlock.Header.MerkleRoot,                // MerkleRootHash
		&testBlock.Header.StakeRoot,                 // StakeRoot
		uint16(0x0000),                              // VoteBits
		[6]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // FinalState
		uint16(0x0000),                              // Voters
		uint8(0x00),                                 // FreshStake
		uint8(0x00),                                 // Revocations
		uint32(0),                                   // Poolsize
		testBlock.Header.Bits,                       // Bits
		int64(0x0000000000000000),                   // Sbits
		uint32(1),                                   // Height
		uint32(0),                                   // Size
		testBlock.Header.Nonce,                      // Nonce
		[32]byte{},                                  // ExtraData
		uint32(0x7e1eca57),                          // StakeVersion
	)

	// Ensure the command is expected value.
	wantCmd := "merkleblock"
	msg := NewMsgMerkleBlock(bh)
	if cmd := msg.Command(); cmd != wantCmd {
		t.Errorf("NewMsgBlock: wrong command - got %v want %v",
			cmd, wantCmd)
	}

	// Ensure max payload is expected value for latest protocol version.
	// Num addresses (varInt) + max allowed addresses.
	wantPayload := uint32(1000000)
	maxPayload := msg.MaxPayloadLength(pver)
	if maxPayload != wantPayload {
		t.Errorf("MaxPayloadLength: wrong max payload length for "+
			"protocol version %d - got %v, want %v", pver,
			maxPayload, wantPayload)
	}

	// Load maxTxPerBlock hashes
	data := make([]byte, 32)
	for i := 0; i < MaxTxPerTxTree; i++ {
		rand.Read(data)
		hash, err := chainhash.NewHash(data)
		if err != nil {
			t.Errorf("NewShaHash failed: %v\n", err)
			return
		}

		if err = msg.AddTxHash(hash); err != nil {
			t.Errorf("AddTxHash failed: %v\n", err)
			return
		}
		if err = msg.AddSTxHash(hash); err != nil {
			t.Errorf("AddSTxHash failed: %v\n", err)
			return
		}
	}

	// Add one more Tx to test failure.
	rand.Read(data)
	hash, err := chainhash.NewHash(data)
	if err != nil {
		t.Errorf("NewShaHash failed: %v\n", err)
		return
	}

	if err = msg.AddTxHash(hash); err == nil {
		t.Errorf("AddTxHash succeeded when it should have failed")
		return
	}

	// Add one more STx to test failure.
	rand.Read(data)
	hash, err = chainhash.NewHash(data)
	if err != nil {
		t.Errorf("NewShaHash failed: %v\n", err)
		return
	}

	if err = msg.AddSTxHash(hash); err == nil {
		t.Errorf("AddTxHash succeeded when it should have failed")
		return
	}

	// Test encode with latest protocol version.
	var buf bytes.Buffer
	err = msg.BtcEncode(&buf, pver)
	if err != nil {
		t.Errorf("encode of MsgMerkleBlock failed %v err <%v>", msg, err)
	}

	// Test decode with latest protocol version.
	readmsg := MsgMerkleBlock{}
	err = readmsg.BtcDecode(&buf, pver)
	if err != nil {
		t.Errorf("decode of MsgMerkleBlock failed [%v] err <%v>", buf, err)
	}

	// Force extra hash to test maxTxPerBlock.
	msg.Hashes = append(msg.Hashes, hash)
	err = msg.BtcEncode(&buf, pver)
	if err == nil {
		t.Errorf("encode of MsgMerkleBlock succeeded with too many " +
			"tx hashes when it should have failed")
		return
	}

	// Force too many flag bytes to test maxFlagsPerMerkleBlock.
	// Reset the number of hashes back to a valid value.
	msg.Hashes = msg.Hashes[len(msg.Hashes)-1:]
	msg.Flags = make([]byte, maxFlagsPerMerkleBlock+1)
	err = msg.BtcEncode(&buf, pver)
	if err == nil {
		t.Errorf("encode of MsgMerkleBlock succeeded with too many " +
			"flag bytes when it should have failed")
		return
	}
}
Example #17
0
// TestShaHash tests the ShaHash API.
func TestShaHash(t *testing.T) {

	// Hash of block 234439.
	blockHashStr := "14a0810ac680a3eb3f82edc878cea25ec41d6b790744e5daeef"
	blockHash, err := chainhash.NewHashFromStr(blockHashStr)
	if err != nil {
		t.Errorf("NewShaHashFromStr: %v", err)
	}

	// Hash of block 234440 as byte slice.
	buf := []byte{
		0x79, 0xa6, 0x1a, 0xdb, 0xc6, 0xe5, 0xa2, 0xe1,
		0x39, 0xd2, 0x71, 0x3a, 0x54, 0x6e, 0xc7, 0xc8,
		0x75, 0x63, 0x2e, 0x75, 0xf1, 0xdf, 0x9c, 0x3f,
		0xa6, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	}

	hash, err := chainhash.NewHash(buf)
	if err != nil {
		t.Errorf("NewShaHash: unexpected error %v", err)
	}

	// Ensure proper size.
	if len(hash) != chainhash.HashSize {
		t.Errorf("NewShaHash: hash length mismatch - got: %v, want: %v",
			len(hash), chainhash.HashSize)
	}

	// Ensure contents match.
	if !bytes.Equal(hash[:], buf) {
		t.Errorf("NewShaHash: hash contents mismatch - got: %v, want: %v",
			hash[:], buf)
	}

	// Ensure contents of hash of block 234440 don't match 234439.
	if hash.IsEqual(blockHash) {
		t.Errorf("IsEqual: hash contents should not match - got: %v, want: %v",
			hash, blockHash)
	}

	// Set hash from byte slice and ensure contents match.
	err = hash.SetBytes(blockHash.Bytes())
	if err != nil {
		t.Errorf("SetBytes: %v", err)
	}
	if !hash.IsEqual(blockHash) {
		t.Errorf("IsEqual: hash contents mismatch - got: %v, want: %v",
			hash, blockHash)
	}

	// Invalid size for SetBytes.
	err = hash.SetBytes([]byte{0x00})
	if err == nil {
		t.Errorf("SetBytes: failed to received expected err - got: nil")
	}

	// Invalid size for NewShaHash.
	invalidHash := make([]byte, chainhash.HashSize+1)
	_, err = chainhash.NewHash(invalidHash)
	if err == nil {
		t.Errorf("NewShaHash: failed to received expected err - got: nil")
	}
}
Example #18
0
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
}