Skip to main content

NotificationImpliesPersistedChange

Trait NotificationImpliesPersistedChange 

Source
pub trait NotificationImpliesPersistedChange: CorrectValidator + StorageAtomicity { }
Expand description

Lemma (A correct validator’s notification reports a change that is already persisted). If a client receives a Notification from a correct validator, the state change it names is in that validator’s storage. Nothing is claimed about a faulty validator’s notifications, which by CorrectValidator may report anything at all.

Proof. Notifications are not sent where they are built. Each is pushed onto the notifications field of a NetworkActions value which the handler returns, and every handler that changes state calls save() before returning it — a failed save propagates with ?, so the actions are dropped and nothing is dispatched. Site by site:

  • Reason::NewBlock and Reason::NewEvents are pushed in ChainWorkerState::execute_contiguous_block before its self.save()?, so a save that fails discards them along with the actions that carry them.
  • Reason::NewEvents is pushed again in preprocess_certified_block, there after the save rather than before it, which reaches the same conclusion more directly.
  • Reason::NewRound is built inside create_network_actions from ChainManager::current_round, and travels out in the same returned value.
  • Reason::NewIncomingBundle is pushed in WorkerState::handle_cross_chain_request only once process_cross_chain_update has returned CrossChainUpdateResult::Updated, and that result crosses a chain_write batch, which takes the lock and saves once before replying.

The caller dispatches through Notifier::notify_chain on the returned value alone, so no path reaches a client without a completed save. By StorageAtomicity that save is all or nothing, so a client is never told about a half-written change. ∎

A notification carries no evidence. Notification is a chain_id and a Reason: no signature, no certificate, not even a field naming the sender. Validators are not asked to sign them.

Knowing who sent one is a deployment matter rather than a protocol one. Under NetworkProtocol::Grpc(TlsConfig::Tls) the transport authenticates which validator the stream came from, so a third party cannot inject notifications into it; TlsConfig::ClearText is an equally valid configuration, so the specification cannot assume even that. And where it does hold it authenticates the origin, never the content, and only to the client holding the connection — a client cannot show anyone else what a validator told it. A notification is therefore never evidence in the sense the accountability results use: none is convictable, and none can be forwarded as proof of anything.

So the qualifier above is not a technicality a client can discharge by inspection. A fabricated notification is indistinguishable by content from a sound one, and the only way to learn whether the change happened is to ask. What a client may take from one is that it is worth querying now, and never what the answer will be. That the named block is the block at that height, rather than one validator’s idea of it, is CommitAgreement’s and not this lemma’s.

Implementors§