This commit adds support for relaying blocks between peers. It keeps
track of inventory that has either already been advertised to remote peers
or advertised by remote peers using a size-limited most recently used
cache. This helps avoid relaying inventory the peer already knows as
much as possible while not allowing rogue peers to eat up arbitrary
amounts of memory with bogus inventory.
This commit reworks the getblocks handling a bit to clean it up and match
the reference implementation handling. In particular, it adds monitoring
for when peers request the final block advertised from a previous
getblocks message and automatically avertises the latest known block
inventory to trigger the peer to send another getblocks message.
When no blocks in the block locator are found, start with the block after
the genesis block. This means the client will start over with the genesis
block if unknown block locators are provided. This mirrors the behavior
in the reference implementation.
This commit reworks the getheaders handling a bit to clean it up and match
the reference implementation handling. In particular, in addition to the
normal handling where headers starting after the block locator up to the
stop hash are served, when no locator hashes are provided, the stop hash
acts as a way to specifically request that header. Next, an empty headers
message is sent when no hashes provided by the block locator can be
found. Finally, there was a bug that was limiting the number of headers
that could requested at once to 500 instead of the expected 2000.
Rather than only setting the services field for inbound peers, set it for
all peers. This field referes to the remote peer's services regardless of
inbound or outbound.
This commit significantly reworks the fetching code to interop better with
bitcoind. In particular, when an inventory message is sent, and the
remote peer requests the final block, the remote peer sends the current
end of the main chain to signal that there are more blocks to get.
Previously this code was automatically requesting more blocks when the
number of in-flight blocks was under a certain threshold. The original
approach does help alleviate delays in the "request final, wait for
orphan, request more" round trip, but due to the aforementioned mechanism,
it leads to double requests and other subtle issues.
This commit modifies the input message handler so that when a remote peer
sends a block, no further messages from that peer are accepted until the
block has been fully processed and therefore known good or bad. This
helps prevent a malicious peer from queueing up a bunch of bad blocks
before disconnecting (or being disconnected) and wasting memory.
Additionally, this behavior is depended on by at least the block
acceptance test tool as the reference implementation processes blocks in
the same thread and therefore blocks further messages until the block has
been fully processed as well.