msgcfilter.go raw

   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