pub trait LostNotificationsAreRepaired: NotificationChannelIsLossy { }Expand description
Lemma (A lost notification is repaired). A client that misses a notification still reaches the state it would have reached, provided it remains connected to at least one correct validator that has the change. Three independent mechanisms do this, and none of them replays the lost message.
Redundancy. ChainClient::listen opens one subscription per validator in the committee, via
update_notification_streams, and processes them concurrently. Every validator that processes a
change notifies about it, so a client loses a notification only when every validator it is
subscribed to fails to deliver that one — not when any single one does.
Resynchronization on (re)subscribe. Establishing a stream is not just an attachment point: the
same future calls Client::synchronize_chain_state_from against that validator before yielding
the stream, precisely because, in the code’s own words, “we may have missed notifications since
the last time we synchronized”. Since update_notification_streams is re-run on every
Reason::NewBlock, and a dropped connection is re-established through the same path, a gap in
the stream is closed by state synchronization rather than by recovering the messages that fell
in it.
Coalescing. No handler applies the change it was told about; each brings the chain up to date.
In linera_client::chain_listener, Reason::NewIncomingBundle and Reason::NewEvents both
reduce to maybe_notify_inbox_processing, whose waiting loop runs
ChainClient::process_inbox_without_prepare — draining everything pending, not the one bundle
named. Reason::NewBlock calls update_wallet and re-derives event subscriptions. Handlers are
therefore idempotent and depend only on current state, so one run after k notifications
achieves what k runs would. Notify::notify_one stores a permit when no task is waiting, so a
notification arriving during a pass starts another rather than being swallowed. ∎
What is not repaired. Every mechanism above assumes a failure that is either whole-process or
network-level, because those are the failures the model has. A validator that is up, answering
RPCs and voting normally, but silently delivering no notifications — the partial crash
NotificationChannelIsLossy describes — defeats two of the three. Redundancy survives only if
such a failure is independent across validators, which a systematic one is not. Resynchronization
never runs, because it is triggered by establishing a stream and no stream ever drops: the client
holds a healthy connection to a validator that has stopped talking.
Coalescing is then irrelevant, since nothing arrives to coalesce. The client is not told it is
learning nothing, and nothing escalates: ChainListener::next_action selects over the
notification streams, the cancellation token and its command channel, and there is no timer among
them. Pending bundles stay unprocessed and subscribed events unread for as long as the condition
lasts, which — being outside the fault model — is not bounded by GST or by anything else the
specification states.