Home /
Input Output /
ouroboros-leios-sim
Jun 07, 3-4 PM (0)
Jun 07, 4-5 PM (0)
Jun 07, 5-6 PM (0)
Jun 07, 6-7 PM (0)
Jun 07, 7-8 PM (0)
Jun 07, 8-9 PM (0)
Jun 07, 9-10 PM (0)
Jun 07, 10-11 PM (0)
Jun 07, 11-12 AM (0)
Jun 08, 12-1 AM (0)
Jun 08, 1-2 AM (0)
Jun 08, 2-3 AM (0)
Jun 08, 3-4 AM (0)
Jun 08, 4-5 AM (0)
Jun 08, 5-6 AM (0)
Jun 08, 6-7 AM (0)
Jun 08, 7-8 AM (0)
Jun 08, 8-9 AM (0)
Jun 08, 9-10 AM (8)
Jun 08, 10-11 AM (0)
Jun 08, 11-12 PM (0)
Jun 08, 12-1 PM (0)
Jun 08, 1-2 PM (0)
Jun 08, 2-3 PM (0)
Jun 08, 3-4 PM (0)
Jun 08, 4-5 PM (0)
Jun 08, 5-6 PM (0)
Jun 08, 6-7 PM (0)
Jun 08, 7-8 PM (0)
Jun 08, 8-9 PM (0)
Jun 08, 9-10 PM (0)
Jun 08, 10-11 PM (0)
Jun 08, 11-12 AM (0)
Jun 09, 12-1 AM (0)
Jun 09, 1-2 AM (0)
Jun 09, 2-3 AM (0)
Jun 09, 3-4 AM (0)
Jun 09, 4-5 AM (0)
Jun 09, 5-6 AM (0)
Jun 09, 6-7 AM (2)
Jun 09, 7-8 AM (2)
Jun 09, 8-9 AM (1)
Jun 09, 9-10 AM (1)
Jun 09, 10-11 AM (0)
Jun 09, 11-12 PM (1)
Jun 09, 12-1 PM (0)
Jun 09, 1-2 PM (1)
Jun 09, 2-3 PM (0)
Jun 09, 3-4 PM (0)
Jun 09, 4-5 PM (0)
Jun 09, 5-6 PM (1)
Jun 09, 6-7 PM (0)
Jun 09, 7-8 PM (0)
Jun 09, 8-9 PM (0)
Jun 09, 9-10 PM (0)
Jun 09, 10-11 PM (0)
Jun 09, 11-12 AM (0)
Jun 10, 12-1 AM (0)
Jun 10, 1-2 AM (0)
Jun 10, 2-3 AM (0)
Jun 10, 3-4 AM (0)
Jun 10, 4-5 AM (0)
Jun 10, 5-6 AM (0)
Jun 10, 6-7 AM (0)
Jun 10, 7-8 AM (0)
Jun 10, 8-9 AM (0)
Jun 10, 9-10 AM (6)
Jun 10, 10-11 AM (9)
Jun 10, 11-12 PM (9)
Jun 10, 12-1 PM (0)
Jun 10, 1-2 PM (0)
Jun 10, 2-3 PM (0)
Jun 10, 3-4 PM (0)
Jun 10, 4-5 PM (0)
Jun 10, 5-6 PM (0)
Jun 10, 6-7 PM (0)
Jun 10, 7-8 PM (0)
Jun 10, 8-9 PM (1)
Jun 10, 9-10 PM (0)
Jun 10, 10-11 PM (0)
Jun 10, 11-12 AM (0)
Jun 11, 12-1 AM (0)
Jun 11, 1-2 AM (0)
Jun 11, 2-3 AM (0)
Jun 11, 3-4 AM (0)
Jun 11, 4-5 AM (0)
Jun 11, 5-6 AM (0)
Jun 11, 6-7 AM (0)
Jun 11, 7-8 AM (0)
Jun 11, 8-9 AM (0)
Jun 11, 9-10 AM (0)
Jun 11, 10-11 AM (0)
Jun 11, 11-12 PM (0)
Jun 11, 12-1 PM (0)
Jun 11, 1-2 PM (0)
Jun 11, 2-3 PM (0)
Jun 11, 3-4 PM (0)
Jun 11, 4-5 PM (0)
Jun 11, 5-6 PM (0)
Jun 11, 6-7 PM (0)
Jun 11, 7-8 PM (5)
Jun 11, 8-9 PM (3)
Jun 11, 9-10 PM (0)
Jun 11, 10-11 PM (0)
Jun 11, 11-12 AM (0)
Jun 12, 12-1 AM (0)
Jun 12, 1-2 AM (0)
Jun 12, 2-3 AM (0)
Jun 12, 3-4 AM (0)
Jun 12, 4-5 AM (0)
Jun 12, 5-6 AM (0)
Jun 12, 6-7 AM (0)
Jun 12, 7-8 AM (0)
Jun 12, 8-9 AM (0)
Jun 12, 9-10 AM (0)
Jun 12, 10-11 AM (0)
Jun 12, 11-12 PM (0)
Jun 12, 12-1 PM (0)
Jun 12, 1-2 PM (0)
Jun 12, 2-3 PM (0)
Jun 12, 3-4 PM (0)
Jun 12, 4-5 PM (0)
Jun 12, 5-6 PM (0)
Jun 12, 6-7 PM (0)
Jun 12, 7-8 PM (0)
Jun 12, 8-9 PM (0)
Jun 12, 9-10 PM (0)
Jun 12, 10-11 PM (0)
Jun 12, 11-12 AM (0)
Jun 13, 12-1 AM (0)
Jun 13, 1-2 AM (0)
Jun 13, 2-3 AM (0)
Jun 13, 3-4 AM (0)
Jun 13, 4-5 AM (0)
Jun 13, 5-6 AM (0)
Jun 13, 6-7 AM (0)
Jun 13, 7-8 AM (0)
Jun 13, 8-9 AM (0)
Jun 13, 9-10 AM (0)
Jun 13, 10-11 AM (0)
Jun 13, 11-12 PM (0)
Jun 13, 12-1 PM (0)
Jun 13, 1-2 PM (0)
Jun 13, 2-3 PM (0)
Jun 13, 3-4 PM (0)
Jun 13, 4-5 PM (0)
Jun 13, 5-6 PM (0)
Jun 13, 6-7 PM (0)
Jun 13, 7-8 PM (0)
Jun 13, 8-9 PM (0)
Jun 13, 9-10 PM (0)
Jun 13, 10-11 PM (0)
Jun 13, 11-12 AM (0)
Jun 14, 12-1 AM (0)
Jun 14, 1-2 AM (0)
Jun 14, 2-3 AM (0)
Jun 14, 3-4 AM (0)
Jun 14, 4-5 AM (0)
Jun 14, 5-6 AM (0)
Jun 14, 6-7 AM (0)
Jun 14, 7-8 AM (0)
Jun 14, 8-9 AM (0)
Jun 14, 9-10 AM (0)
Jun 14, 10-11 AM (0)
Jun 14, 11-12 PM (0)
Jun 14, 12-1 PM (0)
Jun 14, 1-2 PM (0)
Jun 14, 2-3 PM (0)
Jun 14, 3-4 PM (0)
50 commits this week
Jun 07, 2026
-
Jun 14, 2026
Unify usage of ghc 9.10.3
Split the monolithic cabal.project into per-cluster Haskell projects
Each Haskell cluster (simulation, leios-trace-hs, leios-trace-verifier, trace-processor, leios-deltaq, betti0) now owns its own cabal.project and its own haskell.nix project scoped to just its subtree, exposed lazily under legacyPackages.<cluster>. The previous setup snapshot the whole repo as haskell.nix source, so any edit invalidated every cluster's plan and IFD ran on every nix develop; now eval inputs are bounded per cluster, dev shells are plain mkShell decoupled from haskell.nix (~10s entry), and clusters can drift their pins independently. Cross-cluster source deps (simulation, leios-trace-verifier both consume leios-trace-hs) use lib.fileset.toSource + cabalProjectFileName so the existing ../leios-trace-hs paths resolve naturally. iogx is dropped; flake-parts drives the flake directly with haskell-nix and CHaP as top-level inputs. CI now scopes to the simulation cluster. Co-Authored-By: Claude Opus 4.7 <[email protected]>
deploy: 32d13711ff7ba331da9a96ecc15dbe5ca0c6048a
Merge pull request #883 from input-output-hk/ch1bo/leios-voting
Prototype: Voting UI updates
Regenerate schema from types
Stub out sim-rs/net-rs/shared-rs after move to leios-tools
These three Rust workspaces now live in their own repository, cardano-scaling/leios-tools, extracted with full git history. Replace each directory's contents with a short README pointing at the new home, and remove the now-orphaned build/CI that referenced the deleted source: - .github/workflows/sim-rs.yaml — built sim-rs (moved). - .github/workflows/conformance-linear.yaml — built sim-rs and ran the linear conformance check against sim-rs/parameters (moved). - .github/workflows/net-node-docker.yaml — built the net-node docker image from net-rs/ + shared-rs/ (moved; docker CI lives in leios-tools). - Dockerfile — drop the Rust build stage (rs-builder) and the `rs` target image that compiled sim-cli from sim-rs/. The Haskell `hs` image is unchanged. Stale prose/comment references remain in .dockerignore, topology-viewer/scripts/build-viewer-data.py, and a couple of config comments; left untouched here as they don't break the build. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
net-node: correct follow-dev-relay usage snippet config paths
The configs live under net-node/configs/, but the snippet wrote just configs/...; running it from the net-rs/ workspace root (the canonical location per CLAUDE.md) would fail to find the files. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
praos: fix stuck-rollup parent check + clean up per-peer state
- maybe_emit_stuck_warning was counting any peer-chain parent missing from adopted_ancestors as "unreachable", but the diagnostic doc says "neither in chain_tree nor block_cache". A peer chain that forks off into a branch we hold but haven't adopted would false-positive the WARN. Check the whole chain_tree (every fork we know about) instead. - record_peer_disconnected wasn't removing the per-peer last_gap_warning_at throttle entry, so the map grew without bound under reconnect churn if PeerIds are monotonically assigned. Same lifecycle as the orphan cooldown that already gets cleared here. - Drop a duplicate `#[allow(clippy::too_many_arguments)]` on on_tip_advanced (one was enough). Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
behaviour: short-circuit DropInboundPeers at probability >= 1.0
`u64 / u64::MAX as f64` lands in [0, 1] inclusive: `u64::MAX as f64` rounds to 2^64, and a hash equal to u64::MAX yields a draw of exactly 1.0. The `draw < probability` test then refused to drop on that one-in-2^64 hash even when the operator asked for "always drop" semantics with probability=1.0. Mirror the `probability <= 0.0` short-circuit at the top of the function so probability=1.0 unconditionally returns true, and fix the comment to say [0, 1] rather than [0, 1). Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
sim-core: clear pre-existing clippy 1.92 lints
- tcp_connection.rs: `mem::replace(_, Default::default())` → `mem::take`. - config.rs: `for (_, spec) in &out` → `for spec in out.values()`. - network/connection.rs: allow `clippy::large_enum_variant` on `ConnectionKind` — the two variants share a uniform interface and Box-ing the TCP variant would add an indirection on every connection access in the sim hot path. Also allow `clippy::items_after_test_module` on the file's `mod tests` block; `ConnectionKind` legitimately lives after it and moving the 400-line test module to the file end would be pure churn. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
net-cluster: clear pre-existing clippy 1.92 lints
- aggregator.rs: drop `len.clone()` on a `usize` (Copy). - server.rs: allow `clippy::too_many_arguments` on `start()`; the nine args are all distinct top-level cluster wiring (port, channels, shared state) and grouping them into a config struct would be churn for marginal benefit. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
shared-consensus: clear pre-existing clippy 1.92 lints
- t22.rs: dedent inline list items to 2 spaces (overindented); drop the redundant `let decision = …; decision` binding (`needless_return`). - praos.rs: rewrap PraosStateSizes equivocation_bytes_estimate doc so the list bullet sits flush with the prose. - behaviour/selection.rs: replace `out.get(&2).is_none()` with `!out.contains_key(&2)` (`unnecessary_get_then_check`). Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
shared-rs: apply cargo fmt
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
net-rs: apply cargo fmt
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
clippy: use `.is_multiple_of()` instead of manual `% N == 0`
Clippy 1.92 lints the manual form; introduced on this branch via DeepReorg behaviour and net-node's state-size log gate. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
net-core: log the resolved peer IP per connection
Carry the concrete socket address the TCP connection landed on
(`resolved_addr`) on `Connection`/`DuplexConnection`, and log it with
the peer_id at connect time:
peer connected (duplex) peer_id=peer-0
host=leios-node.play.dev.cardano.org:3001 resolved_ip=52.29.179.71:3001
The host is often a round-robin DNS name, so each (re)connection can
land on a different backend. Since the per-peer Leios trace logs are
keyed by peer_id, this one line lets a given EB's activity be
attributed to the specific IP that served it.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
net: align LeiosFetch with the prototype CDDL
Bring the LeiosFetch mini-protocol up to the cardano-blueprint
leios-prototype CDDL, fixing the live `leios_fetch block: expected
bytes, got map` disconnect when fetching an EB from the dev relay.
Wire changes:
- msgLeiosBlock = [1, endorser_block] where
endorser_block = { tx_hash => tx_size } (a CBOR map, previously
decoded as an opaque bytestring). The codec now captures/splices
the map's raw CBOR verbatim (minicbor input()/writer_mut()), so the
`block: Vec<u8>` plumbing is unchanged — the bytes simply *are* the
manifest map.
- msgLeiosBlockTxs = [3, point, bitmaps, tx_list] (was [3, tx_list]);
the server now echoes the request's point + bitmap. Each tx in
tx_list is carried as raw CBOR (opaque pass-through), so a
structured `tx.tx` from a real peer round-trips.
- Removed the block-range sub-protocol (msgLeiosBlockRangeRequest [6],
msgLeiosNext/LastBlockAndTxsInRange [7]/[8], StBlockRange,
fetch_block_range) — gone from the spec.
net-node: encode/decode_overflow_eb now (de)serialise the
`{ hash => size }` manifest map (sizes 0 on the produce path; the EB
blob's slot is dropped — it was never read). Callers/tests updated.
Verified against the live Leios dev relay (magic 164): an EB is fetched,
the manifest decodes, an election is created (phase CertEligible), and
an EB-tx fetch is issued — zero CBOR decode errors. Tests: net-core
318, net-node 112, shared-consensus 297, net-cli green.
Known follow-up: the relay sends a TCP RST shortly after our
MsgLeiosBlockTxsRequest (bitmap EB-tx fetch); no decode error on our
side, connection reconnects and resyncs. Separate behavioural item.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
praos: fetch only the frontier gap during catch-up
A follower far behind a peer re-fetched the entire not-yet-validated backlog on every ChainSync roll-forward: `issue_fetch_internal` built a range `[anchor .. missing.last()]` and deduped only on the `to` endpoint, while `in_flight` recorded only that single endpoint. Each new tip therefore re-issued an overlapping range, so blocks_received grew ~30x the chain length and block bandwidth climbed super-linearly during deep catch-up. Track BlockFetch ranges per block in `in_flight` (matching the per-block removal already done in on_block_received), filter `missing` against it so only the frontier gap is requested, and start the range at the first still-needed block when an in-flight prefix was filtered. on_block_fetch_ failed now clears the whole [from,to] slot range so a failed range can be retried. Verified offline (local producer -> stake-0 follower): blocks_received == validated == tip (1x) vs the prior 30x. New regression test deep_catch_up_does_not_refetch_in_flight_blocks. Co-Authored-By: Claude Opus 4.8 <[email protected]>
sim-core: update Praos lottery call site after main's API rename
PR #924 moved the lottery threshold from a free function `lottery::rb_win_threshold(rate, stake)` returning an absolute count in `[0, total_stake)` to a method `LotteryParams::new(f).rb_win_threshold(stake, total_stake)` returning a `[0, 2^64)` threshold (spec-faithful `φ(σ) = 1 − (1−f)^σ` scaled by 2^64). net-rs/production.rs was updated on main, but sim-core was missed because the merge auto-resolved here on an unrelated hunk (PR #928's LeiosElectionInfo telemetry arm). Switch the call to the new method form and pair it with a direct `Rng::draw_u64` (uniform `[0, 2^64)`) instead of `draw_range(..., total_stake)`, mirroring how net-rs/production.rs draws and compares. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
net-core: trace Leios client EB/vote activity with full hashes
Add client-side tracing to the per-peer LeiosNotify and LeiosFetch
sub-tasks so a follower's logs can be cross-referenced against a peer's
(e.g. a relay's) server-side logs:
- leios_notify: EB offered / EB txs offered (slot + full eb_hash),
votes received (count; per-vote slot/eb_hash/voter_id/sig at debug),
EB announcement (header size).
- leios_fetch: requesting EB / EB received (slot, full eb_hash,
manifest bytes); requesting EB txs / received (requested index
count + first indices); request-failed warnings carry the same
fields so a disconnect is attributable to a specific EB.
EB hashes are logged in full (32 bytes) — the natural correlation key
against a relay's logs. info level for the per-EB events, debug for
per-vote detail.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
shared-consensus: cache voter index/id lookups in Elections
`Elections::voter_id_at` and `voter_index` previously did O(N) scans of `cfg.stake_registry` keys on every call. `voter_id_at` is called once per inbound vote inside `leios.rs::on_votes_received`, so for a 600-vote batch against a ~2500-pool registry that was ~750K string comparisons per batch. Build a `Vec<String>` (registry order) and a `BTreeMap<String, u16>` once at construction; both methods now reduce to a `Vec::get` / `BTreeMap::get`. `BTreeMap` keeps the shared-consensus no-HashMap- iteration rule and stays deterministic. `u16::try_from` truncation is preserved: entries past 65535 still resolve via `voter_id_at` but return `None` from `voter_index`. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
shared-consensus: remove the now-dead VoteFetchPolicy
Votes are delivered inline (previous commit), so the vote offer→fetch
machinery has no callers. Remove it across the workspace:
- shared-consensus fetch.rs: drop the VoteFetchPolicy trait, its
LowestRttFirst/BroadcastN/NoFetch impls, VoteCandidateLookup, and
the CandidateTracker vote_offers / pending_vote_fetches fields plus
note_vote_offered / vote_candidates / start_vote_fetch /
finish_vote_fetch. state_sizes() drops its two vote counters.
VoteId stays as a generic (slot, voter_id) tuple (sim-rs keys its
own vote state on it).
- shared-consensus leios.rs: drop the vote_policy field, the
with_fetch vote_policy param, and set_vote_policy.
- net-node / sim-rs: drop the `votes` fetch-policy config field,
into_vote_policy, and the set_vote_policy wiring; drop the
fetch_policy.votes doc from mainnet.toml.
EB / EB-tx fetch policies are untouched. Tests: shared-consensus 297,
net-core 322, net-node 112, net-cli 57 pass.
Co-Authored-By: Claude Opus 4.8 <[email protected]>