May 30, 2-3 AM (1)
May 30, 3-4 AM (7)
May 30, 4-5 AM (2)
May 30, 5-6 AM (11)
May 30, 6-7 AM (0)
May 30, 7-8 AM (2)
May 30, 8-9 AM (11)
May 30, 9-10 AM (13)
May 30, 10-11 AM (10)
May 30, 11-12 PM (5)
May 30, 12-1 PM (8)
May 30, 1-2 PM (5)
May 30, 2-3 PM (18)
May 30, 3-4 PM (5)
May 30, 4-5 PM (1)
May 30, 5-6 PM (9)
May 30, 6-7 PM (9)
May 30, 7-8 PM (1)
May 30, 8-9 PM (5)
May 30, 9-10 PM (4)
May 30, 10-11 PM (27)
May 30, 11-12 AM (12)
May 31, 12-1 AM (17)
May 31, 1-2 AM (0)
May 31, 2-3 AM (1)
May 31, 3-4 AM (1)
May 31, 4-5 AM (0)
May 31, 5-6 AM (0)
May 31, 6-7 AM (7)
May 31, 7-8 AM (4)
May 31, 8-9 AM (10)
May 31, 9-10 AM (3)
May 31, 10-11 AM (4)
May 31, 11-12 PM (4)
May 31, 12-1 PM (1)
May 31, 1-2 PM (2)
May 31, 2-3 PM (24)
May 31, 3-4 PM (16)
May 31, 4-5 PM (2)
May 31, 5-6 PM (1)
May 31, 6-7 PM (2)
May 31, 7-8 PM (2)
May 31, 8-9 PM (2)
May 31, 9-10 PM (7)
May 31, 10-11 PM (25)
May 31, 11-12 AM (11)
Jun 01, 12-1 AM (14)
Jun 01, 1-2 AM (7)
Jun 01, 2-3 AM (3)
Jun 01, 3-4 AM (10)
Jun 01, 4-5 AM (13)
Jun 01, 5-6 AM (16)
Jun 01, 6-7 AM (10)
Jun 01, 7-8 AM (14)
Jun 01, 8-9 AM (46)
Jun 01, 9-10 AM (50)
Jun 01, 10-11 AM (19)
Jun 01, 11-12 PM (27)
Jun 01, 12-1 PM (49)
Jun 01, 1-2 PM (40)
Jun 01, 2-3 PM (44)
Jun 01, 3-4 PM (34)
Jun 01, 4-5 PM (54)
Jun 01, 5-6 PM (5)
Jun 01, 6-7 PM (32)
Jun 01, 7-8 PM (37)
Jun 01, 8-9 PM (9)
Jun 01, 9-10 PM (12)
Jun 01, 10-11 PM (30)
Jun 01, 11-12 AM (22)
Jun 02, 12-1 AM (13)
Jun 02, 1-2 AM (8)
Jun 02, 2-3 AM (5)
Jun 02, 3-4 AM (14)
Jun 02, 4-5 AM (10)
Jun 02, 5-6 AM (43)
Jun 02, 6-7 AM (32)
Jun 02, 7-8 AM (58)
Jun 02, 8-9 AM (65)
Jun 02, 9-10 AM (28)
Jun 02, 10-11 AM (19)
Jun 02, 11-12 PM (15)
Jun 02, 12-1 PM (47)
Jun 02, 1-2 PM (66)
Jun 02, 2-3 PM (97)
Jun 02, 3-4 PM (23)
Jun 02, 4-5 PM (15)
Jun 02, 5-6 PM (27)
Jun 02, 6-7 PM (29)
Jun 02, 7-8 PM (18)
Jun 02, 8-9 PM (9)
Jun 02, 9-10 PM (19)
Jun 02, 10-11 PM (33)
Jun 02, 11-12 AM (22)
Jun 03, 12-1 AM (13)
Jun 03, 1-2 AM (31)
Jun 03, 2-3 AM (16)
Jun 03, 3-4 AM (0)
Jun 03, 4-5 AM (7)
Jun 03, 5-6 AM (12)
Jun 03, 6-7 AM (80)
Jun 03, 7-8 AM (16)
Jun 03, 8-9 AM (24)
Jun 03, 9-10 AM (22)
Jun 03, 10-11 AM (39)
Jun 03, 11-12 PM (76)
Jun 03, 12-1 PM (93)
Jun 03, 1-2 PM (28)
Jun 03, 2-3 PM (62)
Jun 03, 3-4 PM (26)
Jun 03, 4-5 PM (24)
Jun 03, 5-6 PM (23)
Jun 03, 6-7 PM (15)
Jun 03, 7-8 PM (17)
Jun 03, 8-9 PM (19)
Jun 03, 9-10 PM (8)
Jun 03, 10-11 PM (31)
Jun 03, 11-12 AM (14)
Jun 04, 12-1 AM (12)
Jun 04, 1-2 AM (4)
Jun 04, 2-3 AM (1)
Jun 04, 3-4 AM (5)
Jun 04, 4-5 AM (1)
Jun 04, 5-6 AM (0)
Jun 04, 6-7 AM (14)
Jun 04, 7-8 AM (10)
Jun 04, 8-9 AM (11)
Jun 04, 9-10 AM (19)
Jun 04, 10-11 AM (11)
Jun 04, 11-12 PM (14)
Jun 04, 12-1 PM (53)
Jun 04, 1-2 PM (39)
Jun 04, 2-3 PM (60)
Jun 04, 3-4 PM (12)
Jun 04, 4-5 PM (4)
Jun 04, 5-6 PM (7)
Jun 04, 6-7 PM (46)
Jun 04, 7-8 PM (27)
Jun 04, 8-9 PM (4)
Jun 04, 9-10 PM (2)
Jun 04, 10-11 PM (24)
Jun 04, 11-12 AM (7)
Jun 05, 12-1 AM (6)
Jun 05, 1-2 AM (8)
Jun 05, 2-3 AM (1)
Jun 05, 3-4 AM (1)
Jun 05, 4-5 AM (1)
Jun 05, 5-6 AM (5)
Jun 05, 6-7 AM (9)
Jun 05, 7-8 AM (9)
Jun 05, 8-9 AM (8)
Jun 05, 9-10 AM (11)
Jun 05, 10-11 AM (12)
Jun 05, 11-12 PM (8)
Jun 05, 12-1 PM (52)
Jun 05, 1-2 PM (61)
Jun 05, 2-3 PM (26)
Jun 05, 3-4 PM (24)
Jun 05, 4-5 PM (17)
Jun 05, 5-6 PM (7)
Jun 05, 6-7 PM (14)
Jun 05, 7-8 PM (10)
Jun 05, 8-9 PM (6)
Jun 05, 9-10 PM (2)
Jun 05, 10-11 PM (20)
Jun 05, 11-12 AM (9)
Jun 06, 12-1 AM (6)
Jun 06, 1-2 AM (0)
Jun 06, 2-3 AM (0)
3,040 commits this week May 30, 2026 - Jun 06, 2026
fix(leios): address review-bot findings
- ComputeCommittee now errors when the coverage target is unreachable
  (pool stake sum below sigma_c of total active stake) instead of
  returning a partial committee
