1 package wire
2 3 import (
4 "fmt"
5 "io"
6 7 "github.com/p9c/p9/pkg/chainhash"
8 )
9 10 // FilterType is used to represent a filter type.
11 type FilterType uint8
12 13 const (
14 // GCSFilterRegular is the regular filter type.
15 GCSFilterRegular FilterType = iota
16 )
17 const (
18 // MaxCFilterDataSize is the maximum byte size of a committed filter. The
19 // maximum size is currently defined as 256KiB.
20 MaxCFilterDataSize = 256 * 1024
21 )
22 23 // MsgCFilter implements the Message interface and represents a bitcoin cfilter
24 // message. It is used to deliver a committed filter in response to a
25 // getcfilters (MsgGetCFilters) message.
26 type MsgCFilter struct {
27 FilterType FilterType
28 BlockHash chainhash.Hash
29 Data []byte
30 }
31 32 // BtcDecode decodes r using the bitcoin protocol encoding into the receiver.
33 // This is part of the Message interface implementation.
34 func (msg *MsgCFilter) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding) (e error) {
35 // Read filter type
36 if e = readElement(r, &msg.FilterType); E.Chk(e) {
37 return
38 }
39 // Read the hash of the filter's block
40 if e = readElement(r, &msg.BlockHash); E.Chk(e) {
41 return e
42 }
43 // Read filter data
44 msg.Data, e = ReadVarBytes(r, pver, MaxCFilterDataSize, "cfilter data")
45 return
46 }
47 48 // BtcEncode encodes the receiver to w using the bitcoin protocol encoding. This
49 // is part of the Message interface implementation.
50 func (msg *MsgCFilter) BtcEncode(w io.Writer, pver uint32, _ MessageEncoding) (e error) {
51 size := len(msg.Data)
52 if size > MaxCFilterDataSize {
53 str := fmt.Sprintf(
54 "cfilter size too large for message "+
55 "[size %v, max %v]", size, MaxCFilterDataSize,
56 )
57 return messageError("MsgCFilter.BtcEncode", str)
58 }
59 if e = writeElement(w, msg.FilterType); E.Chk(e) {
60 return
61 }
62 if e = writeElement(w, msg.BlockHash); E.Chk(e) {
63 return
64 }
65 return WriteVarBytes(w, pver, msg.Data)
66 }
67 68 // Deserialize decodes a filter from r into the receiver using a format that is
69 // suitable for long-term storage such as a database. This function differs from
70 // BtcDecode in that BtcDecode decodes from the bitcoin wire protocol as it was
71 // sent across the network. The wire encoding can technically differ depending
72 // on the protocol version and doesn't even really need to match the format of a
73 // stored filter at all. As of the time this comment was written, the encoded
74 // filter is the same in both instances, but there is a distinct difference and
75 // separating the two allows the API to be flexible enough to with changes.
76 func (msg *MsgCFilter) Deserialize(r io.Reader) (e error) {
77 // At the current time, there is no difference between the wire encoding and the
78 // stable long-term storage format. As a result, make use of BtcDecode.
79 return msg.BtcDecode(r, 0, BaseEncoding)
80 }
81 82 // Command returns the protocol command string for the message. This is part of
83 // the Message interface implementation.
84 func (msg *MsgCFilter) Command() string {
85 return CmdCFilter
86 }
87 88 // MaxPayloadLength returns the maximum length the payload can be for the
89 // receiver. This is part of the Message interface implementation.
90 func (msg *MsgCFilter) MaxPayloadLength(pver uint32) uint32 {
91 return uint32(VarIntSerializeSize(MaxCFilterDataSize)) + MaxCFilterDataSize + chainhash.HashSize + 1
92 }
93 94 // NewMsgCFilter returns a new bitcoin cfilter message that conforms to the
95 // Message interface. See MsgCFilter for details.
96 func NewMsgCFilter(
97 filterType FilterType, blockHash *chainhash.Hash,
98 data []byte,
99 ) *MsgCFilter {
100 return &MsgCFilter{
101 FilterType: filterType,
102 BlockHash: *blockHash,
103 Data: data,
104 }
105 }
106