multi: Modify CFHeaders message to have a PrevFilterHeader field.

This commit is contained in:
Jim Posen 2018-01-19 13:06:39 -08:00 committed by Olaoluwa Osuntokun
parent 7a53a05878
commit 175af18043
3 changed files with 75 additions and 16 deletions

View file

@ -788,13 +788,28 @@ func (sp *serverPeer) OnGetCFHeaders(_ *peer.Peer, msg *wire.MsgGetCFHeaders) {
return return
} }
startHeight := int32(msg.StartHeight)
maxResults := wire.MaxCFHeadersPerMsg
// If StartHeight is positive, fetch the predecessor block hash so we can
// populate the PrevFilterHeader field.
if msg.StartHeight > 0 {
startHeight--
maxResults++
}
// Fetch the hashes from the block index. // Fetch the hashes from the block index.
hashList, err := sp.server.chain.HeightToHashRange(int32(msg.StartHeight), hashList, err := sp.server.chain.HeightToHashRange(startHeight,
&msg.StopHash, wire.MaxCFHeadersPerMsg) &msg.StopHash, maxResults)
if err != nil { if err != nil {
peerLog.Debugf("Invalid getcfheaders request: %v", err) peerLog.Debugf("Invalid getcfheaders request: %v", err)
} }
if len(hashList) == 0 {
// This is possible if StartHeight is one greater that the height of
// StopHash, and we pull a valid range of hashes including the previous
// filter header.
if len(hashList) == 0 || (msg.StartHeight > 0 && len(hashList) == 1) {
peerLog.Debug("No results for getcfheaders request")
return return
} }
@ -815,6 +830,37 @@ func (sp *serverPeer) OnGetCFHeaders(_ *peer.Peer, msg *wire.MsgGetCFHeaders) {
// Generate cfheaders message and send it. // Generate cfheaders message and send it.
headersMsg := wire.NewMsgCFHeaders() headersMsg := wire.NewMsgCFHeaders()
// Populate the PrevFilterHeader field.
if msg.StartHeight > 0 {
prevBlockHash := &hashList[0]
// Fetch the raw committed filter header bytes from the
// database.
headerBytes, err := sp.server.cfIndex.FilterHeaderByBlockHash(
prevBlockHash, msg.FilterType)
if err != nil {
peerLog.Errorf("Error retrieving CF header: %v", err)
return
}
if len(headerBytes) == 0 {
peerLog.Warnf("Could not obtain CF header for %v", prevBlockHash)
return
}
// Deserialize the hash into PrevFilterHeader.
err = headersMsg.PrevFilterHeader.SetBytes(headerBytes)
if err != nil {
peerLog.Warnf("Committed filter header deserialize "+
"failed: %v", err)
return
}
hashList = hashList[1:]
filterHeaders = filterHeaders[1:]
}
// Populate HeaderHashes.
for i, headerBytes := range filterHeaders { for i, headerBytes := range filterHeaders {
if len(headerBytes) == 0 { if len(headerBytes) == 0 {
peerLog.Warnf("Could not obtain CF header for %v", hashList[i]) peerLog.Warnf("Could not obtain CF header for %v", hashList[i])

View file

@ -106,7 +106,7 @@ func TestMessage(t *testing.T) {
{msgGetCFilters, msgGetCFilters, pver, MainNet, 61}, {msgGetCFilters, msgGetCFilters, pver, MainNet, 61},
{msgGetCFHeaders, msgGetCFHeaders, pver, MainNet, 61}, {msgGetCFHeaders, msgGetCFHeaders, pver, MainNet, 61},
{msgCFilter, msgCFilter, pver, MainNet, 65}, {msgCFilter, msgCFilter, pver, MainNet, 65},
{msgCFHeaders, msgCFHeaders, pver, MainNet, 58}, {msgCFHeaders, msgCFHeaders, pver, MainNet, 90},
} }
t.Logf("Running %d tests", len(tests)) t.Logf("Running %d tests", len(tests))

View file

@ -27,9 +27,10 @@ const (
// of committed filter headers per message is currently 2000. See // of committed filter headers per message is currently 2000. See
// MsgGetCFHeaders for details on requesting the headers. // MsgGetCFHeaders for details on requesting the headers.
type MsgCFHeaders struct { type MsgCFHeaders struct {
StopHash chainhash.Hash FilterType FilterType
FilterType FilterType StopHash chainhash.Hash
HeaderHashes []*chainhash.Hash PrevFilterHeader chainhash.Hash
HeaderHashes []*chainhash.Hash
} }
// AddCFHeader adds a new committed filter header to the message. // AddCFHeader adds a new committed filter header to the message.
@ -47,14 +48,20 @@ func (msg *MsgCFHeaders) AddCFHeader(headerHash *chainhash.Hash) error {
// BtcDecode decodes r using the bitcoin protocol encoding into the receiver. // BtcDecode decodes r using the bitcoin protocol encoding into the receiver.
// This is part of the Message interface implementation. // This is part of the Message interface implementation.
func (msg *MsgCFHeaders) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding) error { func (msg *MsgCFHeaders) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding) error {
// Read stop hash // Read filter type
err := readElement(r, &msg.StopHash) err := readElement(r, &msg.FilterType)
if err != nil { if err != nil {
return err return err
} }
// Read filter type // Read stop hash
err = readElement(r, &msg.FilterType) err = readElement(r, &msg.StopHash)
if err != nil {
return err
}
// Read prev filter header
err = readElement(r, &msg.PrevFilterHeader)
if err != nil { if err != nil {
return err return err
} }
@ -91,14 +98,20 @@ func (msg *MsgCFHeaders) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding)
// BtcEncode encodes the receiver to w using the bitcoin protocol encoding. // BtcEncode encodes the receiver to w using the bitcoin protocol encoding.
// This is part of the Message interface implementation. // This is part of the Message interface implementation.
func (msg *MsgCFHeaders) BtcEncode(w io.Writer, pver uint32, _ MessageEncoding) error { func (msg *MsgCFHeaders) BtcEncode(w io.Writer, pver uint32, _ MessageEncoding) error {
// Write stop hash // Write filter type
err := writeElement(w, msg.StopHash) err := writeElement(w, msg.FilterType)
if err != nil { if err != nil {
return err return err
} }
// Write filter type // Write stop hash
err = writeElement(w, msg.FilterType) err = writeElement(w, msg.StopHash)
if err != nil {
return err
}
// Write prev filter header
err = writeElement(w, msg.PrevFilterHeader)
if err != nil { if err != nil {
return err return err
} }
@ -154,7 +167,7 @@ func (msg *MsgCFHeaders) Command() string {
func (msg *MsgCFHeaders) MaxPayloadLength(pver uint32) uint32 { func (msg *MsgCFHeaders) MaxPayloadLength(pver uint32) uint32 {
// Hash size + filter type + num headers (varInt) + // Hash size + filter type + num headers (varInt) +
// (header size * max headers). // (header size * max headers).
return chainhash.HashSize + 1 + MaxVarIntPayload + return 1 + chainhash.HashSize + chainhash.HashSize + MaxVarIntPayload +
(MaxCFHeaderPayload * MaxCFHeadersPerMsg) (MaxCFHeaderPayload * MaxCFHeadersPerMsg)
} }