Peer communication during Sync
In this commit, the peer state machine handles the messages used during Sync. Currently once the peer reaches the Ready
state, it does nothing else since the FSM has the NullFunction
for its handler.
We need to add handlers for the four messages: GetHeaders
, GetBlocks
, Headers
and Block
. GetBlocks is the only message
that is strictly not a Bitcoin protocol message. But in fact, it is very close to GetData
, the message that will be sent out.
case class GetBlocks(hsd: List[HeaderSyncData])
We have a different message because we want to keep a list of HeaderSyncData
rather than a list of InvEntry
. InvEntry
is just a hash whereas HeaderSyncData has the block header, the height and the proof of work. It is something that we
need to build after we have the new headers and we want to carry this information throughout the rest of the Sync process.
The handlers for GetHeaders/Headers and GetBlocks/Blocks use the same pattern. It is assumed that a peer cannot be asked for headers and blocks at the same time, i.e. the caller should get the response to GetHeaders before it asks for blocks. Actually, only one request can be done at a time and it's okay for the peer to store a reference to the actor that sent it.
These states have timers that fire if the peer doesn't make progress because the remote side doesn't reply. When the timer
expires, the peer gets a StateTimeout
message which is caught in the common handler whenUnhandled
. The peer shuts itself
down on a time out.
The peer doesn't track which blocks it has received and therefore cannot tell if the GetBlock request finished. It is actually
the requestor that informs the peer of this fact with the GetBlocksFinished
message. The "getblocks" timer is reset on every
block so that it triggers only if no block has been received before the time runs out.
In the next section, we'll make the peer manager maintain a pool of peers of a configurable size.