github.com/lbryio/lbcd@v0.22.119/wire/msgcfheaders.go (about) 1 // Copyright (c) 2017 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/lbryio/lbcd/chaincfg/chainhash" 12 ) 13 14 const ( 15 // MaxCFHeaderPayload is the maximum byte size of a committed 16 // filter header. 17 MaxCFHeaderPayload = chainhash.HashSize 18 19 // MaxCFHeadersPerMsg is the maximum number of committed filter headers 20 // that can be in a single bitcoin cfheaders message. 21 MaxCFHeadersPerMsg = 2000 22 ) 23 24 // MsgCFHeaders implements the Message interface and represents a bitcoin 25 // cfheaders message. It is used to deliver committed filter header information 26 // in response to a getcfheaders message (MsgGetCFHeaders). The maximum number 27 // of committed filter headers per message is currently 2000. See 28 // MsgGetCFHeaders for details on requesting the headers. 29 type MsgCFHeaders struct { 30 FilterType FilterType 31 StopHash chainhash.Hash 32 PrevFilterHeader chainhash.Hash 33 FilterHashes []*chainhash.Hash 34 } 35 36 // AddCFHash adds a new filter hash to the message. 37 func (msg *MsgCFHeaders) AddCFHash(hash *chainhash.Hash) error { 38 if len(msg.FilterHashes)+1 > MaxCFHeadersPerMsg { 39 str := fmt.Sprintf("too many block headers in message [max %v]", 40 MaxBlockHeadersPerMsg) 41 return messageError("MsgCFHeaders.AddCFHash", str) 42 } 43 44 msg.FilterHashes = append(msg.FilterHashes, hash) 45 return nil 46 } 47 48 // BtcDecode decodes r using the bitcoin protocol encoding into the receiver. 49 // This is part of the Message interface implementation. 50 func (msg *MsgCFHeaders) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding) error { 51 // Read filter type 52 err := readElement(r, &msg.FilterType) 53 if err != nil { 54 return err 55 } 56 57 // Read stop hash 58 err = readElement(r, &msg.StopHash) 59 if err != nil { 60 return err 61 } 62 63 // Read prev filter header 64 err = readElement(r, &msg.PrevFilterHeader) 65 if err != nil { 66 return err 67 } 68 69 // Read number of filter headers 70 count, err := ReadVarInt(r, pver) 71 if err != nil { 72 return err 73 } 74 75 // Limit to max committed filter headers per message. 76 if count > MaxCFHeadersPerMsg { 77 str := fmt.Sprintf("too many committed filter headers for "+ 78 "message [count %v, max %v]", count, 79 MaxBlockHeadersPerMsg) 80 return messageError("MsgCFHeaders.BtcDecode", str) 81 } 82 83 // Create a contiguous slice of hashes to deserialize into in order to 84 // reduce the number of allocations. 85 msg.FilterHashes = make([]*chainhash.Hash, 0, count) 86 for i := uint64(0); i < count; i++ { 87 var cfh chainhash.Hash 88 err := readElement(r, &cfh) 89 if err != nil { 90 return err 91 } 92 msg.AddCFHash(&cfh) 93 } 94 95 return nil 96 } 97 98 // BtcEncode encodes the receiver to w using the bitcoin protocol encoding. 99 // This is part of the Message interface implementation. 100 func (msg *MsgCFHeaders) BtcEncode(w io.Writer, pver uint32, _ MessageEncoding) error { 101 // Write filter type 102 err := writeElement(w, msg.FilterType) 103 if err != nil { 104 return err 105 } 106 107 // Write stop hash 108 err = writeElement(w, msg.StopHash) 109 if err != nil { 110 return err 111 } 112 113 // Write prev filter header 114 err = writeElement(w, msg.PrevFilterHeader) 115 if err != nil { 116 return err 117 } 118 119 // Limit to max committed headers per message. 120 count := len(msg.FilterHashes) 121 if count > MaxCFHeadersPerMsg { 122 str := fmt.Sprintf("too many committed filter headers for "+ 123 "message [count %v, max %v]", count, 124 MaxBlockHeadersPerMsg) 125 return messageError("MsgCFHeaders.BtcEncode", str) 126 } 127 128 err = WriteVarInt(w, pver, uint64(count)) 129 if err != nil { 130 return err 131 } 132 133 for _, cfh := range msg.FilterHashes { 134 err := writeElement(w, cfh) 135 if err != nil { 136 return err 137 } 138 } 139 140 return nil 141 } 142 143 // Deserialize decodes a filter header from r into the receiver using a format 144 // that is suitable for long-term storage such as a database. This function 145 // differs from BtcDecode in that BtcDecode decodes from the bitcoin wire 146 // protocol as it was sent across the network. The wire encoding can 147 // technically differ depending on the protocol version and doesn't even really 148 // need to match the format of a stored filter header at all. As of the time 149 // this comment was written, the encoded filter header is the same in both 150 // instances, but there is a distinct difference and separating the two allows 151 // the API to be flexible enough to deal with changes. 152 func (msg *MsgCFHeaders) Deserialize(r io.Reader) error { 153 // At the current time, there is no difference between the wire encoding 154 // and the stable long-term storage format. As a result, make use of 155 // BtcDecode. 156 return msg.BtcDecode(r, 0, BaseEncoding) 157 } 158 159 // Command returns the protocol command string for the message. This is part 160 // of the Message interface implementation. 161 func (msg *MsgCFHeaders) Command() string { 162 return CmdCFHeaders 163 } 164 165 // MaxPayloadLength returns the maximum length the payload can be for the 166 // receiver. This is part of the Message interface implementation. 167 func (msg *MsgCFHeaders) MaxPayloadLength(pver uint32) uint32 { 168 // Hash size + filter type + num headers (varInt) + 169 // (header size * max headers). 170 return 1 + chainhash.HashSize + chainhash.HashSize + MaxVarIntPayload + 171 (MaxCFHeaderPayload * MaxCFHeadersPerMsg) 172 } 173 174 // NewMsgCFHeaders returns a new bitcoin cfheaders message that conforms to 175 // the Message interface. See MsgCFHeaders for details. 176 func NewMsgCFHeaders() *MsgCFHeaders { 177 return &MsgCFHeaders{ 178 FilterHashes: make([]*chainhash.Hash, 0, MaxCFHeadersPerMsg), 179 } 180 }