Skip to content

Commit

Permalink
server: Convert CF code to use new inv discovery.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
davecgh committed Jun 12, 2018
1 parent ffabd89 commit 53ec802
Showing 1 changed file with 23 additions and 86 deletions.
109 changes: 23 additions & 86 deletions server.go
Original file line number Diff line number Diff line change
Expand Up @@ -791,15 +791,15 @@ 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.
//
// NOTE: Even though the addBanScore function already examines whether
// 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
Expand All @@ -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
}
Expand Down Expand Up @@ -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
}
Expand All @@ -911,106 +910,44 @@ 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
}

// Deserialize the hash.
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)
Expand All @@ -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
}
Expand Down

0 comments on commit 53ec802

Please sign in to comment.