1 package wire
2 3 import (
4 "fmt"
5 "io"
6 )
7 8 // MaxBlockHeadersPerMsg is the maximum number of block headers that can be in a
9 // single bitcoin headers message.
10 const MaxBlockHeadersPerMsg = 2000
11 12 // MsgHeaders implements the Message interface and represents a bitcoin headers
13 // message. It is used to deliver block header information in response to a
14 // getheaders message (MsgGetHeaders). The maximum number of block headers per
15 // message is currently 2000. See MsgGetHeaders for details on requesting the
16 // headers.
17 type MsgHeaders struct {
18 Headers []*BlockHeader
19 }
20 21 // AddBlockHeader adds a new block header to the message.
22 func (msg *MsgHeaders) AddBlockHeader(bh *BlockHeader) (e error) {
23 if len(msg.Headers)+1 > MaxBlockHeadersPerMsg {
24 str := fmt.Sprintf(
25 "too many block headers in message [max %v]",
26 MaxBlockHeadersPerMsg,
27 )
28 return messageError("MsgHeaders.AddBlockHeader", str)
29 }
30 msg.Headers = append(msg.Headers, bh)
31 return nil
32 }
33 34 // BtcDecode decodes r using the bitcoin protocol encoding into the receiver.
35 // This is part of the Message interface implementation.
36 func (msg *MsgHeaders) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) (e error) {
37 var count uint64
38 if count, e = ReadVarInt(r, pver); E.Chk(e) {
39 return
40 }
41 // Limit to max block headers per message.
42 if count > MaxBlockHeadersPerMsg {
43 str := fmt.Sprintf(
44 "too many block headers for message "+
45 "[count %v, max %v]", count, MaxBlockHeadersPerMsg,
46 )
47 return messageError("MsgHeaders.BtcDecode", str)
48 }
49 // Create a contiguous slice of headers to deserialize into in order to reduce
50 // the number of allocations.
51 headers := make([]BlockHeader, count)
52 msg.Headers = make([]*BlockHeader, 0, count)
53 for i := uint64(0); i < count; i++ {
54 bh := &headers[i]
55 if e = readBlockHeader(r, pver, bh); E.Chk(e) {
56 return
57 }
58 txCount, e := ReadVarInt(r, pver)
59 if e != nil {
60 return e
61 }
62 // Ensure the transaction count is zero for headers.
63 if txCount > 0 {
64 str := fmt.Sprintf(
65 "block headers may not contain "+
66 "transactions [count %v]", txCount,
67 )
68 return messageError("MsgHeaders.BtcDecode", str)
69 }
70 if e = msg.AddBlockHeader(bh); E.Chk(e) {
71 }
72 }
73 return
74 }
75 76 // BtcEncode encodes the receiver to w using the bitcoin protocol encoding. This
77 // is part of the Message interface implementation.
78 func (msg *MsgHeaders) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) (e error) {
79 // Limit to max block headers per message.
80 count := len(msg.Headers)
81 if count > MaxBlockHeadersPerMsg {
82 str := fmt.Sprintf(
83 "too many block headers for message "+
84 "[count %v, max %v]", count, MaxBlockHeadersPerMsg,
85 )
86 return messageError("MsgHeaders.BtcEncode", str)
87 }
88 if e = WriteVarInt(w, pver, uint64(count)); E.Chk(e) {
89 return
90 }
91 for _, bh := range msg.Headers {
92 if e = writeBlockHeader(w, pver, bh); E.Chk(e) {
93 return
94 }
95 // The wire protocol encoding always includes a 0 for the number of transactions
96 // on header messages. This is really just an artifact of the way the original
97 // implementation serializes block headers, but it is required.
98 if e = WriteVarInt(w, pver, 0); E.Chk(e) {
99 return
100 }
101 }
102 return
103 }
104 105 // Command returns the protocol command string for the message. This is part of the Message interface implementation.
106 func (msg *MsgHeaders) Command() string {
107 return CmdHeaders
108 }
109 110 // MaxPayloadLength returns the maximum length the payload can be for the receiver. This is part of the Message
111 // interface implementation.
112 func (msg *MsgHeaders) MaxPayloadLength(pver uint32) uint32 {
113 // Num headers (varInt) + max allowed headers (header length + 1 byte for the number of transactions which is always
114 // 0).
115 return MaxVarIntPayload + ((MaxBlockHeaderPayload + 1) *
116 MaxBlockHeadersPerMsg)
117 }
118 119 // NewMsgHeaders returns a new bitcoin headers message that conforms to the Message interface. See MsgHeaders for
120 // details.
121 func NewMsgHeaders() *MsgHeaders {
122 return &MsgHeaders{
123 Headers: make([]*BlockHeader, 0, MaxBlockHeadersPerMsg),
124 }
125 }
126