OSDN Git Service

new repo
[bytom/vapor.git] / vendor / github.com / btcsuite / btcd / wire / msgmerkleblock.go
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         err := readBlockHeader(r, pver, &msg.Header)
53         if err != nil {
54                 return err
55         }
56
57         err = readElement(r, &msg.Transactions)
58         if err != nil {
59                 return err
60         }
61
62         // Read num block locator hashes and limit to max.
63         count, err := ReadVarInt(r, pver)
64         if err != nil {
65                 return err
66         }
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)
71         }
72
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++ {
78                 hash := &hashes[i]
79                 err := readElement(r, hash)
80                 if err != nil {
81                         return err
82                 }
83                 msg.AddTxHash(hash)
84         }
85
86         msg.Flags, err = ReadVarBytes(r, pver, maxFlagsPerMerkleBlock,
87                 "merkle block flags size")
88         return err
89 }
90
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 "+
96                         "version %d", pver)
97                 return messageError("MsgMerkleBlock.BtcEncode", str)
98         }
99
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)
106         }
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)
112         }
113
114         err := writeBlockHeader(w, pver, &msg.Header)
115         if err != nil {
116                 return err
117         }
118
119         err = writeElement(w, msg.Transactions)
120         if err != nil {
121                 return err
122         }
123
124         err = WriteVarInt(w, pver, uint64(numHashes))
125         if err != nil {
126                 return err
127         }
128         for _, hash := range msg.Hashes {
129                 err = writeElement(w, hash)
130                 if err != nil {
131                         return err
132                 }
133         }
134
135         return WriteVarBytes(w, pver, msg.Flags)
136 }
137
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
142 }
143
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
148 }
149
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{
154                 Header:       *bh,
155                 Transactions: 0,
156                 Hashes:       make([]*chainhash.Hash, 0),
157                 Flags:        make([]byte, 0),
158         }
159 }