1 package wire
2 3 import (
4 "fmt"
5 "io"
6 7 "github.com/p9c/p9/pkg/chainhash"
8 )
9 10 // maxFlagsPerMerkleBlock is the maximum number of flag bytes that could possibly fit into a merkle block. Since each
11 // transaction is represented by a single bit, this is the max number of transactions per block divided by 8 bits per
12 // byte. Then an extra one to cover partials.
13 const maxFlagsPerMerkleBlock = maxTxPerBlock / 8
14 15 // MsgMerkleBlock implements the Message interface and represents a bitcoin merkleblock message which is used to reset a
16 // Bloom filter. This message was not added until protocol version BIP0037Version.
17 type MsgMerkleBlock struct {
18 Header BlockHeader
19 Transactions uint32
20 Hashes []*chainhash.Hash
21 Flags []byte
22 }
23 24 // AddTxHash adds a new transaction hash to the message.
25 func (msg *MsgMerkleBlock) AddTxHash(hash *chainhash.Hash) (e error) {
26 if len(msg.Hashes)+1 > maxTxPerBlock {
27 str := fmt.Sprintf(
28 "too many tx hashes for message [max %v]",
29 maxTxPerBlock,
30 )
31 return messageError("MsgMerkleBlock.AddTxHash", str)
32 }
33 msg.Hashes = append(msg.Hashes, hash)
34 return nil
35 }
36 37 // BtcDecode decodes r using the bitcoin protocol encoding into the receiver. This is part of the Message interface
38 // implementation.
39 func (msg *MsgMerkleBlock) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) (e error) {
40 if pver < BIP0037Version {
41 str := fmt.Sprintf(
42 "merkleblock message invalid for protocol "+
43 "version %d", pver,
44 )
45 return messageError("MsgMerkleBlock.BtcDecode", str)
46 }
47 if e = readBlockHeader(r, pver, &msg.Header); E.Chk(e) {
48 return
49 }
50 if e = readElement(r, &msg.Transactions); E.Chk(e) {
51 return
52 }
53 // Read num block locator hashes and limit to max.
54 var count uint64
55 if count, e = ReadVarInt(r, pver); E.Chk(e) {
56 return
57 }
58 if count > maxTxPerBlock {
59 str := fmt.Sprintf(
60 "too many transaction hashes for message "+
61 "[count %v, max %v]", count, maxTxPerBlock,
62 )
63 return messageError("MsgMerkleBlock.BtcDecode", str)
64 }
65 // Create a contiguous slice of hashes to deserialize into in order to reduce the number of allocations.
66 hashes := make([]chainhash.Hash, count)
67 msg.Hashes = make([]*chainhash.Hash, 0, count)
68 for i := uint64(0); i < count; i++ {
69 hash := &hashes[i]
70 if e = readElement(r, hash); E.Chk(e) {
71 return
72 }
73 if e = msg.AddTxHash(hash); E.Chk(e) {
74 }
75 }
76 msg.Flags, e = ReadVarBytes(
77 r, pver, maxFlagsPerMerkleBlock,
78 "merkle block flags size",
79 )
80 return
81 }
82 83 // BtcEncode encodes the receiver to w using the bitcoin protocol encoding. This is part of the Message interface
84 // implementation.
85 func (msg *MsgMerkleBlock) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) (e error) {
86 if pver < BIP0037Version {
87 str := fmt.Sprintf(
88 "merkleblock message invalid for protocol "+
89 "version %d", pver,
90 )
91 return messageError("MsgMerkleBlock.BtcEncode", str)
92 }
93 // Read num transaction hashes and limit to max.
94 numHashes := len(msg.Hashes)
95 if numHashes > maxTxPerBlock {
96 str := fmt.Sprintf(
97 "too many transaction hashes for message "+
98 "[count %v, max %v]", numHashes, maxTxPerBlock,
99 )
100 return messageError("MsgMerkleBlock.BtcDecode", str)
101 }
102 numFlagBytes := len(msg.Flags)
103 if numFlagBytes > maxFlagsPerMerkleBlock {
104 str := fmt.Sprintf(
105 "too many flag bytes for message [count %v, "+
106 "max %v]", numFlagBytes, maxFlagsPerMerkleBlock,
107 )
108 return messageError("MsgMerkleBlock.BtcDecode", str)
109 }
110 if e = writeBlockHeader(w, pver, &msg.Header); E.Chk(e) {
111 return
112 }
113 e = writeElement(w, msg.Transactions)
114 if e != nil {
115 return
116 }
117 e = WriteVarInt(w, pver, uint64(numHashes))
118 if e != nil {
119 return
120 }
121 for _, hash := range msg.Hashes {
122 e = writeElement(w, hash)
123 if e != nil {
124 return
125 }
126 }
127 return WriteVarBytes(w, pver, msg.Flags)
128 }
129 130 // Command returns the protocol command string for the message. This is part of the Message interface implementation.
131 func (msg *MsgMerkleBlock) Command() string {
132 return CmdMerkleBlock
133 }
134 135 // MaxPayloadLength returns the maximum length the payload can be for the receiver. This is part of the Message
136 // interface implementation.
137 func (msg *MsgMerkleBlock) MaxPayloadLength(pver uint32) uint32 {
138 return MaxBlockPayload
139 }
140 141 // NewMsgMerkleBlock returns a new bitcoin merkleblock message that conforms to the Message interface. See
142 // MsgMerkleBlock for details.
143 func NewMsgMerkleBlock(bh *BlockHeader) *MsgMerkleBlock {
144 return &MsgMerkleBlock{
145 Header: *bh,
146 Transactions: 0,
147 Hashes: make([]*chainhash.Hash, 0),
148 Flags: make([]byte, 0),
149 }
150 }
151