13. Consensus and validator membership

Draft protocolSource at 169cbd2 ↗Excerpt SHA-256 2fda2a0…0ee

Consensus orders blocks and produces the finalization certificates every proof in section 15 rests on. This chapter fixes the consensus wiring that two implementations must share, the epoch structure that paces membership change, the rules by which the validator set changes under DynamicReshareV1, and the custody obligations that attach to the one threshold identity the chain ever has. The consensus profile that selects between the two lifecycles is defined in section 5.

13.1 Consensus wiring

R-13.1. Consensus is Simplex with a BLS12-381 threshold VRF signing scheme under the N3f1 fault model, where f = ⌊(n − 1) / 3⌋ and quorum = n − f are derived from committee size and never from a chainspec field.

R-13.2. Leader election uses the VRF Random elector, version V1, with rotating terms, and term length is a consensus-critical surface (section 18).

R-13.3. A change to a stable-term RoundRobin elector activates under DynamicReshareV1 only through a qualified consensus-critical release, and under FixedEpochZeroV1 requires a reset (section 5).

R-13.4. track_historical_votes is true, with the library's AttributableReporter in front of the diagnostics and evidence pipeline.

R-13.5. Retained votes are observations and never transferable proof, and group finalization certificates are the evidence for finality and for settlement.

R-13.6. There is no automatic penalty.

R-13.7. The marshal variant is standard::Deferred, and a change to the coding marshal variant is a release coupled to the block byte limit of section 11.

R-13.8. A validator MUST NOT gossip commands to another validator.

Quorum sizes follow from the formula: n = 7 gives 5, n = 8 gives 6, and n = 10 gives 7. The spare fault at n = 7 exists only after counting every current fault. Retained votes live only until their rounds are pruned, network-reported votes are not verified before reaching a plain reporter, and threshold BLS partial signatures are not individually attributable, because enough partials forge any participant's partial, which the wrapper suppresses.

Leader terms, timeouts, and track_historical_votes are chainspec values (section 5), and their launch values and calibration items are listed in section 19. Gateway fan-out, the delivery floor that supports liveness, and the meaning of an admission acknowledgement are specified in operations.

13.2 Epochs

A height is a block number from genesis. Under DynamicReshareV1 an epoch is a fixed number of heights taken from the chainspec schedule, written blocks_per_epoch, and the boundary of an epoch E is the final block of epoch E − 1, which is the block that carries E's EpochInfo; epoch zero has no boundary block, and the genesis block carries its EpochInfo. Under FixedEpochZeroV1 only epoch zero exists: the epocher is FixedEpocher::new(NonZeroU64::MAX), and epoch zero covers heights 0..=u64::MAX - 1.

R-13.9. Under FixedEpochZeroV1, every round, proposal, vote, certificate, recovered block context, and certified ancestry relation MUST name epoch zero and agree with that epocher (section 11), and the engine boundary and every other caller MUST independently reject a nonzero epoch before scheme lookup or use, before signing, and before using a certificate.

ConstantProvider is not an authorization check, because it returns its one scheme for every requested scope.

R-13.10. A node MUST NOT derive retained_marshal_blocks, recovery horizons, or exporter retention from the u64::MAX fixed epoch length, and the ordinary marshal, stateful, proof, publication, and outage rules remain independently configured and enforced.

13.3 The validator schedule under DynamicReshareV1

Under DynamicReshareV1, membership is chain state. VALIDATOR_SET_SCHEDULE (section 8) is the only command that changes it. Launch bounds are command validity, not tooling policy, and depend only on chain state.

R-13.11. VALIDATOR_SET_SCHEDULE, authorized by the governance multisig, appends an immutable entry {target_epoch, participants (sorted), directory}.

R-13.12. An entry is invalid unless target_epoch ≥ current_epoch + 3, and at most one entry may be pending.

R-13.13. A pending entry is cancelable only by a pure cancel entry and only until lock-in: once the final block of target_epoch − 2 has embedded it as next_players, a cancel of that entry is deterministically invalid, lock-in is pinned to the state as of that block, and a cancel in that same block is ineligible.

R-13.14. Records follow the append-only pattern: added-at and deactivated-at epochs, one-way deactivation, public keys reserved forever, and proof of possession on add.

R-13.15. An entry is valid only if all of the following hold:

a. committee size lies in [7, 64]; b. it makes at most one addition and at most one removal for its epoch; c. it respects the fixed max_participants; d. every added key supplies a proof of possession; e. no carry-over is in effect (section 13.5).

