Blocks from the future
A node can receive a block whose slot is ahead of the current slot. We call such blocks from the future.
The Praos protocol ignores chains with blocks from the future during chain selection. It assumes nodes have perfectly synchronized clocks, which is not realistic due to imperfections in protocols like NTP and leap seconds. In practice, a clock skew of up to 2 seconds is considered acceptable. Our implementation differentiates between blocks from the near future and those from the far future:
- A block is from the near future if the onset of its slot is ahead of the wall clock, but only by at most the admissible clock skew. Despite being from the future, these blocks are assumed to potentially have been minted by honest nodes.
- A block is from the far future if the onset of its slot is ahead of the wall clock by more than the admissible clock skew. By assumption, these blocks cannot have been minted by an honest node.
Handling blocks from the future
As of #525:
- When receiving a header from the near future in
ChainSync
, an artificial delay is introduced until the header is no longer from the future. Only then it is validated and the corresponding block body is downloaded and added to theChainDB
for chain selection, where it is not considered to be from the future due to the previous artificial delay. - When receiving a header from the far future, we immediately disconnect from the corresponding peer.
In addition, we never forge atop a block from the future (which was the case even before #525.
During initialization
Since we now delay the headers until they are no longer from the near future, a caught up node will never contain blocks from the future in the VolatileDB
, according to its own clock.
However, there are two caveats:
- Clock rewinds can violate this property. In particular the node will error when we rewind the clock by more than 20 seconds.
- The node clock might be set in the future relative to the rest of the nodes in the network.
Thus, it is possible that after restarting a node with a clock set in the future, and setting the clock back so that the clock is now synchronized with the rest of the network, the blocks in the
VolatileDB
are regarded as blocks from the future.
When initializing the ChainDB
we do not check if blocks in the VolatileDB
are from the future. This presents two inconveniences:
- When the node diffuses these blocks from the far future, it will be disconnected from other peers.
- The node will not forge a block on top of a block from the future, thus missing its chance to lead in the slot.
These problems can be solved by wiping out the VolatileDB
in this situation.
However, note this is an extremely rare situation: the clock of the node would have to have been set quite far in the future, as shutting down a node and restarting it already takes a significant amount of time.
In the future we might delete blocks from the future from the VolatileDB
to improve the user experience and robustness of the initialization logic. For now it does not seem worthwhile to handle that rare case. (Downstream/bidirectional peers will disconnect from such a node, but only until enough time has passed that its VolatileDB
does not contain blocks from the future anymore.)