multi: Redefine GetCFHeaders to have StartHeight and StopHash.
This commit is contained in:
parent
daac60675e
commit
7a53a05878
4 changed files with 55 additions and 147 deletions
|
@ -540,7 +540,7 @@ func TestPeerListeners(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"OnGetCFHeaders",
|
"OnGetCFHeaders",
|
||||||
wire.NewMsgGetCFHeaders(),
|
wire.NewMsgGetCFHeaders(wire.GCSFilterRegular, 0, &chainhash.Hash{}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"OnCFilter",
|
"OnCFilter",
|
||||||
|
|
99
server.go
99
server.go
|
@ -788,91 +788,36 @@ func (sp *serverPeer) OnGetCFHeaders(_ *peer.Peer, msg *wire.MsgGetCFHeaders) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attempt to look up the height of the provided stop hash.
|
// Fetch the hashes from the block index.
|
||||||
chain := sp.server.chain
|
hashList, err := sp.server.chain.HeightToHashRange(int32(msg.StartHeight),
|
||||||
endIdx := int32(math.MaxInt32)
|
&msg.StopHash, wire.MaxCFHeadersPerMsg)
|
||||||
height, err := chain.BlockHeightByHash(&msg.HashStop)
|
|
||||||
if err == nil {
|
|
||||||
endIdx = height + 1
|
|
||||||
}
|
|
||||||
|
|
||||||
// There are no block locators so a specific header is being requested
|
|
||||||
// as identified by the stop hash.
|
|
||||||
if len(msg.BlockLocatorHashes) == 0 {
|
|
||||||
// No blocks with the stop hash were found so there is nothing
|
|
||||||
// to do. Just return. This behavior mirrors the reference
|
|
||||||
// implementation.
|
|
||||||
if endIdx == math.MaxInt32 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch the raw committed filter header bytes from the
|
|
||||||
// database.
|
|
||||||
headerBytes, err := sp.server.cfIndex.FilterHeaderByBlockHash(
|
|
||||||
&msg.HashStop, msg.FilterType)
|
|
||||||
if (err != nil) || (len(headerBytes) == 0) {
|
|
||||||
peerLog.Warnf("Could not obtain CF header for %v: %v",
|
|
||||||
msg.HashStop, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deserialize the hash.
|
|
||||||
var header chainhash.Hash
|
|
||||||
err = header.SetBytes(headerBytes)
|
|
||||||
if err != nil {
|
|
||||||
peerLog.Warnf("Committed filter header deserialize "+
|
|
||||||
"failed: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
headersMsg := wire.NewMsgCFHeaders()
|
|
||||||
headersMsg.AddCFHeader(&header)
|
|
||||||
headersMsg.StopHash = msg.HashStop
|
|
||||||
headersMsg.FilterType = msg.FilterType
|
|
||||||
sp.QueueMessage(headersMsg, nil)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the most recent known block based on the block locator.
|
|
||||||
// Use the block after the genesis block if no other blocks in the
|
|
||||||
// provided locator are known. This does mean the client will start
|
|
||||||
// over with the genesis block if unknown block locators are provided.
|
|
||||||
// This mirrors the behavior in the reference implementation.
|
|
||||||
startIdx := int32(1)
|
|
||||||
for _, hash := range msg.BlockLocatorHashes {
|
|
||||||
height, err := chain.BlockHeightByHash(hash)
|
|
||||||
if err == nil {
|
|
||||||
// Start with the next hash since we know this one.
|
|
||||||
startIdx = height + 1
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't attempt to fetch more than we can put into a single message.
|
|
||||||
if endIdx-startIdx > wire.MaxBlockHeadersPerMsg {
|
|
||||||
endIdx = startIdx + wire.MaxBlockHeadersPerMsg
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch the inventory from the block database.
|
|
||||||
hashList, err := chain.HeightRange(startIdx, endIdx)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
peerLog.Warnf("Header lookup failed: %v", err)
|
peerLog.Debugf("Invalid getcfheaders request: %v", err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
if len(hashList) == 0 {
|
if len(hashList) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create []*chainhash.Hash from []chainhash.Hash to pass to
|
||||||
|
// FilterHeadersByBlockHashes.
|
||||||
|
hashPtrs := make([]*chainhash.Hash, len(hashList))
|
||||||
|
for i := range hashList {
|
||||||
|
hashPtrs[i] = &hashList[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch the raw filter header bytes from the database for all blocks.
|
||||||
|
filterHeaders, err := sp.server.cfIndex.FilterHeadersByBlockHashes(hashPtrs,
|
||||||
|
msg.FilterType)
|
||||||
|
if err != nil {
|
||||||
|
peerLog.Errorf("Error retrieving cfilters: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Generate cfheaders message and send it.
|
// Generate cfheaders message and send it.
|
||||||
headersMsg := wire.NewMsgCFHeaders()
|
headersMsg := wire.NewMsgCFHeaders()
|
||||||
for i := range hashList {
|
for i, headerBytes := range filterHeaders {
|
||||||
// Fetch the raw committed filter header bytes from the
|
if len(headerBytes) == 0 {
|
||||||
// database.
|
peerLog.Warnf("Could not obtain CF header for %v", hashList[i])
|
||||||
headerBytes, err := sp.server.cfIndex.FilterHeaderByBlockHash(
|
|
||||||
&hashList[i], msg.FilterType)
|
|
||||||
if (err != nil) || (len(headerBytes) == 0) {
|
|
||||||
peerLog.Warnf("Could not obtain CF header for %v: %v",
|
|
||||||
hashList[i], err)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -70,7 +70,7 @@ func TestMessage(t *testing.T) {
|
||||||
msgMerkleBlock := NewMsgMerkleBlock(bh)
|
msgMerkleBlock := NewMsgMerkleBlock(bh)
|
||||||
msgReject := NewMsgReject("block", RejectDuplicate, "duplicate block")
|
msgReject := NewMsgReject("block", RejectDuplicate, "duplicate block")
|
||||||
msgGetCFilters := NewMsgGetCFilters(GCSFilterExtended, 0, &chainhash.Hash{})
|
msgGetCFilters := NewMsgGetCFilters(GCSFilterExtended, 0, &chainhash.Hash{})
|
||||||
msgGetCFHeaders := NewMsgGetCFHeaders()
|
msgGetCFHeaders := NewMsgGetCFHeaders(GCSFilterExtended, 0, &chainhash.Hash{})
|
||||||
msgCFilter := NewMsgCFilter(GCSFilterExtended, &chainhash.Hash{},
|
msgCFilter := NewMsgCFilter(GCSFilterExtended, &chainhash.Hash{},
|
||||||
[]byte("payload"))
|
[]byte("payload"))
|
||||||
msgCFHeaders := NewMsgCFHeaders()
|
msgCFHeaders := NewMsgCFHeaders()
|
||||||
|
@ -104,7 +104,7 @@ func TestMessage(t *testing.T) {
|
||||||
{msgMerkleBlock, msgMerkleBlock, pver, MainNet, 110},
|
{msgMerkleBlock, msgMerkleBlock, pver, MainNet, 110},
|
||||||
{msgReject, msgReject, pver, MainNet, 79},
|
{msgReject, msgReject, pver, MainNet, 79},
|
||||||
{msgGetCFilters, msgGetCFilters, pver, MainNet, 61},
|
{msgGetCFilters, msgGetCFilters, pver, MainNet, 61},
|
||||||
{msgGetCFHeaders, msgGetCFHeaders, pver, MainNet, 58},
|
{msgGetCFHeaders, msgGetCFHeaders, pver, MainNet, 61},
|
||||||
{msgCFilter, msgCFilter, pver, MainNet, 65},
|
{msgCFilter, msgCFilter, pver, MainNet, 65},
|
||||||
{msgCFHeaders, msgCFHeaders, pver, MainNet, 58},
|
{msgCFHeaders, msgCFHeaders, pver, MainNet, 58},
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
package wire
|
package wire
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||||
|
@ -15,87 +14,51 @@ import (
|
||||||
// filter headers. It allows to set the FilterType field to get headers in the
|
// filter headers. It allows to set the FilterType field to get headers in the
|
||||||
// chain of basic (0x00) or extended (0x01) headers.
|
// chain of basic (0x00) or extended (0x01) headers.
|
||||||
type MsgGetCFHeaders struct {
|
type MsgGetCFHeaders struct {
|
||||||
BlockLocatorHashes []*chainhash.Hash
|
FilterType FilterType
|
||||||
HashStop chainhash.Hash
|
StartHeight uint32
|
||||||
FilterType FilterType
|
StopHash chainhash.Hash
|
||||||
}
|
|
||||||
|
|
||||||
// AddBlockLocatorHash adds a new block locator hash to the message.
|
|
||||||
func (msg *MsgGetCFHeaders) AddBlockLocatorHash(hash *chainhash.Hash) error {
|
|
||||||
if len(msg.BlockLocatorHashes)+1 > MaxBlockLocatorsPerMsg {
|
|
||||||
str := fmt.Sprintf("too many block locator hashes for message [max %v]",
|
|
||||||
MaxBlockLocatorsPerMsg)
|
|
||||||
return messageError("MsgGetCFHeaders.AddBlockLocatorHash", str)
|
|
||||||
}
|
|
||||||
|
|
||||||
msg.BlockLocatorHashes = append(msg.BlockLocatorHashes, hash)
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 *MsgGetCFHeaders) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding) error {
|
func (msg *MsgGetCFHeaders) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding) error {
|
||||||
// Read num block locator hashes and limit to max.
|
err := readElement(r, &msg.FilterType)
|
||||||
count, err := ReadVarInt(r, pver)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if count > MaxBlockLocatorsPerMsg {
|
|
||||||
str := fmt.Sprintf("too many block locator hashes for message "+
|
|
||||||
"[count %v, max %v]", count, MaxBlockLocatorsPerMsg)
|
|
||||||
return messageError("MsgGetHeaders.BtcDecode", str)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a contiguous slice of hashes to deserialize into in order to
|
|
||||||
// reduce the number of allocations.
|
|
||||||
locatorHashes := make([]chainhash.Hash, count)
|
|
||||||
msg.BlockLocatorHashes = make([]*chainhash.Hash, 0, count)
|
|
||||||
for i := uint64(0); i < count; i++ {
|
|
||||||
hash := &locatorHashes[i]
|
|
||||||
err := readElement(r, hash)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
msg.AddBlockLocatorHash(hash)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = readElement(r, &msg.HashStop)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return readElement(r, &msg.FilterType)
|
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.
|
// 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 *MsgGetCFHeaders) BtcEncode(w io.Writer, pver uint32, _ MessageEncoding) error {
|
func (msg *MsgGetCFHeaders) BtcEncode(w io.Writer, pver uint32, _ MessageEncoding) error {
|
||||||
// Limit to max block locator hashes per message.
|
err := writeElement(w, msg.FilterType)
|
||||||
count := len(msg.BlockLocatorHashes)
|
|
||||||
if count > MaxBlockLocatorsPerMsg {
|
|
||||||
str := fmt.Sprintf("too many block locator hashes for message "+
|
|
||||||
"[count %v, max %v]", count, MaxBlockLocatorsPerMsg)
|
|
||||||
return messageError("MsgGetHeaders.BtcEncode", str)
|
|
||||||
}
|
|
||||||
|
|
||||||
err := WriteVarInt(w, pver, uint64(count))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, hash := range msg.BlockLocatorHashes {
|
err = writeElement(w, &msg.StartHeight)
|
||||||
err := writeElement(w, hash)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err = writeElement(w, &msg.HashStop)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return writeElement(w, msg.FilterType)
|
err = writeElement(w, &msg.StopHash)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Command returns the protocol command string for the message. This is part
|
// Command returns the protocol command string for the message. This is part
|
||||||
|
@ -107,18 +70,18 @@ func (msg *MsgGetCFHeaders) Command() string {
|
||||||
// MaxPayloadLength returns the maximum length the payload can be for the
|
// MaxPayloadLength returns the maximum length the payload can be for the
|
||||||
// receiver. This is part of the Message interface implementation.
|
// receiver. This is part of the Message interface implementation.
|
||||||
func (msg *MsgGetCFHeaders) MaxPayloadLength(pver uint32) uint32 {
|
func (msg *MsgGetCFHeaders) MaxPayloadLength(pver uint32) uint32 {
|
||||||
// Num block locator hashes (varInt) + max allowed
|
// Filter type + uint32 + block hash
|
||||||
// block locators + hash stop + filter type 1 byte.
|
return 1 + 4 + chainhash.HashSize
|
||||||
return MaxVarIntPayload + (MaxBlockLocatorsPerMsg *
|
|
||||||
chainhash.HashSize) + chainhash.HashSize + 1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewMsgGetCFHeaders returns a new bitcoin getcfheader message that conforms to
|
// NewMsgGetCFHeaders returns a new bitcoin getcfheader message that conforms to
|
||||||
// the Message interface using the passed parameters and defaults for the
|
// the Message interface using the passed parameters and defaults for the
|
||||||
// remaining fields.
|
// remaining fields.
|
||||||
func NewMsgGetCFHeaders() *MsgGetCFHeaders {
|
func NewMsgGetCFHeaders(filterType FilterType, startHeight uint32,
|
||||||
|
stopHash *chainhash.Hash) *MsgGetCFHeaders {
|
||||||
return &MsgGetCFHeaders{
|
return &MsgGetCFHeaders{
|
||||||
BlockLocatorHashes: make([]*chainhash.Hash, 0,
|
FilterType: filterType,
|
||||||
MaxBlockLocatorsPerMsg),
|
StartHeight: startHeight,
|
||||||
|
StopHash: *stopHash,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue