ZooBC wiki
Security and architecture

The spine chain

You are looking at an old version of this page: revision #112 by zoobc.how, 2026-10-26 20:44 UTC. See the current version

Every ZooBC node keeps two chains. The main chain makes a block every 15 seconds and carries the transactions. Beside it runs the spine: one block a day on mainnet, carrying no transactions at all. A spine block records what the registry as a whole vouches for, a checkpoint of the main chain, the node keys that joined or left, and the manifests of the latest snapshots, and it needs the signatures of two thirds of the seats. That makes the spine the anchor of finality and the starting point of every new node.

What a spine block holds

  • A checkpoint. Each spine block names a main-chain reference block deep enough to be settled: 760 blocks (3 hours 10 minutes) below the main tip when the spine block is made, and never lower than the previous spine block's reference. It copies that block's Merkle root, and its payload hash commits to the reference block's own hash and cumulative difficulty, so the checkpoint pins one exact block, not just a height.
  • Public-key changes. The node keys added to or removed from the registry since the previous spine block.
  • Snapshot manifests. For each recent snapshot of the main chain's state: the whole-file hash, the hash of every chunk, the reference height, an expiry and the main chain's genesis hash (see snapshots and fast sync).

The spine makes one block per spine_smithing_period: 86,400 seconds, one a day, on mainnet and testnet, and 3,600 seconds, one an hour, on devnet, where the checkpoint depth is 80 blocks (20 minutes).

A spine block opened into three compartments, checkpoint 760 below the tip, registry key changes and snapshot manifests, beside 11 seats of which 8 sign: two thirds.
A spine block opened into three compartments, checkpoint 760 below the tip, registry key changes and snapshot manifests, beside 11 seats of which 8 sign: two thirds.

Co-signed by two thirds of the seats

A spine block carries an aggregate signature: a 4-byte count followed, for each signer, by its 32-byte node key and its 64-byte Ed25519 signature, all over the same 204 header bytes. The block's hash is SHA3-256 of the header bytes and the whole signature field.

The number of signatures required is:

required = max(spine_min_signatures, ceil(n × 67 / 100))

where n is the size of the signer list. With 11 seats, 11 × 67 / 100 = 7.37, rounded up to 8. The rounding is upwards on purpose: 7 would be less than two thirds of 11.

The spine counts every seat on its signer list, suspended or not. It is the one two-thirds count in which suspended seats still count, so a checkpoint always speaks for two thirds of all seats (see two-thirds rules).

If too many seats are gone and the spine stalls, the bar relaxes in one step: after 3 spine periods with no stored spine block (3 days on mainnet), more than half is enough, 6 of 11. Neither bar may fall below spine_min_signatures, which is 5 on every chain. Requiring all 11 signatures would let a single missing seat stop the spine.

Two rings of 11 seats: normally at least 8 sign (two thirds, rounded up); after 3 periods without a spine block at least 6 (more than half); never below 5. Each signer first checks the key changes, the manifests, the reference depth and that it signs one block per height.
Two rings of 11 seats: normally at least 8 sign (two thirds, rounded up); after 3 periods without a spine block at least 6 (more than half); never below 5. Each signer first checks the key changes, the manifests, the reference depth and that it signs one block per height.

Signers check before they sign

A seat never signs blindly. Before co-signing a proposal, each signer checks that:

  • the key changes equal the changes in its own registry over the same range;
  • every manifest for its chain equals its own snapshot, hash for hash; a signer without the snapshot abstains;
  • the reference block is deep enough and does not go backwards;
  • it has not already co-signed a different block at that spine height.

When a node stores a spine block, it checks the content again, along with the producer draw and the block's difficulty.

Who proposes, and when

The spine's producer is drawn from the signer list: the signer at index LE64(SHA3-256(seed ‖ "spine" ‖ round)) mod n, where the seed is the main block's seed at the previous spine block's reference height, so every validator can repeat the draw. On mainnet a spine round lasts 100 seconds, the creation window is 300 seconds and the tolerance 150 seconds; a signer refuses a proposal older than its 60-second collection window. A spine block that comes earlier than the previous one plus the period, minus the tolerance, is refused.

Spine blocks are never empty. Between competing spines, the one with more signatures wins. A node weighs a competing spine before rolling anything back, never rolls its spine back below the release pin, and restores its own spine if the other one fails to apply.

What the spine is for

  • Finality. No node reorganises the main chain below the last stored spine checkpoint (see finality and rollback).
  • Fast sync. A new node syncs the spine first: its manifests say which snapshot to fetch, and its key changes say which node keys to trust (see snapshots and fast sync).

The spine is kept by every node, not by the Foundation, and nothing is traded on it.

See also