multi: Redefine GetCFilters to have StartHeight and StopHash.

This commit is contained in:
Jim Posen 2018-01-18 19:10:42 -08:00 committed by Olaoluwa Osuntokun
parent 3425d33506
commit daac60675e
8 changed files with 152 additions and 106 deletions

View file

@ -151,9 +151,9 @@ type MessageListeners struct {
// message.
OnGetHeaders func(p *Peer, msg *wire.MsgGetHeaders)
// OnGetCFilter is invoked when a peer receives a getcfilter bitcoin
// OnGetCFilters is invoked when a peer receives a getcfilters bitcoin
// message.
OnGetCFilter func(p *Peer, msg *wire.MsgGetCFilter)
OnGetCFilters func(p *Peer, msg *wire.MsgGetCFilters)
// OnGetCFHeaders is invoked when a peer receives a getcfheaders
// bitcoin message.
@ -1591,9 +1591,9 @@ out:
p.cfg.Listeners.OnGetHeaders(p, msg)
}
case *wire.MsgGetCFilter:
if p.cfg.Listeners.OnGetCFilter != nil {
p.cfg.Listeners.OnGetCFilter(p, msg)
case *wire.MsgGetCFilters:
if p.cfg.Listeners.OnGetCFilters != nil {
p.cfg.Listeners.OnGetCFilters(p, msg)
}
case *wire.MsgGetCFHeaders:

View file

@ -399,7 +399,7 @@ func TestPeerListeners(t *testing.T) {
OnGetHeaders: func(p *peer.Peer, msg *wire.MsgGetHeaders) {
ok <- msg
},
OnGetCFilter: func(p *peer.Peer, msg *wire.MsgGetCFilter) {
OnGetCFilters: func(p *peer.Peer, msg *wire.MsgGetCFilters) {
ok <- msg
},
OnGetCFHeaders: func(p *peer.Peer, msg *wire.MsgGetCFHeaders) {
@ -535,9 +535,8 @@ func TestPeerListeners(t *testing.T) {
wire.NewMsgGetHeaders(),
},
{
"OnGetCFilter",
wire.NewMsgGetCFilter(&chainhash.Hash{},
wire.GCSFilterRegular),
"OnGetCFilters",
wire.NewMsgGetCFilters(wire.GCSFilterRegular, 0, &chainhash.Hash{}),
},
{
"OnGetCFHeaders",
@ -545,8 +544,8 @@ func TestPeerListeners(t *testing.T) {
},
{
"OnCFilter",
wire.NewMsgCFilter(&chainhash.Hash{},
wire.GCSFilterRegular, []byte("payload")),
wire.NewMsgCFilter(wire.GCSFilterRegular, &chainhash.Hash{},
[]byte("payload")),
},
{
"OnCFHeaders",

View file

@ -743,26 +743,42 @@ func (sp *serverPeer) OnGetHeaders(_ *peer.Peer, msg *wire.MsgGetHeaders) {
sp.QueueMessage(&wire.MsgHeaders{Headers: blockHeaders}, nil)
}
// OnGetCFilter is invoked when a peer receives a getcfilter bitcoin message.
func (sp *serverPeer) OnGetCFilter(_ *peer.Peer, msg *wire.MsgGetCFilter) {
// Ignore getcfilter requests if not in sync.
// OnGetCFilters is invoked when a peer receives a getcfilters bitcoin message.
func (sp *serverPeer) OnGetCFilters(_ *peer.Peer, msg *wire.MsgGetCFilters) {
// Ignore getcfilters requests if not in sync.
if !sp.server.syncManager.IsCurrent() {
return
}
filterBytes, err := sp.server.cfIndex.FilterByBlockHash(&msg.BlockHash,
msg.FilterType)
if len(filterBytes) > 0 {
peerLog.Tracef("Obtained CF for %v", msg.BlockHash)
} else {
peerLog.Warnf("Could not obtain CF for %v: %v", msg.BlockHash,
err)
hashes, err := sp.server.chain.HeightToHashRange(int32(msg.StartHeight),
&msg.StopHash, wire.MaxGetCFiltersReqRange)
if err != nil {
peerLog.Debugf("Invalid getcfilters request: %v", err)
return
}
filterMsg := wire.NewMsgCFilter(&msg.BlockHash, msg.FilterType,
filterBytes)
sp.QueueMessage(filterMsg, nil)
// Create []*chainhash.Hash from []chainhash.Hash to pass to
// FiltersByBlockHashes.
hashPtrs := make([]*chainhash.Hash, len(hashes))
for i := range hashes {
hashPtrs[i] = &hashes[i]
}
filters, err := sp.server.cfIndex.FiltersByBlockHashes(hashPtrs,
msg.FilterType)
if err != nil {
peerLog.Errorf("Error retrieving cfilters: %v", err)
return
}
for i, filterBytes := range filters {
if len(filterBytes) == 0 {
peerLog.Warnf("Could not obtain cfilter for %v", hashes[i])
return
}
filterMsg := wire.NewMsgCFilter(msg.FilterType, &hashes[i], filterBytes)
sp.QueueMessage(filterMsg, nil)
}
}
// OnGetCFHeaders is invoked when a peer receives a getcfheader bitcoin message.
@ -1724,7 +1740,7 @@ func newPeerConfig(sp *serverPeer) *peer.Config {
OnGetData: sp.OnGetData,
OnGetBlocks: sp.OnGetBlocks,
OnGetHeaders: sp.OnGetHeaders,
OnGetCFilter: sp.OnGetCFilter,
OnGetCFilters: sp.OnGetCFilters,
OnGetCFHeaders: sp.OnGetCFHeaders,
OnFeeFilter: sp.OnFeeFilter,
OnFilterAdd: sp.OnFilterAdd,

View file

@ -51,7 +51,7 @@ const (
CmdReject = "reject"
CmdSendHeaders = "sendheaders"
CmdFeeFilter = "feefilter"
CmdGetCFilter = "getcfilter"
CmdGetCFilters = "getcfilters"
CmdGetCFHeaders = "getcfheaders"
CmdCFilter = "cfilter"
CmdCFHeaders = "cfheaders"
@ -160,8 +160,8 @@ func makeEmptyMessage(command string) (Message, error) {
case CmdFeeFilter:
msg = &MsgFeeFilter{}
case CmdGetCFilter:
msg = &MsgGetCFilter{}
case CmdGetCFilters:
msg = &MsgGetCFilters{}
case CmdGetCFHeaders:
msg = &MsgGetCFHeaders{}

View file

@ -69,9 +69,9 @@ func TestMessage(t *testing.T) {
bh := NewBlockHeader(1, &chainhash.Hash{}, &chainhash.Hash{}, 0, 0)
msgMerkleBlock := NewMsgMerkleBlock(bh)
msgReject := NewMsgReject("block", RejectDuplicate, "duplicate block")
msgGetCFilter := NewMsgGetCFilter(&chainhash.Hash{}, GCSFilterExtended)
msgGetCFilters := NewMsgGetCFilters(GCSFilterExtended, 0, &chainhash.Hash{})
msgGetCFHeaders := NewMsgGetCFHeaders()
msgCFilter := NewMsgCFilter(&chainhash.Hash{}, GCSFilterExtended,
msgCFilter := NewMsgCFilter(GCSFilterExtended, &chainhash.Hash{},
[]byte("payload"))
msgCFHeaders := NewMsgCFHeaders()
@ -103,7 +103,7 @@ func TestMessage(t *testing.T) {
{msgFilterLoad, msgFilterLoad, pver, MainNet, 35},
{msgMerkleBlock, msgMerkleBlock, pver, MainNet, 110},
{msgReject, msgReject, pver, MainNet, 79},
{msgGetCFilter, msgGetCFilter, pver, MainNet, 57},
{msgGetCFilters, msgGetCFilters, pver, MainNet, 61},
{msgGetCFHeaders, msgGetCFHeaders, pver, MainNet, 58},
{msgCFilter, msgCFilter, pver, MainNet, 65},
{msgCFHeaders, msgCFHeaders, pver, MainNet, 58},

View file

@ -30,26 +30,28 @@ const (
// MsgCFilter implements the Message interface and represents a bitcoin cfilter
// message. It is used to deliver a committed filter in response to a
// getcfilter (MsgGetCFilter) message.
// getcfilters (MsgGetCFilters) message.
type MsgCFilter struct {
BlockHash chainhash.Hash
FilterType FilterType
BlockHash chainhash.Hash
Data []byte
}
// BtcDecode decodes r using the bitcoin protocol encoding into the receiver.
// This is part of the Message interface implementation.
func (msg *MsgCFilter) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding) error {
// Read the hash of the filter's block
err := readElement(r, &msg.BlockHash)
if err != nil {
return err
}
// Read filter type
err = readElement(r, &msg.FilterType)
err := readElement(r, &msg.FilterType)
if err != nil {
return err
}
// Read the hash of the filter's block
err = readElement(r, &msg.BlockHash)
if err != nil {
return err
}
// Read filter data
msg.Data, err = ReadVarBytes(r, pver, MaxCFilterDataSize,
"cfilter data")
@ -66,12 +68,12 @@ func (msg *MsgCFilter) BtcEncode(w io.Writer, pver uint32, _ MessageEncoding) er
return messageError("MsgCFilter.BtcEncode", str)
}
err := writeElement(w, msg.BlockHash)
err := writeElement(w, msg.FilterType)
if err != nil {
return err
}
err = writeElement(w, msg.FilterType)
err = writeElement(w, msg.BlockHash)
if err != nil {
return err
}
@ -110,11 +112,11 @@ func (msg *MsgCFilter) MaxPayloadLength(pver uint32) uint32 {
// NewMsgCFilter returns a new bitcoin cfilter message that conforms to the
// Message interface. See MsgCFilter for details.
func NewMsgCFilter(blockHash *chainhash.Hash, filterType FilterType,
func NewMsgCFilter(filterType FilterType, blockHash *chainhash.Hash,
data []byte) *MsgCFilter {
return &MsgCFilter{
BlockHash: *blockHash,
FilterType: filterType,
BlockHash: *blockHash,
Data: data,
}
}

View file

@ -1,62 +0,0 @@
// Copyright (c) 2017 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package wire
import (
"io"
"github.com/btcsuite/btcd/chaincfg/chainhash"
)
// MsgGetCFilter implements the Message interface and represents a bitcoin
// getcfilter message. It is used to request a committed filter for a block.
type MsgGetCFilter struct {
BlockHash chainhash.Hash
FilterType FilterType
}
// BtcDecode decodes r using the bitcoin protocol encoding into the receiver.
// This is part of the Message interface implementation.
func (msg *MsgGetCFilter) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding) error {
err := readElement(r, &msg.BlockHash)
if err != nil {
return err
}
return readElement(r, &msg.FilterType)
}
// BtcEncode encodes the receiver to w using the bitcoin protocol encoding.
// This is part of the Message interface implementation.
func (msg *MsgGetCFilter) BtcEncode(w io.Writer, pver uint32, _ MessageEncoding) error {
err := writeElement(w, &msg.BlockHash)
if err != nil {
return err
}
return writeElement(w, msg.FilterType)
}
// Command returns the protocol command string for the message. This is part
// of the Message interface implementation.
func (msg *MsgGetCFilter) Command() string {
return CmdGetCFilter
}
// MaxPayloadLength returns the maximum length the payload can be for the
// receiver. This is part of the Message interface implementation.
func (msg *MsgGetCFilter) MaxPayloadLength(pver uint32) uint32 {
// Block hash + filter type.
return chainhash.HashSize + 1
}
// NewMsgGetCFilter returns a new bitcoin getcfilter message that conforms to
// the Message interface using the passed parameters and defaults for the
// remaining fields.
func NewMsgGetCFilter(blockHash *chainhash.Hash,
filterType FilterType) *MsgGetCFilter {
return &MsgGetCFilter{
BlockHash: *blockHash,
FilterType: filterType,
}
}

91
wire/msggetcfilters.go Normal file
View file

@ -0,0 +1,91 @@
// Copyright (c) 2017 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package wire
import (
"io"
"github.com/roasbeef/btcd/chaincfg/chainhash"
)
// MaxGetCFiltersReqRange the maximum number of filters that may be requested in
// a getcfheaders message.
const MaxGetCFiltersReqRange = 100
// MsgGetCFilters implements the Message interface and represents a bitcoin
// getcfilters message. It is used to request committed filters for a range of
// blocks.
type MsgGetCFilters struct {
FilterType FilterType
StartHeight uint32
StopHash chainhash.Hash
}
// BtcDecode decodes r using the bitcoin protocol encoding into the receiver.
// This is part of the Message interface implementation.
func (msg *MsgGetCFilters) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding) error {
err := readElement(r, &msg.FilterType)
if err != nil {
return err
}
err = readElement(r, &msg.StartHeight)
if err != nil {
return err
}
err = readElement(r, &msg.StopHash)
if err != nil {
return err
}
return nil
}
// BtcEncode encodes the receiver to w using the bitcoin protocol encoding.
// This is part of the Message interface implementation.
func (msg *MsgGetCFilters) BtcEncode(w io.Writer, pver uint32, _ MessageEncoding) error {
err := writeElement(w, msg.FilterType)
if err != nil {
return err
}
err = writeElement(w, &msg.StartHeight)
if err != nil {
return err
}
err = writeElement(w, &msg.StopHash)
if err != nil {
return err
}
return nil
}
// Command returns the protocol command string for the message. This is part
// of the Message interface implementation.
func (msg *MsgGetCFilters) Command() string {
return CmdGetCFilters
}
// MaxPayloadLength returns the maximum length the payload can be for the
// receiver. This is part of the Message interface implementation.
func (msg *MsgGetCFilters) MaxPayloadLength(pver uint32) uint32 {
// Filter type + uint32 + block hash
return 1 + 4 + chainhash.HashSize
}
// NewMsgGetCFilters returns a new bitcoin getcfilters message that conforms to
// the Message interface using the passed parameters and defaults for the
// remaining fields.
func NewMsgGetCFilters(filterType FilterType, startHeight uint32,
stopHash *chainhash.Hash) *MsgGetCFilters {
return &MsgGetCFilters{
FilterType: filterType,
StartHeight: startHeight,
StopHash: *stopHash,
}
}