R-13.16. Possession is a raw Ed25519 signature over BLAKE3("makechain.validator-possession" || chain_id || u64(target_epoch) || identity_key), supplied only by added identities, in identity order.

R-13.17. A participant record contains its Ed25519 identity, and never a separately invented per-validator threshold public key.

R-13.18. Nothing in validity refers to who is faulty or reachable, there is no on-chain fault set, and a liveness assessment is a governance and operator obligation before scheduling, never a consensus predicate.

R-13.19. A departing validator MUST keep dealing until a reshare excluding it is certified.

R-13.20. ParticipantsProvider::participants(epoch) reads the validator schedule as of the state committed by the final block of epoch − 2, the same block that locks the entry and after which a cancel of it is invalid, and never current state, because repeated calls for one epoch MUST return byte-identical sets.

R-13.21. directory(epoch, peers) returns addresses for exactly the peers it is handed, which the library computes as the union of the last successful output's players, the current next players, and the newly scheduled next players, so it is correct during a carry-over.

R-13.22. Both providers are deterministic and sorted, so every honest node embeds the same next_players.

R-13.23. Chainspec validation and startup MUST both assert two couplings the library does not check:

a. marshal retention, max_pending_acks + 1 + retained_marshal_blocks ≥ blocks_per_epoch; b. dealer-log slot capacity, blocks_per_epoch − (blocks_per_epoch / 2 + 1) ≥ max(dealer_quorum, previous_quorum).

INV-GOV-02. A validator-set entry is immutable except by pure cancel; at most one is pending; deactivation is one-way and public keys are reserved forever.

INV-GOV-06. A validator-set entry cannot be cancelled after the final block of target_epoch − 2 has embedded it.

INV-GOV-03. A departing validator remains dealing until a reshare excluding it is certified; membership taking effect and reshare success are distinct events.

13.4 The four sets and the effective voting set

Four sets are distinct and named.

Set What it is
Scheduled set the participants of a validator-set entry in chain state
Ceremony players EpochInfo.players, the participants of a reshare ceremony
Effective signer set the players of the last successful reshare output, which is what the voting scheme registers
Transport union the peers the directory serves, spanning current, scheduled, and departing validators together with the chainspec exporter roster (section 5)

R-13.24. A membership change is announced when it is scheduled, in effect for the ceremony when players advance, and effective for voting only when a reshare that includes the new member succeeds.

R-13.25. The effective voting set is the effective signer set, a scheduled change MUST NOT be treated as effective for voting before its reshare succeeds, and transport membership never determines voting membership.

R-13.26. Every quorum-dependent consumer uses the effective signer set, including consumers outside consensus (see operations).

The finalized events for those three moments are distinct (section 14).

INV-GOV-05. The effective voting set is the last successful reshare's players; a scheduled change is never treated as effective for voting before that.

13.5 Reshare and carry-over

A carry-over is the continued use of the previous epoch's threshold output when a reshare reports the library's Failure outcome.

R-13.27. Under DynamicReshareV1 a DKG reshare runs per epoch, carry-over of the previous output is permitted only on the Failure outcome, and any other divergence is fatal-local (section 12).

R-13.28. Every carry-over emits a finalized system event (section 14), whose emitting block is the boundary block that carries the EpochInfo recording that Failure outcome; escalation on consecutive carry-overs is an operator alert policy (section 19) and never an automatic halt, removal, or trust change.

R-13.29. A stray or mismatched ceremony payload is rejected on verification (section 11), the reshare wrapper compares the reconstructed boundary outcome against the block's payload, and verification stays pending while a following node lacks the ceremony history, which is transient inability and not invalidity (section 12).

R-13.30. Under DynamicReshareV1, validators install the per-epoch scheme of an epoch E from the EpochInfo carried by E's boundary block, the final block of E − 1, and under FixedEpochZeroV1 the genesis scheme is the only scheme.

R-13.31. Under DynamicReshareV1, a late joiner probes the chainspec bootstrap committee until f + 1 answer, takes the highest certified floor, and reads that epoch's boundary block.

R-13.32. A certified floor at or before the epoch midpoint lets a late joiner participate in that epoch's reshare, a later floor makes it a follower until the next boundary, and in either case it can sign ordinary blocks as soon as it holds a share.

R-13.33. A scheduled future validator MUST state-sync while it is still a next player.

R-13.34. The chainspec bootstrap list is updated by release (section 18), and an anchor supplied by a validator or read from the store is a recent finalization plus its EpochInfo, adopted only if its height is within max_anchor_age blocks of the highest certificate-verified finalization among the answers of f + 1 members of the chainspec bootstrap committee, f computed from that committee's size; a height reported without a certificate the joiner verifies is never such an answer, and max_anchor_age is a calibration item (section 19).

