This is an implementation of #5982 (and based off @sipa’s commit in #5307, which has been squashed into this commit).
Currently new blocks are announced via inv
messages. Since headers-first download was introduced in 0.10, blocks are not processed unless the headers for the block connect to known, valid headers, so peers receiving inv
messages respond with a getheaders
and a getdata
: the expectation is that the announcing peer will send the headers for the block and any parents unknown to the peer before delivering the new block.
In the case of a reorg, nodes currently announce only the new tip, and not the blocks that lead to the tip. This means that an extra round-trip is required to relay a reorg, because the peer receiving the inv
for the tip must wait for the response to the getheaders
message before being able to request the missing blocks. (For additional reasons discussed in #5307 (comment), it’s not optimal to inv
all the blocks added in the reorg to a headers-first peer, because this results in needless traffic due to the way getheaders
requests are generated when direct-fetching inv
‘ed blocks.)
This pull implements a new sendheaders
p2p message, which a node sends to its peers to indicate that the node prefers to receive new block announcements via a headers
message rather than an inv. This implementation does a few things:
- When announcing a new block to a peer that prefers headers, try to announce all the blocks that are being added, back to the last fork point, by sending headers for each.
- Avoid sending headers for blocks that are already known to the peer (determined by checking
pindexBestKnownBlock
andpindexBestHeaderSent
and their ancestors).- pindexBestKnownBlock is updated based on
inv
messages,headers
sent from that peer, andgetheaders
messages sent from the peer. pindexBestHeaderSent
is a new variable that tracks the best header we have sent to the peer
- pindexBestKnownBlock is updated based on
- Avoid sending more than 8 headers to the peer. This code is designed to be optimized for relaying at the tip, so a large reorg is some kind of error condition; in that case avoid spamming the peer with a lot of headers and instead fall back to the old
inv
mechanism. - If the headers to be announced aren’t known to connect to headers that the peer has, then revert to sending an
inv
at the tip instead. This is designed to avoid DoS points from sending headers that don’t connect. Since every new block should generally be announced by one peer in any pair of peers, it’s expected that once headers-announcement begins on a link (ie once two nodes are known to be synced), it should be able to continue. - After #6148 is merged, this would allow pruning nodes to generally be able to relay reorgs to peers via headers announcements. The code that implements direct fetching upon receipt of a headers message will send
getdata
requests to any peer that announces a block via a headers message.
This pull includes a new python p2p test exercising the new functionality.
BIP 130 describes the proposed new sendheaders
p2p message here:
https://github.com/bitcoin/bips/blob/master/bip-0130.mediawiki