github.com/lbryio/lbcd@v0.22.119/wire/msgcfcheckpt.go (about) 1 // Copyright (c) 2018 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 "errors" 9 "fmt" 10 "io" 11 12 "github.com/lbryio/lbcd/chaincfg/chainhash" 13 ) 14 15 const ( 16 // CFCheckptInterval is the gap (in number of blocks) between each 17 // filter header checkpoint. 18 CFCheckptInterval = 1000 19 20 // maxCFHeadersLen is the max number of filter headers we will attempt 21 // to decode. 22 maxCFHeadersLen = 100000 23 ) 24 25 // ErrInsaneCFHeaderCount signals that we were asked to decode an 26 // unreasonable number of cfilter headers. 27 var ErrInsaneCFHeaderCount = errors.New( 28 "refusing to decode unreasonable number of filter headers") 29 30 // MsgCFCheckpt implements the Message interface and represents a bitcoin 31 // cfcheckpt message. It is used to deliver committed filter header information 32 // in response to a getcfcheckpt message (MsgGetCFCheckpt). See MsgGetCFCheckpt 33 // for details on requesting the headers. 34 type MsgCFCheckpt struct { 35 FilterType FilterType 36 StopHash chainhash.Hash 37 FilterHeaders []*chainhash.Hash 38 } 39 40 // AddCFHeader adds a new committed filter header to the message. 41 func (msg *MsgCFCheckpt) AddCFHeader(header *chainhash.Hash) error { 42 if len(msg.FilterHeaders) == cap(msg.FilterHeaders) { 43 str := fmt.Sprintf("FilterHeaders has insufficient capacity for "+ 44 "additional header: len = %d", len(msg.FilterHeaders)) 45 return messageError("MsgCFCheckpt.AddCFHeader", str) 46 } 47 48 msg.FilterHeaders = append(msg.FilterHeaders, header) 49 return nil 50 } 51 52 // BtcDecode decodes r using the bitcoin protocol encoding into the receiver. 53 // This is part of the Message interface implementation. 54 func (msg *MsgCFCheckpt) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding) error { 55 // Read filter type 56 err := readElement(r, &msg.FilterType) 57 if err != nil { 58 return err 59 } 60 61 // Read stop hash 62 err = readElement(r, &msg.StopHash) 63 if err != nil { 64 return err 65 } 66 67 // Read number of filter headers 68 count, err := ReadVarInt(r, pver) 69 if err != nil { 70 return err 71 } 72 73 // Refuse to decode an insane number of cfheaders. 74 if count > maxCFHeadersLen { 75 return ErrInsaneCFHeaderCount 76 } 77 78 // Create a contiguous slice of hashes to deserialize into in order to 79 // reduce the number of allocations. 80 msg.FilterHeaders = make([]*chainhash.Hash, count) 81 for i := uint64(0); i < count; i++ { 82 var cfh chainhash.Hash 83 err := readElement(r, &cfh) 84 if err != nil { 85 return err 86 } 87 msg.FilterHeaders[i] = &cfh 88 } 89 90 return nil 91 } 92 93 // BtcEncode encodes the receiver to w using the bitcoin protocol encoding. 94 // This is part of the Message interface implementation. 95 func (msg *MsgCFCheckpt) BtcEncode(w io.Writer, pver uint32, _ MessageEncoding) error { 96 // Write filter type 97 err := writeElement(w, msg.FilterType) 98 if err != nil { 99 return err 100 } 101 102 // Write stop hash 103 err = writeElement(w, msg.StopHash) 104 if err != nil { 105 return err 106 } 107 108 // Write length of FilterHeaders slice 109 count := len(msg.FilterHeaders) 110 err = WriteVarInt(w, pver, uint64(count)) 111 if err != nil { 112 return err 113 } 114 115 for _, cfh := range msg.FilterHeaders { 116 err := writeElement(w, cfh) 117 if err != nil { 118 return err 119 } 120 } 121 122 return nil 123 } 124 125 // Deserialize decodes a filter header from r into the receiver using a format 126 // that is suitable for long-term storage such as a database. This function 127 // differs from BtcDecode in that BtcDecode decodes from the bitcoin wire 128 // protocol as it was sent across the network. The wire encoding can 129 // technically differ depending on the protocol version and doesn't even really 130 // need to match the format of a stored filter header at all. As of the time 131 // this comment was written, the encoded filter header is the same in both 132 // instances, but there is a distinct difference and separating the two allows 133 // the API to be flexible enough to deal with changes. 134 func (msg *MsgCFCheckpt) Deserialize(r io.Reader) error { 135 // At the current time, there is no difference between the wire encoding 136 // and the stable long-term storage format. As a result, make use of 137 // BtcDecode. 138 return msg.BtcDecode(r, 0, BaseEncoding) 139 } 140 141 // Command returns the protocol command string for the message. This is part 142 // of the Message interface implementation. 143 func (msg *MsgCFCheckpt) Command() string { 144 return CmdCFCheckpt 145 } 146 147 // MaxPayloadLength returns the maximum length the payload can be for the 148 // receiver. This is part of the Message interface implementation. 149 func (msg *MsgCFCheckpt) MaxPayloadLength(pver uint32) uint32 { 150 // Message size depends on the blockchain height, so return general limit 151 // for all messages. 152 return MaxMessagePayload 153 } 154 155 // NewMsgCFCheckpt returns a new bitcoin cfheaders message that conforms to 156 // the Message interface. See MsgCFCheckpt for details. 157 func NewMsgCFCheckpt(filterType FilterType, stopHash *chainhash.Hash, 158 headersCount int) *MsgCFCheckpt { 159 return &MsgCFCheckpt{ 160 FilterType: filterType, 161 StopHash: *stopHash, 162 FilterHeaders: make([]*chainhash.Hash, 0, headersCount), 163 } 164 }