blockmanager: Avoid duplicate header announcements.

Clients are able to choose between two modes of notification about new
blocks via the wire protocol.  The first, and current default, is via
inv messages and the second is via direct header announcements.

There is code in the peer package which deals with filtering duplicate
inventory announcements via the QueueInventory message.  This works as
expected for inv-based announcements, however, direct header
announcements are not inv messages and hence do not use that code path.

Consequently, the recent addition of the fast relay path which relied on
that filtering to avoid sending duplicate announcements resulted in
duplicate announcements being sent to peers who requested the header
announcements mode.

This resolves the issue by adding some logic directly to the
notifications themselves to deal with filtering duplicates, both for inv
and header-based announcements.
This commit is contained in:
Dave Collins 2018-09-27 18:07:09 -05:00
parent b6d564d119
commit b413da2350
No known key found for this signature in database
GPG Key ID: B8904D9D9C93D1F2

View File

@ -330,6 +330,10 @@ type blockManager struct {
cachedCurrentTemplate *BlockTemplate
cachedParentTemplate *BlockTemplate
AggressiveMining bool
// The following fields are used to filter duplicate block announcements.
announcedBlockMtx sync.Mutex
announcedBlock *chainhash.Hash
}
// resetHeaderState sets the headers-first mode state to values appropriate for
@ -1659,6 +1663,9 @@ func (b *blockManager) handleNotifyMsg(notification *blockchain.Notification) {
// Generate the inventory vector and relay it immediately.
iv := wire.NewInvVect(wire.InvTypeBlock, block.Hash())
b.server.RelayInventory(iv, block.MsgBlock().Header, true)
b.announcedBlockMtx.Lock()
b.announcedBlock = block.Hash()
b.announcedBlockMtx.Unlock()
// A block has been accepted into the block chain. Relay it to other peers
// (will be ignored if already relayed via NTNewTipBlockChecked) and
@ -1736,9 +1743,16 @@ func (b *blockManager) handleNotifyMsg(notification *blockchain.Notification) {
}
}
// Generate the inventory vector and relay it immediately.
iv := wire.NewInvVect(wire.InvTypeBlock, blockHash)
b.server.RelayInventory(iv, block.MsgBlock().Header, true)
// Generate the inventory vector and relay it immediately if not already
// known to have been sent in NTNewTipBlockChecked.
b.announcedBlockMtx.Lock()
sent := b.announcedBlock != nil && *b.announcedBlock == *blockHash
b.announcedBlock = nil
b.announcedBlockMtx.Unlock()
if !sent {
iv := wire.NewInvVect(wire.InvTypeBlock, blockHash)
b.server.RelayInventory(iv, block.MsgBlock().Header, true)
}
// A block has been connected to the main block chain.
case blockchain.NTBlockConnected: