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 (9)
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 (12)
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 (12)
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 (3)
Jun 06, 3-4 AM (4)
Jun 06, 4-5 AM (0)
Jun 06, 5-6 AM (24)
Jun 06, 6-7 AM (1)
Jun 06, 7-8 AM (2)
Jun 06, 8-9 AM (3)
Jun 06, 9-10 AM (0)
Jun 06, 10-11 AM (3)
Jun 06, 11-12 PM (6)
Jun 06, 12-1 PM (2)
Jun 06, 1-2 PM (2)
Jun 06, 2-3 PM (2)
Jun 06, 3-4 PM (18)
Jun 06, 4-5 PM (1)
Jun 06, 5-6 PM (6)
Jun 06, 6-7 PM (0)
Jun 06, 7-8 PM (6)
Jun 06, 8-9 PM (0)
Jun 06, 9-10 PM (1)
Jun 06, 10-11 PM (27)
Jun 06, 11-12 AM (9)
Jun 07, 12-1 AM (14)
Jun 07, 1-2 AM (2)
Jun 07, 2-3 AM (0)
Jun 07, 3-4 AM (0)
Jun 07, 4-5 AM (1)
Jun 07, 5-6 AM (1)
Jun 07, 6-7 AM (3)
Jun 07, 7-8 AM (0)
Jun 07, 8-9 AM (0)
Jun 07, 9-10 AM (1)
Jun 07, 10-11 AM (2)
Jun 07, 11-12 PM (2)
Jun 07, 12-1 PM (5)
Jun 07, 1-2 PM (35)
Jun 07, 2-3 PM (2)
Jun 07, 3-4 PM (4)
Jun 07, 4-5 PM (2)
Jun 07, 5-6 PM (4)
Jun 07, 6-7 PM (0)
Jun 07, 7-8 PM (0)
Jun 07, 8-9 PM (17)
Jun 07, 9-10 PM (1)
Jun 07, 10-11 PM (21)
Jun 07, 11-12 AM (9)
Jun 08, 12-1 AM (9)
Jun 08, 1-2 AM (5)
Jun 08, 2-3 AM (3)
Jun 08, 3-4 AM (4)
Jun 08, 4-5 AM (2)
Jun 08, 5-6 AM (9)
Jun 08, 6-7 AM (5)
Jun 08, 7-8 AM (25)
Jun 08, 8-9 AM (36)
Jun 08, 9-10 AM (40)
Jun 08, 10-11 AM (24)
Jun 08, 11-12 PM (22)
Jun 08, 12-1 PM (40)
Jun 08, 1-2 PM (48)
Jun 08, 2-3 PM (33)
Jun 08, 3-4 PM (27)
Jun 08, 4-5 PM (12)
Jun 08, 5-6 PM (23)
Jun 08, 6-7 PM (14)
Jun 08, 7-8 PM (3)
Jun 08, 8-9 PM (6)
Jun 08, 9-10 PM (19)
Jun 08, 10-11 PM (29)
Jun 08, 11-12 AM (8)
Jun 09, 12-1 AM (5)
Jun 09, 1-2 AM (3)
Jun 09, 2-3 AM (1)
Jun 09, 3-4 AM (3)
Jun 09, 4-5 AM (26)
Jun 09, 5-6 AM (5)
Jun 09, 6-7 AM (23)
Jun 09, 7-8 AM (50)
Jun 09, 8-9 AM (35)
Jun 09, 9-10 AM (45)
Jun 09, 10-11 AM (51)
Jun 09, 11-12 PM (44)
Jun 09, 12-1 PM (86)
Jun 09, 1-2 PM (67)
Jun 09, 2-3 PM (36)
Jun 09, 3-4 PM (38)
Jun 09, 4-5 PM (15)
Jun 09, 5-6 PM (17)
Jun 09, 6-7 PM (18)
Jun 09, 7-8 PM (19)
Jun 09, 8-9 PM (14)
Jun 09, 9-10 PM (1)
2,774 commits this week Jun 02, 2026 - Jun 09, 2026
feat(governance): in-app Ekklesia/Hydra budget voting for multisig DRep (#272)
Adds an off-chain DRep voting flow for the Intersect Cardano Budget 2026
ballot, which runs on Ekklesia/Hydra (L2) via CIP-8 signed messages rather
than on-chain CIP-1694 actions. Multisig DReps are supported: each signer
co-signs the same vote package and Ekklesia aggregates at threshold.

- API spec reverse-engineered from the live API + frontend bundle (the
  published docs are JS-rendered); captured in src/lib/ekklesia/SPEC.md
- Server proxy (src/pages/api/ekklesia/[...path].ts) — CORS blocks direct
  browser calls; forwards auth + cookies
- Typed client + orchestration (src/lib/ekklesia/{types,client,voteFlow}.ts),
  reusing the signable subsystem for multi-signer coordination
- HydraBudgetVote UI + page + governance-hub entry
- EKKLESIA_API_BASE env var

Note: per-signer CIP-95 DRep-key signing and the multisig session binding
need verification against a live multisig DRep wallet before relying on it
for the June 12 deadline; manual voting via Ekklesia's CardanoSigner is the
fallback.

Co-authored-by: Claude Opus 4.8 <[email protected]>
feat(leios): implement stake-truncated committee voting and stake quorum (#2509)
* 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]>

* 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]>

