1 // Copyright (c) 2014-2016 The btcsuite developers
2 // Use of this source code is governed by an ISC
3 // license that can be found in the LICENSE file.
11 "github.com/btcsuite/btcd/chaincfg/chainhash"
14 // maxFlagsPerMerkleBlock is the maximum number of flag bytes that could
15 // possibly fit into a merkle block. Since each transaction is represented by
16 // a single bit, this is the max number of transactions per block divided by
17 // 8 bits per byte. Then an extra one to cover partials.
18 const maxFlagsPerMerkleBlock = maxTxPerBlock / 8
20 // MsgMerkleBlock implements the Message interface and represents a bitcoin
21 // merkleblock message which is used to reset a Bloom filter.
23 // This message was not added until protocol version BIP0037Version.
24 type MsgMerkleBlock struct {
27 Hashes []*chainhash.Hash
31 // AddTxHash adds a new transaction hash to the message.
32 func (msg *MsgMerkleBlock) AddTxHash(hash *chainhash.Hash) error {
33 if len(msg.Hashes)+1 > maxTxPerBlock {
34 str := fmt.Sprintf("too many tx hashes for message [max %v]",
36 return messageError("MsgMerkleBlock.AddTxHash", str)
39 msg.Hashes = append(msg.Hashes, hash)
43 // BtcDecode decodes r using the bitcoin protocol encoding into the receiver.
44 // This is part of the Message interface implementation.
45 func (msg *MsgMerkleBlock) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
46 if pver < BIP0037Version {
47 str := fmt.Sprintf("merkleblock message invalid for protocol "+
49 return messageError("MsgMerkleBlock.BtcDecode", str)
52 err := readBlockHeader(r, pver, &msg.Header)
57 err = readElement(r, &msg.Transactions)
62 // Read num block locator hashes and limit to max.
63 count, err := ReadVarInt(r, pver)
67 if count > maxTxPerBlock {
68 str := fmt.Sprintf("too many transaction hashes for message "+
69 "[count %v, max %v]", count, maxTxPerBlock)
70 return messageError("MsgMerkleBlock.BtcDecode", str)
73 // Create a contiguous slice of hashes to deserialize into in order to
74 // reduce the number of allocations.
75 hashes := make([]chainhash.Hash, count)
76 msg.Hashes = make([]*chainhash.Hash, 0, count)
77 for i := uint64(0); i < count; i++ {
79 err := readElement(r, hash)
86 msg.Flags, err = ReadVarBytes(r, pver, maxFlagsPerMerkleBlock,
87 "merkle block flags size")
91 // BtcEncode encodes the receiver to w using the bitcoin protocol encoding.
92 // This is part of the Message interface implementation.
93 func (msg *MsgMerkleBlock) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error {
94 if pver < BIP0037Version {
95 str := fmt.Sprintf("merkleblock message invalid for protocol "+
97 return messageError("MsgMerkleBlock.BtcEncode", str)
100 // Read num transaction hashes and limit to max.
101 numHashes := len(msg.Hashes)
102 if numHashes > maxTxPerBlock {
103 str := fmt.Sprintf("too many transaction hashes for message "+
104 "[count %v, max %v]", numHashes, maxTxPerBlock)
105 return messageError("MsgMerkleBlock.BtcDecode", str)
107 numFlagBytes := len(msg.Flags)
108 if numFlagBytes > maxFlagsPerMerkleBlock {
109 str := fmt.Sprintf("too many flag bytes for message [count %v, "+
110 "max %v]", numFlagBytes, maxFlagsPerMerkleBlock)
111 return messageError("MsgMerkleBlock.BtcDecode", str)
114 err := writeBlockHeader(w, pver, &msg.Header)
119 err = writeElement(w, msg.Transactions)
124 err = WriteVarInt(w, pver, uint64(numHashes))
128 for _, hash := range msg.Hashes {
129 err = writeElement(w, hash)
135 return WriteVarBytes(w, pver, msg.Flags)
138 // Command returns the protocol command string for the message. This is part
139 // of the Message interface implementation.
140 func (msg *MsgMerkleBlock) Command() string {
141 return CmdMerkleBlock
144 // MaxPayloadLength returns the maximum length the payload can be for the
145 // receiver. This is part of the Message interface implementation.
146 func (msg *MsgMerkleBlock) MaxPayloadLength(pver uint32) uint32 {
147 return MaxBlockPayload
150 // NewMsgMerkleBlock returns a new bitcoin merkleblock message that conforms to
151 // the Message interface. See MsgMerkleBlock for details.
152 func NewMsgMerkleBlock(bh *BlockHeader) *MsgMerkleBlock {
153 return &MsgMerkleBlock{
156 Hashes: make([]*chainhash.Hash, 0),
157 Flags: make([]byte, 0),