Safety and Liveness: What This Chain Looked Like It Was Losing, and What It Is Actually Doing

The two properties, without the jargon

Safety is that nothing bad ever happens. For a chain: two conflicting histories are never both committed. A safety failure is permanent and cannot be repaired by waiting.

Liveness is that something good eventually happens. For a chain: it keeps producing. A liveness failure is frustrating and is repaired the moment the network recovers.

Why you cannot simply have both

When messages can be delayed arbitrarily, a protocol cannot guarantee both at once. It has to be willing to give one up while conditions are bad.

Protocols of this family always give up liveness. They stop rather than risk committing two conflicting things, because a stalled chain can be restarted and a forked one cannot be unforked.

That choice is not a compromise. It is the design.

The safety mechanism here, exactly

Each participant keeps a lock: a certificate it will not vote against.

The rule read at its call site is the classic one. A block is votable only if its parent certificate is at least as recent as the locked one, or if it extends the locked block directly.

And the lock trails by one. When a higher certificate arrives, the previously-highest becomes the new lock. So a participant is always anchored one certificate behind the frontier, which is what stops it endorsing a competing branch that its own recent votes already ruled out.

The liveness mechanism is the pacemaker

A deadline per round, a vote to abandon the round when it expires, a bounded doubling of the wait, and a fresh round under somebody else.

The wait is capped, so a silent leader costs a bounded delay rather than an unbounded one.

CORRECTED 2026-08-02: this network does NOT have a liveness problem

An earlier version of this section reported blocks arriving in bursts separated by twenty to thirty minutes of nothing, said no rounds were being lost, and said nothing explained it.

Two things were wrong with that, and they compounded.

First, the wrong index. Three chained blocks share a single height value on this chain, so counting by height sees one block in three. The "twenty to thirty minute" gap was three ten-minute intervals collapsed into one.

Second, and decisively: the quiet is configured. Re-measured by canonical sequence, the gaps are six hundred seconds, each within a couple of seconds of it, eight in a row. That is a named constant in the node with a comment explaining the whole behaviour: the proposer is event-driven, and with no work it proposes one empty block every ten minutes, which finalizes the previous burst's leftovers, bounds how far participants can drift, and keeps the head visibly advancing.

The reason is disk. The comment records that the free-running proposer wrote on the order of a gigabyte a day, and the heartbeat brings it to a few megabytes.

So there is no liveness failure here. An idle chain producing a heartbeat is a chain working as designed, and this page had it wrong for the ordinary reason: a measurement taken through the wrong index, then a rate derived from it.

What the correction does not change

The theory above stands. A protocol of this family gives up liveness rather than safety, and that is still the trade it makes.

And the way to tell the two apart from outside is still the right method: compare rounds against heights against timestamps. What this estate got wrong was not the method but the index it applied the method to, which is a distinction worth keeping, because the method survived and the numbers did not.

The limit of our own safety evidence, stated plainly

We have not seen a fork. That is much weaker evidence than it sounds.

Safety is a claim about two histories, and checking it means comparing two independent observers. This network has one process behind one endpoint, so a reader asking the endpoint whether it disagrees with itself will always be told no.

So: no fork has been observed, by an observer structurally incapable of observing one. That is the honest sentence, and it is why an independently operated node is worth more to this network than almost anything else on the roadmap.

Target and observed, both stated

The genesis parameters set a target of half a second per block.

When there is work, the chain meets or beats it: nine blocks in about seven and a half seconds in the burst this estate measured. When there is none, it produces one block every ten minutes on purpose.

So the average across both is the wrong statistic and would describe a steady trickle that exists in neither mode. This estate has now corrected itself twice over this number, and the lesson has sharpened: the first correction was that intermittent and slow are different; the second was that the interval it called intermittent was configured, and measured through the wrong index.

What you can check yourself

solidus_canonHead, then solidus_getBlockBySeq downward, comparing round, height and timestamp_ms together

Use the sequence, not the height, or you will see one block in three and derive a rate three times too slow, which is exactly what this page did. Then read all three fields, not one: height alone tells you nothing about why, round tells you whether the protocol is fighting, and the timestamps tell you whether the interval is organic or a constant.

Keep reading

Safety and Liveness: What This Chain Looked Like It Was Losing, and What It Is Actually Doing · Solidus