consensus-test
Safe HaskellSafe-Inferred
LanguageHaskell2010

Test.Consensus.MiniProtocol.ChainSync.Client

Description

Tests for the chain sync client.

The chain sync client is a stateful component that tracks the chain of an upstream peer. It validates the headers that it receives from the peer; validated headers are then reported to the block fetch client which will download them and offer them to the chain DB, which makes the final choice whether or not to adopt those blocks.

The tests mock a series of state changes of the up-stream node as well as the node's own state (the node's own state is relevant because if the node and the up-stream peer diverge too much we are not interested in their chain anymore, and we might not be able to validate their headers). We then check that the chain sync client is reporting the right exceptions if and only if we expect them to be thrown based on the mock state changes (exceptions such as "fork is deep", "up-stream node asked for an invalid rollback", etc.).

The client's (simulated) wall-clock matters in this test because the ChainSync client has special handling for headers that arrive before the wall-clock reaches the onset of the header's claimed slot, which is inevitable even with only honest peers due to non-global clocks drifting/etc. This test advances time in a way that is unrealistic but does allow for some headers to arrive early (but not so early that the client disconnects from the server).

The approach to the clocks is as follows. A logical clock drives the whole test; it ticks along the naturals. Each tick causes the local and upstream chains to update and that's the primary content of the whole test. However, the first thing that happens at the start of each logical tick is the client's simulated wall-clock advances (via a single threadDelay call) to the onset of the greatest slot involved in any of that logical tick's server-side chain updates less the randomly-chosen local clock skew. Thus, if the greatest header involved in some logical tick is part of an upstream chain update, then it will arrive as a future header (but only near-future, never far-future). (Client-side updates are also handled, but slightly differently; see the code comments.) Finally, recall that the io-sim layer means those delays happen nearly instantaneously with respect to the real world wall-clock.

Documentation