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