Architecture · Explanation
Consensus, finality, and epoch boundaries
Singularity's default consensus path orders block payloads through Simplex, then executes finalized blocks in height order. A consensus decision, a successful execution, and a durable local recovery point are different facts. Keeping them separate explains both normal transaction confirmation and the node's refusal to continue after a local execution failure.
For application code, follow the transaction lifecycle. To investigate a node that has stopped advancing, follow incident diagnosis; for exact status responses, use the RPC reference.
The engine and the application have different jobs
The active integration imports Commonware's Simplex engine and its Ed25519 scheme. The application supplies an automaton for proposals and verification, a relay for payload availability, and a reporter for finalized decisions. Some older module comments and thread names still say “aggregation”; those names do not select the engine. The constructor and resolved configuration do. Engine integration.
A proposal identifies its parent and carries a height, recorded timestamp, and transaction payload. The automaton checks linkage and contiguous height, and validates the timestamp against the parent's recorded time or the committed clock floor. It also checks payload framing. These checks prevent a proposal from creating a hole that the height-ordered execution queue could never fill. They are not a pre-vote execution of every contract in the payload. Verification.
This distinction matters when evaluating safety assumptions. Agreement on an ordered payload still depends on every executing node having the correct deterministic engine, state, and protocol settings. A broken local GPU engine cannot turn its failure into a different valid application result.
From a decision to state
The execution queue can prepare later blocks while the current block executes. Preparation is allowed off-thread only when it does not need the current state. In particular, address lookup table resolution must use the correct height's accounts and slot hashes; blocks containing those lookups keep that work on the execution thread.
Execution and the first state-application phase remain serial by height. The finalization lane consumes their result snapshots through a bounded FIFO channel. Its bound is 16 blocks, which limits how far execution can lead the later work. The state's separate ordered writer performs WAL and durable-height writes; the finalization lane is not itself the disk writer. Queue and lane, state-dependent preparation.
Why a finalized block can halt a node
There are two different failure classes:
| Failure | Required interpretation |
|---|---|
| A transaction deterministically fails an instruction or budget check | Execute the agreed failure semantics and produce the corresponding result. |
| The node cannot execute an already-finalized block because of a local engine, framing, journal, or state defect | Halt rather than skip that height or invent a failed transaction result. |
The reporter explicitly latches a halt when preparation/execution cannot produce the finalized block's result. Skipping it would leave a “ghost” height: consensus has finalized it, but the local state and receipts have never applied it. Later execution could then silently diverge.
Storage has another distinction. A persistent-store drain failure is fatal; a slow QMDB root drain is a different condition and can be nonfatal while the cumulative-root path continues. Do not diagnose either from an HTTP 200 or a previously observed slot alone. Use the health response and durability watermarks. Failure handling, execution halt.
Epoch transitions are state changes
An epoch groups heights for stake activation, deactivation, rewards, and validator membership rotation. The transition code persists the advancing epoch, processes stake changes, derives reward participants from the on-chain registry when seeded, credits rewards, and rotates the registry.
The next block must observe those changes. Consequently, after submitting the first block of a new epoch to finalization, the execution worker waits until that height has fully finalized before executing the next block. Ordinary blocks do not take this barrier. Removing it for throughput would change what the next transaction can read. Epoch barrier, transition.
Membership rotation also changes the engine's participant set and epoch domain. The runtime creates epoch-specific engine partitions and retires old engine handles. A joining node derives an initial epoch from its installed height as well as configuration. Registration alone does not give a process voting authority; see validator lifecycle and state sync.
Epoch persistence and account durability are separate operations in the current implementation. Do not infer a single atomic disk commit for every transition effect from the presence of the execution barrier. The recovery workflow explains the restart implications.
Engine and role choices
Simplex is the default engine. Rohu selects the experimental Rohu-Paplet integration, whose configuration requires the different n = 5f + 1 validator model. It is not a performance switch to turn on independently within an existing Simplex fleet. Engine selection can come from the consensus configuration and its documented override; unknown explicit selections are rejected by the strict parser.
Roles are also distinct. Sequencers produce diffs. Validators re-execute finalized blocks. Read-only replicas ingest the replicated state path and serve queries without voting. The fact that a validator has a diff queue constructed does not mean that queue is its live state-ingestion path. Engine and roles.
Verify changes at the right boundary
Focused tests around child_links_to_parent protect height and timestamp acceptance. Epoch tests cover transition detection, registry-based reward selection, persistence, and the last-height rotation trigger. Membership simulation exercises the interaction between roles and rotation. These are source-level regression evidence, not a measurement of live finality latency.
When changing this path, test proposal acceptance, finalized execution failure, epoch ordering, and restart behavior separately. Use validation strategy to choose the relevant existing shard or focused test without rebuilding the entire test graph unnecessarily.