Skip to main content

SequentialChainState

Trait SequentialChainState 

Source
pub trait SequentialChainState { }
Expand description

Assumption (Sequential instance state). The transitions of one consensus instance are mutually exclusive and each runs to completion: no two of them interleave their reads and writes of the same ChainManager.

Exclusivity has two halves, and only the second is in this repository’s control.

Within a worker process, linera_core::worker::WorkerState reaches a chain only through a per-chain tokio::sync::RwLock<ChainWorkerState>chain_write for transitions, chain_read for queries. A transition holds the write side for its whole duration, and the manager is !Sync-by-construction behind the guard.

Across the processes of one validator, each chain belongs to exactly one worker, because shard assignment is static: ValidatorInternalNetworkPreConfig::get_shard_id in linera-rpc is a pure function of the validator’s public key, the chain id and shards.len(), with no leases and no handoff. Senders route by that function, so a worker is only ever asked for the chains of its own shard.

That partition excludes reads as much as writes. All shards share one backing store, so nothing physically prevents a worker from reading another shard’s keys; what makes it never happen is that a worker is never asked to. A chain’s mutable state is therefore touched in neither direction by any process but its owner.

Chains do still share storage, but only published artifacts: blobs, which are content addressed, and events, which a reader reaches through OracleResponse::Event. Both are immutable once written and belong to no chain’s view. So the boundary is not “no shared storage” but “no reading another chain’s state”: a cross-chain dependency is either delivered as a message or read from one of those two stores, never observed in the producing chain’s ChainManager or inboxes. IncomingBundlesMatchTheLocalInbox is the form that takes for the message case.

The specification relies on the composition whenever it reasons about “the state immediately before” a vote — for instance in UnlockingJustification, where the guard evaluated by ChainManager::check_proposed_block must still describe the state when ChainManager::create_vote runs a few statements later.

Residual obligation. The second half holds only while shards.len() is stable and worker processes do not overlap. Changing the shard count re-partitions every chain, and a rolling restart that runs a replacement alongside its predecessor puts two processes on the same chain; in both cases they compute the same owner and write the same shared keys. Nothing in the code detects either, so this is a deployment obligation, not an enforced invariant.

Implementors§