* fix(leios): decouple vote dedup ledger from serving-store eviction

The vote manager deduplicated votes against the size-capped serving
store while tallies lived on their own TTL. A vote re-received after
its serving entry was evicted (reconnecting peers re-serve their full
log) re-counted its stake into a still-live tally and appended a
duplicate voter id to the verified set, after which BuildEbCertificate
failed on the duplicate forever and the endorser block became
permanently un-certifiable. Post-eviction equivocation was likewise
accepted as fresh, and the tally map was unbounded under fabricated
vote floods in lenient mode.

- Add a voteRecord ledger as the authoritative dedup and
  tally-accounting state, decoupled from serving-store eviction.
  Records are pruned only in lockstep with their endorser block's
  tally (TTL), by epoch at transitions, and by slot on rollbacks, so
  re-delivered votes never re-count and first-wins equivocation
  detection stays durable. The ledger is capacity-capped with
  reject-new semantics (evicting a record would reintroduce the
  re-count); locally emitted votes bypass the cap. The cap
  transitively bounds the tally map.
- Window incoming vote slots against the current (or tip) slot before
  any epoch or committee work. EpochForSlot projects future slots
  indefinitely, so fabricated far-past/future votes previously reached
  stake-snapshot database queries and bloated the committee memo. The
  bounds are provisional pending CIP-0164's L_vote. LedgerState
  satisfies the new SlotProvider directly; a nil provider disables the
  check. The local emission path shares the window so the node does
  not sign votes peers would reject.
- Document the proof-of-possession invariant on BLS aggregate
  verification and the voter registry as its trust root: rogue-key
  attacks make summed-pubkey verification forgeable without it.
- Add a vote-record gauge, slot_window/capacity reject reasons, and
  regression tests covering re-count after size eviction and TTL
  expiry, durable equivocation, capacity semantics, the slot window,
  and rollback re-votes. The re-count tests fail against the previous
  dedup logic.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Signed-off-by: Chris Guiney <[email protected]>

* fix(leios): exempt verified votes from record admission cap

The vote record ledger's capacity cap applied to every peer vote, so
in partially-registered lenient mode an attacker could fill it with
fabricated unverified votes (committee members without registered keys
need no valid signature) and starve subsequent verified votes -- the
only ones that feed verified stake and certificates -- stalling
certification of new endorser blocks for the duration of a flood.

Verified votes now bypass the cap: each requires a valid BLS signature
from a registered committee key and dedup bounds them to one record
per (slot, registered voter) inside the slot window, so their record
growth is protocol-bounded without the cap. The cap keeps gating
unverified peer votes, whose only effect is observed-stake visibility.
Identified by cubic on the previous commit.

The capacity regression test now fills the ledger with unverified
votes (the only kind still subject to the cap), and a new test pins
the bypass: a verified vote is admitted past a full ledger while
unverified votes remain rejected.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Signed-off-by: Chris Guiney <[email protected]>

---------

Signed-off-by: Chris Guiney <[email protected]>
Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
feat(governance): in-app Ekklesia/Hydra budget voting for multisig DRep
Adds an off-chain DRep voting flow for the Intersect Cardano Budget 2026
ballot, which runs on Ekklesia/Hydra (L2) via CIP-8 signed messages rather
than on-chain CIP-1694 actions. Multisig DReps are supported: each signer
co-signs the same vote package and Ekklesia aggregates at threshold.

- API spec reverse-engineered from the live API + frontend bundle (the
  published docs are JS-rendered); captured in src/lib/ekklesia/SPEC.md
- Server proxy (src/pages/api/ekklesia/[...path].ts) — CORS blocks direct
  browser calls; forwards auth + cookies
- Typed client + orchestration (src/lib/ekklesia/{types,client,voteFlow}.ts),
  reusing the signable subsystem for multi-signer coordination
- HydraBudgetVote UI + page + governance-hub entry
- EKKLESIA_API_BASE env var

Note: per-signer CIP-95 DRep-key signing and the multisig session binding
need verification against a live multisig DRep wallet before relying on it
for the June 12 deadline; manual voting via Ekklesia's CardanoSigner is the
fallback.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
diag: instrument ballot vote witness/body-hash divergence (#271)
Add diagnostic-only logging (no behaviour change) to pinpoint the
`InvalidWitnessesUTXOW` rejection seen when submitting legacy-DRep ballot
votes. Conway `voting_procedures` bodies are re-encoded by some wallets,
so a vkey witness ends up signed over a different body hash than the one
reaching the node.

Three [ballot-witness-diag] log points:
- txScriptRecovery: new diagnoseTxWitnesses() verifies every vkey witness
  against the exact body being submitted, logging any stale witness (with
  pubkey/keyhash) right before submitTx. Covers both signing paths.
- txSignUtils.mergeSignerWitnesses: logs wallet body re-canonicalisation,
  distinguishing first-signer (body adopted) from co-signer (swap skipped,
  witness may be stale).
- api/v1/signTransaction: logs when merge/rebuild changes the body hash the
  collected signatures were made over.

Co-authored-by: Claude Opus 4.8 <[email protected]>
chore(deps-dev): bump tailwindcss from 3.4.19 to 4.3.0
Bumps [tailwindcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss) from 3.4.19 to 4.3.0.
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.3.0/packages/tailwindcss)

---
updated-dependencies:
- dependency-name: tailwindcss
  dependency-version: 4.3.0
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>