From 53ec80209188f23a554101dd952cc111dc8cf9e0 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Fri, 8 Jun 2018 20:11:10 -0500 Subject: [PATCH] server: Convert CF code to use new inv discovery. This modifies the getcfheaders handling code to use the recently refactored block locator code that is now available in blockchain instead of manually performing the task. Not only is the code in chain more efficient, it also helps ensure the handling for block locators is consistent. While here, it also modifies a few cfilter-related comments for consistency and corrects a near bug which was limiting the response to the maximum allowed block headers per message as opposed to maximum allowed cfilter headers per message. Since the two constants are currently the same value, this is no functional change in this regard. --- server.go | 109 ++++++++++++------------------------------------------ 1 file changed, 23 insertions(+), 86 deletions(-) diff --git a/server.go b/server.go index 39a6090e..f55645cf 100644 --- a/server.go +++ b/server.go @@ -791,7 +791,7 @@ func (sp *serverPeer) OnGetHeaders(p *peer.Peer, msg *wire.MsgGetHeaders) { // support bit, it will be banned since it is intentionally violating the // protocol. func (sp *serverPeer) enforceNodeCFFlag(cmd string) bool { - if sp.server.services&wire.SFNodeCF != wire.SFNodeCF { + if !hasServices(sp.server.services, wire.SFNodeCF) { // Ban the peer if the protocol version is high enough that the peer is // knowingly violating the protocol and banning is enabled. // @@ -799,7 +799,7 @@ func (sp *serverPeer) enforceNodeCFFlag(cmd string) bool { // or not banning is enabled, it is checked here as well to ensure the // violation is logged and the peer is disconnected regardless. if sp.ProtocolVersion() >= wire.NodeCFVersion && !cfg.DisableBanning { - // Disonnect the peer regardless of whether it was banned. + // Disconnect the peer regardless of whether it was banned. sp.addBanScore(100, 0, cmd) sp.Disconnect() return false @@ -823,7 +823,7 @@ func (sp *serverPeer) OnGetCFilter(p *peer.Peer, msg *wire.MsgGetCFilter) { return } - // Ignore getcfilter requests if cfg.NoCFilters is set or we're not in sync. + // Ignore request if CFs are disabled or the chain is not yet synced. if cfg.NoCFilters || !sp.server.blockManager.IsCurrent() { return } @@ -896,8 +896,7 @@ func (sp *serverPeer) OnGetCFHeaders(p *peer.Peer, msg *wire.MsgGetCFHeaders) { return } - // Ignore getcfheader requests if cfg.NoCFilters is set or we're not in - // sync. + // Ignore request if CFs are disabled or the chain is not yet synced. if cfg.NoCFilters || !sp.server.blockManager.IsCurrent() { return } @@ -911,91 +910,31 @@ func (sp *serverPeer) OnGetCFHeaders(p *peer.Peer, msg *wire.MsgGetCFHeaders) { return } - // Attempt to look up the height of the provided stop hash. + // Find the most recent known block in the best chain based on the block + // locator and fetch all of the block hashes after it until either + // wire.MaxCFHeadersPerMsg have been fetched or the provided stop hash is + // encountered. + // + // Use the block after the genesis block if no other blocks in the provided + // locator are known. This does mean the served filter headers will start + // over at the genesis block if unknown block locators are provided. chain := sp.server.blockManager.chain - endIdx := int64(math.MaxInt64) - 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 := int64(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 { - peerLog.Warnf("Header lookup failed: %v", err) - return - } + hashList := chain.LocateBlocks(msg.BlockLocatorHashes, &msg.HashStop, + wire.MaxCFHeadersPerMsg) if len(hashList) == 0 { return } // Generate cfheaders message and send it. + cfIndex := sp.server.cfIndex 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) + // Fetch the raw committed filter header bytes from the database. + hash := &hashList[i] + headerBytes, err := cfIndex.FilterHeaderByBlockHash(hash, + msg.FilterType) + if err != nil || len(headerBytes) == 0 { + peerLog.Warnf("Could not obtain CF header for %v: %v", hash, err) return } @@ -1003,14 +942,12 @@ func (sp *serverPeer) OnGetCFHeaders(p *peer.Peer, msg *wire.MsgGetCFHeaders) { var header chainhash.Hash err = header.SetBytes(headerBytes) if err != nil { - peerLog.Warnf("Committed filter header deserialize "+ - "failed: %v", err) + peerLog.Warnf("Committed filter header deserialize failed: %v", err) return } headersMsg.AddCFHeader(&header) } - headersMsg.FilterType = msg.FilterType headersMsg.StopHash = hashList[len(hashList)-1] sp.QueueMessage(headersMsg, nil) @@ -1024,7 +961,7 @@ func (sp *serverPeer) OnGetCFTypes(p *peer.Peer, msg *wire.MsgGetCFTypes) { return } - // Ignore getcftypes requests if cfg.NoCFilters is set. + // Ignore request if CFs are disabled. if cfg.NoCFilters { return }