The carry-over escalation thresholds are fixed in section 19. Anchor freshness is weak subjectivity: a node started from a very old anchor trusts its operator's choice of anchor, and a stale bootstrap list reduces the freshness bound to that same weak subjectivity, because the f + 1 answers then need not include a current honest validator and can only under-report the tip.

13.6 Threshold identity and share custody

R-13.35. The group public key established at genesis is preserved under the selected profile: fixed for the life of a FixedEpochZeroV1 chain, and preserved by construction across every DynamicReshareV1 reshare and membership change, which the library asserts.

R-13.36. There is no in-band identity rotation, and a new group key means a new genesis and a new chain_id, which is a chain fork by definition (section 5).

Light clients never need private shares (section 15).

INV-GOV-04. The group public key is invariant across reshares and membership changes; a new key is a new chain.

Under DynamicReshareV1, share custody is operator-owned and outside the protocol, and the SecretStore contract below is binding.

R-13.37. Every share, dealer seed, and received dealing MUST be durable before its write resolves, because otherwise a dealer can equivocate on restart.

R-13.38. That material MUST NOT be written to protocol storage, carried on chain, or sent to peers.

R-13.39. A share lost after a successful epoch is unrecoverable by the protocol, and the validator waits to be re-dealt as a future player.

R-13.40. A share revealed by dealers because the player was offline is public and MUST be treated as public.

R-13.41. Operators MUST securely erase material that is no longer required by the effective output or by the bounded recovery path, only after the handoff to the successor share is durable, and MUST keep no long-lived backups of obsolete material.

R-13.42. During a carry-over the previous sharing remains effective and MUST be kept.

The invariant group key carries a lifetime assumption. A quorum of shares from any single past epoch can sign under the group identity forever, because a certificate verifier checks identity and namespace, not the current committee. Membership removal cannot revoke that, and a suspected historical quorum compromise is an incident whose only remedy is a new chain. A client's recent checkpoint bounds the history it will accept and does not prevent an old quorum from forging a fake successor, which is the accepted trust model at launch (section 4).

The library recovers a preceding share before it prunes, and its prune hook only forgets entries, so zeroization and media erasure are the operator's SecretStore implementation.

13.7 What each profile changes

Section 5 defines each profile, including its genesis threshold source and epoch construction, and section 18 states which release operations each profile admits; this table lists only the consensus consequences.

Aspect FixedEpochZeroV1 DynamicReshareV1
Committee exactly seven fixed validators, ordered by the chainspec 7 at genesis, bounds [7, 64]
VALIDATOR_SET_SCHEDULE every variant deterministically invalid governs membership per section 13.3
Reshare and carry-over none per epoch, with carry-over only on the Failure outcome
DKG block payloads all None in every block (section 11) used under the reshare rules of section 13.5
Per-epoch scheme genesis scheme only installed from each boundary block's EpochInfo
Committee, directory, output, or group-key change reset (section 5) schedule entry plus reshare

R-13.43. Under FixedEpochZeroV1, the chainspec's ordered seven-member committee and directory are the only scheduled set, ceremony set, and effective signing set, every VALIDATOR_SET_SCHEDULE variant is deterministically invalid for every payload and mutates no state, and no pending validator entry can exist in reachable state. Under every profile the transport set is that committee together with the chainspec exporter roster (section 5), which carries no scheduled, ceremony, or signing membership and never counts toward a quorum.

R-13.44. Retired; its content is R-5.30.

R-13.45. Under FixedEpochZeroV1, restart and rebootstrap MUST recover the identical fixed committee, public output, genesis binding, and local share identity.

13.8 Rationale

This subsection is informative.

Rotating leader terms and the VRF elector are the selected baseline. A stable term would not force an offline leader to stall the chain for a whole term, because participants vote to nullify the remaining views after a local stall timeout and a quorum certificate skips to the next term, but Random cannot use a term length greater than one and term length is consensus-critical, so stable terms remain a separate idea. Historical votes are tracked so misbehaviour is attributable.

Membership under DynamicReshareV1 is governed and dynamic because a fixed set makes every operator change a new chain. The three-epoch lead follows the participant lock-in the DKG primitive requires, one change per epoch keeps every reshare bounded, and seven is the smallest committee with a spare fault during a one-member replacement. The group key's invariance is what makes a single trust anchor sufficient for light clients.