msgcfheaders.go raw

   1  package wire
   2  
   3  import (
   4  	"fmt"
   5  	"io"
   6  	
   7  	"github.com/p9c/p9/pkg/chainhash"
   8  )
   9  
  10  const (
  11  	// MaxCFHeaderPayload is the maximum byte size of a committed filter header.
  12  	MaxCFHeaderPayload = chainhash.HashSize
  13  	// MaxCFHeadersPerMsg is the maximum number of committed filter headers that can be in a single bitcoin cfheaders message.
  14  	MaxCFHeadersPerMsg = 2000
  15  )
  16  
  17  // MsgCFHeaders implements the Message interface and represents a bitcoin cfheaders message. It is used to deliver
  18  // committed filter header information in response to a getcfheaders message (MsgGetCFHeaders). The maximum number of
  19  // committed filter headers per message is currently 2000. See MsgGetCFHeaders for details on requesting the headers.
  20  type MsgCFHeaders struct {
  21  	FilterType       FilterType
  22  	StopHash         chainhash.Hash
  23  	PrevFilterHeader chainhash.Hash
  24  	FilterHashes     []*chainhash.Hash
  25  }
  26  
  27  // AddCFHash adds a new filter hash to the message.
  28  func (msg *MsgCFHeaders) AddCFHash(hash *chainhash.Hash) (e error) {
  29  	if len(msg.FilterHashes)+1 > MaxCFHeadersPerMsg {
  30  		str := fmt.Sprintf(
  31  			"too many block headers in message [max %v]",
  32  			MaxBlockHeadersPerMsg,
  33  		)
  34  		return messageError("MsgCFHeaders.AddCFHash", str)
  35  	}
  36  	msg.FilterHashes = append(msg.FilterHashes, hash)
  37  	return nil
  38  }
  39  
  40  // BtcDecode decodes r using the bitcoin protocol encoding into the receiver. This is part of the Message interface
  41  // implementation.
  42  func (msg *MsgCFHeaders) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding) (e error) {
  43  	// Read filter type
  44  	if e = readElement(r, &msg.FilterType); E.Chk(e) {
  45  		return
  46  	}
  47  	// Read stop hash
  48  	if e = readElement(r, &msg.StopHash); E.Chk(e) {
  49  		return
  50  	}
  51  	// Read prev filter header
  52  	if e = readElement(r, &msg.PrevFilterHeader); E.Chk(e) {
  53  		return
  54  	}
  55  	// Read number of filter headers
  56  	var count uint64
  57  	if count, e = ReadVarInt(r, pver); E.Chk(e) {
  58  		return
  59  	}
  60  	// Limit to max committed filter headers per message.
  61  	if count > MaxCFHeadersPerMsg {
  62  		str := fmt.Sprintf(
  63  			"too many committed filter headers for "+
  64  				"message [count %v, max %v]", count,
  65  			MaxBlockHeadersPerMsg,
  66  		)
  67  		return messageError("MsgCFHeaders.BtcDecode", str)
  68  	}
  69  	// Create a contiguous slice of hashes to deserialize into in order to reduce the number of allocations.
  70  	msg.FilterHashes = make([]*chainhash.Hash, 0, count)
  71  	for i := uint64(0); i < count; i++ {
  72  		var cfh chainhash.Hash
  73  		if e = readElement(r, &cfh); E.Chk(e) {
  74  			return
  75  		}
  76  		if e = msg.AddCFHash(&cfh); E.Chk(e) {
  77  		}
  78  	}
  79  	return
  80  }
  81  
  82  // BtcEncode encodes the receiver to w using the bitcoin protocol encoding. This is part of the Message interface
  83  // implementation.
  84  func (msg *MsgCFHeaders) BtcEncode(w io.Writer, pver uint32, _ MessageEncoding) (e error) {
  85  	// Write filter type
  86  	if e = writeElement(w, msg.FilterType); E.Chk(e) {
  87  		return
  88  	}
  89  	// Write stop hash
  90  	if e = writeElement(w, msg.StopHash); E.Chk(e) {
  91  		return
  92  	}
  93  	// Write prev filter header
  94  	if e = writeElement(w, msg.PrevFilterHeader); E.Chk(e) {
  95  		return
  96  	}
  97  	// Limit to max committed headers per message.
  98  	count := len(msg.FilterHashes)
  99  	if count > MaxCFHeadersPerMsg {
 100  		str := fmt.Sprintf(
 101  			"too many committed filter headers for "+
 102  				"message [count %v, max %v]", count,
 103  			MaxBlockHeadersPerMsg,
 104  		)
 105  		return messageError("MsgCFHeaders.BtcEncode", str)
 106  	}
 107  	if e = WriteVarInt(w, pver, uint64(count)); E.Chk(e) {
 108  		return
 109  	}
 110  	for _, cfh := range msg.FilterHashes {
 111  		if e = writeElement(w, cfh); E.Chk(e) {
 112  			return
 113  		}
 114  	}
 115  	return
 116  }
 117  
 118  // Deserialize decodes a filter header from r into the receiver using a format that is suitable for long-term storage
 119  // such as a database. This function differs from BtcDecode in that BtcDecode decodes from the bitcoin wire protocol as
 120  // it was sent across the network. The wire encoding can technically differ depending on the protocol version and
 121  // doesn't even really need to match the format of a stored filter header at all. As of the time this comment was
 122  // written, the encoded filter header is the same in both instances, but there is a distinct difference and separating
 123  // the two allows the API to be flexible enough to deal with changes.
 124  func (msg *MsgCFHeaders) Deserialize(r io.Reader) (e error) {
 125  	// At the current time, there is no difference between the wire encoding and the stable long-term storage format. As
 126  	// a result, make use of BtcDecode.
 127  	return msg.BtcDecode(r, 0, BaseEncoding)
 128  }
 129  
 130  // Command returns the protocol command string for the message.  This is part of the Message interface implementation.
 131  func (msg *MsgCFHeaders) Command() string {
 132  	return CmdCFHeaders
 133  }
 134  
 135  // MaxPayloadLength returns the maximum length the payload can be for the receiver. This is part of the Message
 136  // interface implementation.
 137  func (msg *MsgCFHeaders) MaxPayloadLength(pver uint32) uint32 {
 138  	// Hash size + filter type + num headers (varInt) + (header size * max headers).
 139  	return 1 + chainhash.HashSize + chainhash.HashSize + MaxVarIntPayload +
 140  		(MaxCFHeaderPayload * MaxCFHeadersPerMsg)
 141  }
 142  
 143  // NewMsgCFHeaders returns a new bitcoin cfheaders message that conforms to the Message interface. See MsgCFHeaders for
 144  // details.
 145  func NewMsgCFHeaders() *MsgCFHeaders {
 146  	return &MsgCFHeaders{
 147  		FilterHashes: make([]*chainhash.Hash, 0, MaxCFHeadersPerMsg),
 148  	}
 149  }
 150