- NewVoterRegistry rejects non-28-byte pool key hashes and duplicate
  entries that normalize to the same pool hash
- LoadVoteSigningKeyFile rejects oversized key files instead of
  silently truncating, and reuses keystore.CheckOpenFilePermissions
  (newly exported) so Windows gets the real DACL check instead of a
  no-op; the leios-local permission shims are removed
- VerifyVoteSignature subgroup-checks the public key for callers
  outside the package
- Vote store prunes expired entries before the dedup check so a stale
  vote id cannot block a fresh vote after TTL
- NextVotes persists the per-connection cursor only on successful
  delivery so aborted waits do not skip undelivered votes
- WithLeiosVoterPublicKeys copies the caller's map

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Signed-off-by: Chris Guiney <[email protected]>
feat(leios): implement stake-truncated committee voting and stake quorum
Implement the CIP-0164 (post cardano-foundation/CIPs#1196) stake-based
voting committee model in a new ledger/leios package:

- Committee selection: order pools by active stake descending (pool key
  hash ascending on ties), select until cumulative coverage reaches the
  CommitteeStakeCoverage (sigma_c) parameter, and assign stable voter_id
  indexes. The committee derives from the same epoch-2 stake snapshot
  cadence as Praos leader election and is memoized in memory.
- Stake quorum: votes must represent at least QuorumStakeThreshold (tau)
  of total active stake, evaluated with exact rational arithmetic. The
  tau < sigma_c invariant is revalidated wherever parameters are read.
- Votes: one uniform vote per endorser block per voter (slot_no, EB
  hash, voter_id, BLS signature). Real BLS12-381 MinSig sign/verify/
  aggregate via gnark-crypto, with lenient verification pending CIP-0164
  key registration: a static config registry (leiosVoterPublicKeys)
  supplies voter public keys, and votes from unknown voters count toward
  observed stake but never toward certificates.
- Certificates: signers bitfield plus one aggregated BLS signature
  (gouroboros LeiosEbCertificate), built only from verified votes once
  verified stake meets tau, announced via a new leios.eb_quorum event.
  Validation is exposed but not yet wired into block validation; the
  Dijkstra CDDL leios_cert slot is still an upstream placeholder.
- VoteManager: TTL-bounded in-memory vote store with per-(slot, voter)
  dedup (first vote wins on equivocation), per-connection serving
  cursors for the exactly-count LeiosVotes protocol semantics, local
  vote emission for block producers with a leiosVoteSigningKeyFile, and
  pruning on chain rollbacks and epoch transitions.

The LeiosVotes/LeiosFetch protocol handlers now delegate to the vote
manager through a LeiosVoteHandler interface, the LeiosVotes client is
started on outbound connections, and storing an endorser block triggers
local vote emission.

Fixes #2424

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Signed-off-by: Chris Guiney <[email protected]>
Leios: late-join out-of-order CertRB sweep
Add the child-before-parent handling to leiosAddBlockListener. Two ChainSync
clients can interleave their AddBlock writes, so a CertRB can enter chain
selection before the RB that announced its EB. When that happens the CertRB's
own listener pass finds no cached announcement and cannot read the EB hash to
hold it back, so the block would be selected with a closure it does not have.

A new reverse index, certRbsByAnnouncer, maps an announcer's header hash to the
CertRB children that certify the EB it announced, kept only for CertRBs whose
announcer had not been added when they arrived. recordIfOrphan files such a
CertRB there. When its announcer is later added, sweepOrphanedCertRbs reads the
entry, drops it, and holds each child back if the announced EB's closure is
still missing. The listener runs the sweep for every block, since any block may
be an announcer.

The map holds only CertRBs whose announcer has not arrived yet: the entry is
dropped as soon as the announcer is added, and once the announcer is cached its
later children take the direct path. gcPruner does not touch it.

This changes no behaviour: nothing registers the listener yet. The
ouroboros-consensus library builds under -Werror.
Leios: late-join AddBlock listener body
Add leiosAddBlockListener, the per-block bookkeeping update for the late-join
feature. ChainDB will run it synchronously, in STM scope, between writing a
block to the VolatileDB and running chain selection on it. Sharing the
transaction that adds the block closes the window an asynchronous listener would
leave: there is no moment when the block is in the VolatileDB but absent from
this state, so a closure arriving "in between" cannot strand the block.

For every block the listener records the slot and announced EB point in
headerAnnouncementsCache. For a CertRB whose certified EB closure is not yet
local, it adds the block to announcementsMap so getBlockedCertRBs holds it back.
The certified EB hash comes from the parent's cached announcement, not from the
block itself: a CertRB certifies the EB its parent announced (CIP-0164).

Two helpers carry the work: parentAnnouncement reads the parent's announced EB
hash from a cache snapshot, and blockCertRbIfClosureMissing inserts into
announcementsMap only when the closure is still missing.

This changes no behaviour: nothing registers the listener yet, so it does not
run. The ouroboros-consensus library builds under -Werror.