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  }