github.com/btcsuite/btcd@v0.24.0/wire/msgmerkleblock.go (about) 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. 4 5 package wire 6 7 import ( 8 "fmt" 9 "io" 10 11 "github.com/btcsuite/btcd/chaincfg/chainhash" 12 ) 13 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 19 20 // MsgMerkleBlock implements the Message interface and represents a bitcoin 21 // merkleblock message which is used to reset a Bloom filter. 22 // 23 // This message was not added until protocol version BIP0037Version. 24 type MsgMerkleBlock struct { 25 Header BlockHeader 26 Transactions uint32 27 Hashes []*chainhash.Hash 28 Flags []byte 29 } 30 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]", 35 maxTxPerBlock) 36 return messageError("MsgMerkleBlock.AddTxHash", str) 37 } 38 39 msg.Hashes = append(msg.Hashes, hash) 40 return nil 41 } 42 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 "+ 48 "version %d", pver) 49 return messageError("MsgMerkleBlock.BtcDecode", str) 50 } 51 52 buf := binarySerializer.Borrow() 53 defer binarySerializer.Return(buf) 54 55 err := readBlockHeaderBuf(r, pver, &msg.Header, buf) 56 if err != nil { 57 return err 58 } 59 60 if _, err := io.ReadFull(r, buf[:4]); err != nil { 61 return err 62 } 63 msg.Transactions = littleEndian.Uint32(buf[:4]) 64 65 // Read num block locator hashes and limit to max. 66 count, err := ReadVarIntBuf(r, pver, buf) 67 if err != nil { 68 return err 69 } 70 if count > maxTxPerBlock { 71 str := fmt.Sprintf("too many transaction hashes for message "+ 72 "[count %v, max %v]", count, maxTxPerBlock) 73 return messageError("MsgMerkleBlock.BtcDecode", str) 74 } 75 76 // Create a contiguous slice of hashes to deserialize into in order to 77 // reduce the number of allocations. 78 hashes := make([]chainhash.Hash, count) 79 msg.Hashes = make([]*chainhash.Hash, 0, count) 80 for i := uint64(0); i < count; i++ { 81 hash := &hashes[i] 82 _, err := io.ReadFull(r, hash[:]) 83 if err != nil { 84 return err 85 } 86 msg.AddTxHash(hash) 87 } 88 89 msg.Flags, err = ReadVarBytesBuf(r, pver, buf, maxFlagsPerMerkleBlock, 90 "merkle block flags size") 91 return err 92 } 93 94 // BtcEncode encodes the receiver to w using the bitcoin protocol encoding. 95 // This is part of the Message interface implementation. 96 func (msg *MsgMerkleBlock) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error { 97 if pver < BIP0037Version { 98 str := fmt.Sprintf("merkleblock message invalid for protocol "+ 99 "version %d", pver) 100 return messageError("MsgMerkleBlock.BtcEncode", str) 101 } 102 103 // Read num transaction hashes and limit to max. 104 numHashes := len(msg.Hashes) 105 if numHashes > maxTxPerBlock { 106 str := fmt.Sprintf("too many transaction hashes for message "+ 107 "[count %v, max %v]", numHashes, maxTxPerBlock) 108 return messageError("MsgMerkleBlock.BtcDecode", str) 109 } 110 numFlagBytes := len(msg.Flags) 111 if numFlagBytes > maxFlagsPerMerkleBlock { 112 str := fmt.Sprintf("too many flag bytes for message [count %v, "+ 113 "max %v]", numFlagBytes, maxFlagsPerMerkleBlock) 114 return messageError("MsgMerkleBlock.BtcDecode", str) 115 } 116 117 buf := binarySerializer.Borrow() 118 defer binarySerializer.Return(buf) 119 120 err := writeBlockHeaderBuf(w, pver, &msg.Header, buf) 121 if err != nil { 122 return err 123 } 124 125 littleEndian.PutUint32(buf[:4], msg.Transactions) 126 if _, err := w.Write(buf[:4]); err != nil { 127 return err 128 } 129 130 err = WriteVarIntBuf(w, pver, uint64(numHashes), buf) 131 if err != nil { 132 return err 133 } 134 for _, hash := range msg.Hashes { 135 _, err := w.Write(hash[:]) 136 if err != nil { 137 return err 138 } 139 } 140 141 err = WriteVarBytesBuf(w, pver, msg.Flags, buf) 142 return err 143 } 144 145 // Command returns the protocol command string for the message. This is part 146 // of the Message interface implementation. 147 func (msg *MsgMerkleBlock) Command() string { 148 return CmdMerkleBlock 149 } 150 151 // MaxPayloadLength returns the maximum length the payload can be for the 152 // receiver. This is part of the Message interface implementation. 153 func (msg *MsgMerkleBlock) MaxPayloadLength(pver uint32) uint32 { 154 return MaxBlockPayload 155 } 156 157 // NewMsgMerkleBlock returns a new bitcoin merkleblock message that conforms to 158 // the Message interface. See MsgMerkleBlock for details. 159 func NewMsgMerkleBlock(bh *BlockHeader) *MsgMerkleBlock { 160 return &MsgMerkleBlock{ 161 Header: *bh, 162 Transactions: 0, 163 Hashes: make([]*chainhash.Hash, 0), 164 Flags: make([]byte, 0), 165 } 166 }