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  }