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",
|
||||
wire.NewMsgGetCFHeaders(),
|
||||
wire.NewMsgGetCFHeaders(wire.GCSFilterRegular, 0, &chainhash.Hash{}),
|
||||
},
|
||||
{
|
||||
"OnCFilter",
|
||||
|
|
99
server.go
99
server.go
|
@ -788,91 +788,36 @@ func (sp *serverPeer) OnGetCFHeaders(_ *peer.Peer, msg *wire.MsgGetCFHeaders) {
|
|||
return
|
||||
}
|
||||
|
||||
// Attempt to look up the height of the provided stop hash.
|
||||
chain := sp.server.chain
|
||||
endIdx := int32(math.MaxInt32)
|
||||
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)
|
||||
// Fetch the hashes from the block index.
|
||||
hashList, err := sp.server.chain.HeightToHashRange(int32(msg.StartHeight),
|
||||
&msg.StopHash, wire.MaxCFHeadersPerMsg)
|
||||
if err != nil {
|
||||
peerLog.Warnf("Header lookup failed: %v", err)
|
||||
return
|
||||
peerLog.Debugf("Invalid getcfheaders request: %v", err)
|
||||
}
|
||||
if len(hashList) == 0 {
|
||||
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.
|
||||
headersMsg := wire.NewMsgCFHeaders()
|
||||
for i := range hashList {
|
||||
// Fetch the raw committed filter header bytes from the
|
||||
// database.
|
||||
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)
|
||||
for i, headerBytes := range filterHeaders {
|
||||
if len(headerBytes) == 0 {
|
||||
peerLog.Warnf("Could not obtain CF header for %v", hashList[i])
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ func TestMessage(t *testing.T) {
|
|||
msgMerkleBlock := NewMsgMerkleBlock(bh)
|
||||
msgReject := NewMsgReject("block", RejectDuplicate, "duplicate block")
|
||||
msgGetCFilters := NewMsgGetCFilters(GCSFilterExtended, 0, &chainhash.Hash{})
|
||||
msgGetCFHeaders := NewMsgGetCFHeaders()
|
||||
msgGetCFHeaders := NewMsgGetCFHeaders(GCSFilterExtended, 0, &chainhash.Hash{})
|
||||
msgCFilter := NewMsgCFilter(GCSFilterExtended, &chainhash.Hash{},
|
||||
[]byte("payload"))
|
||||
msgCFHeaders := NewMsgCFHeaders()
|
||||
|
@ -104,7 +104,7 @@ func TestMessage(t *testing.T) {
|
|||
{msgMerkleBlock, msgMerkleBlock, pver, MainNet, 110},
|
||||
{msgReject, msgReject, pver, MainNet, 79},
|
||||
{msgGetCFilters, msgGetCFilters, pver, MainNet, 61},
|
||||
{msgGetCFHeaders, msgGetCFHeaders, pver, MainNet, 58},
|
||||
{msgGetCFHeaders, msgGetCFHeaders, pver, MainNet, 61},
|
||||
{msgCFilter, msgCFilter, pver, MainNet, 65},
|
||||
{msgCFHeaders, msgCFHeaders, pver, MainNet, 58},
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
package wire
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"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
|
||||
// chain of basic (0x00) or extended (0x01) headers.
|
||||
type MsgGetCFHeaders struct {
|
||||
BlockLocatorHashes []*chainhash.Hash
|
||||
HashStop chainhash.Hash
|
||||
FilterType FilterType
|
||||
}
|
||||
|
||||
// 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
|
||||
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 *MsgGetCFHeaders) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding) error {
|
||||
// Read num block locator hashes and limit to max.
|
||||
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)
|
||||
err := readElement(r, &msg.FilterType)
|
||||
if err != nil {
|
||||
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.
|
||||
// This is part of the Message interface implementation.
|
||||
func (msg *MsgGetCFHeaders) BtcEncode(w io.Writer, pver uint32, _ MessageEncoding) error {
|
||||
// Limit to max block locator hashes per message.
|
||||
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))
|
||||
err := writeElement(w, msg.FilterType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, hash := range msg.BlockLocatorHashes {
|
||||
err := writeElement(w, hash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
err = writeElement(w, &msg.HashStop)
|
||||
err = writeElement(w, &msg.StartHeight)
|
||||
if err != nil {
|
||||
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
|
||||
|
@ -107,18 +70,18 @@ func (msg *MsgGetCFHeaders) Command() string {
|
|||
// MaxPayloadLength returns the maximum length the payload can be for the
|
||||
// receiver. This is part of the Message interface implementation.
|
||||
func (msg *MsgGetCFHeaders) MaxPayloadLength(pver uint32) uint32 {
|
||||
// Num block locator hashes (varInt) + max allowed
|
||||
// block locators + hash stop + filter type 1 byte.
|
||||
return MaxVarIntPayload + (MaxBlockLocatorsPerMsg *
|
||||
chainhash.HashSize) + chainhash.HashSize + 1
|
||||
// Filter type + uint32 + block hash
|
||||
return 1 + 4 + chainhash.HashSize
|
||||
}
|
||||
|
||||
// NewMsgGetCFHeaders returns a new bitcoin getcfheader message that conforms to
|
||||
// the Message interface using the passed parameters and defaults for the
|
||||
// remaining fields.
|
||||
func NewMsgGetCFHeaders() *MsgGetCFHeaders {
|
||||
func NewMsgGetCFHeaders(filterType FilterType, startHeight uint32,
|
||||
stopHash *chainhash.Hash) *MsgGetCFHeaders {
|
||||
return &MsgGetCFHeaders{
|
||||
BlockLocatorHashes: make([]*chainhash.Hash, 0,
|
||||
MaxBlockLocatorsPerMsg),
|
||||
FilterType: filterType,
|
||||
StartHeight: startHeight,
|
||||
StopHash: *stopHash,
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue