Skip to content

Slot leader time travel below f1 - #189

Merged
satran004 merged 2 commits into
bloxbean:mainfrom
rjharmon:slot-leader-time-travel-below-f1
Sep 25, 2026
Merged

satran004 merged 2 commits into
bloxbean:mainfrom
rjharmon:slot-leader-time-travel-below-f1

Conversation

@rjharmon

@rjharmon rjharmon commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Default time travel places one block per slot and ignores VRF eligibility. That is fine while only Yano consumes the chain, but a Haskell node validating it rejects the first header at activeSlotsCoeff below 1 with {@code VRFLeaderValueTooBig} and never syncs. So in {@code auto} mode the checks are on when a Haskell node consumes Yano's chain (companion, yano-primary) and activeSlotsCoeff is below 1, and for local multi-node devnets as before.

Default time travel places a block in every slot and ignores VRF
eligibility. At activeSlotsCoeff below 1 the Haskell relay rejects the
first header with VRFLeaderValueTooBig and never syncs, so the cost-model
update is never enacted.

- decide slot-leader time travel in one place, YanoService, and pass the
  result to YanoConfigBuilder instead of duplicating the rule
- auto mode: on when a Haskell node validates the chain (companion,
  yano-primary) and activeSlotsCoeff is below 1, and for local multi-node
  devnets as before; yano-only stays dense
- add yano.past.time.travel.slot.leader.mode (auto, true, false)
- document the rule in the node modes page and the CLI properties file
A bootstrap chain the relay rejects (for example VRFLeaderValueTooBig at
activeSlotsCoeff below 1) was invisible with TraceChainSyncClient off: the
node kept running with exit code 0 and an empty chain.

- add traceChainSyncClient to the genesis config (node.properties),
  default true, rendered into configuration.json
- document it in the node-configuration and node-modes pages

@satran004 satran004 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Thanks @rjharmon

@satran004
satran004 merged commit 8dc06e0 into bloxbean:main Sep 25, 2026
2 checks passed
satran004 added a commit that referenced this pull request Sep 26, 2026
Brings in #188 (relay sync wait by progress), #189 (slot-leader time travel below
f=1) and #190 (stabilityWindowFactor as a double).

- YanoConfigBuilder.build() takes the history dir, #189's slot-leader flag and the
  backfill interval; YanoService keeps both settings and passes both
- application.properties, both node.properties and the node-modes / node-configuration
  docs keep every section; the node.properties examples keep slotsPerKESPeriod=10000000

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
satran004 added a commit that referenced this pull request Sep 26, 2026
#189 turned the node's chain-sync client tracing on by default. On a single-node
companion devnet the node has no upstream peer after the handover, so it costs
little, but on multi-node devnets it logs every header each node receives from each
peer for the life of the devnet. Keep the setting, default it to off, and point to
it in the docs for diagnosing a relay that will not sync.

The unrendered configuration.yaml and spec/config.json templates go back to false
as well; configuration.json takes the value from traceChainSyncClient.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
satran004 added a commit that referenced this pull request Sep 30, 2026
…devnet (#193)

* Update Ogmios to 7.0.0 / Kupo to 2.12.0 and fix devnet startup issues

Move Ogmios and Kupo back to the CardanoSolutions upstream and drop the
PV11 stopgap that bundled Linux x86_64 IntersectMBO builds into the arm64
image. Both components now ship native binaries for linux/amd64,
linux/arm64 and macOS arm64, so the Docker images no longer need x86_64
emulation and a native macOS install works.

Ogmios / Kupo
- Bump to Ogmios 7.0.0 and Kupo 2.12.0 from CardanoSolutions (.tar.gz -> .zip)
- Use real aarch64 assets for arm64 instead of emulated x86_64 ones
- Consolidate the duplicated OS/arch resolution into one helper that fails
  fast with an actionable message on unpublished platforms (macOS x86_64,
  Windows) instead of 404-ing
- Flatten the nested archive layout the macOS zips use (v7.0.0/bin/ogmios)
  so the binary always lands at <home>/bin/<name>
- Handle the Kupo tag/asset version mismatch (tag v2.12, asset v2.12.0)

Ogmios as the Yaci Store tx evaluator
- Enable Ogmios by default (ogmios_enabled=true) and use it to evaluate
  Plutus script costs, falling back to the embedded Scalus evaluator
- Wait for Ogmios to answer on /health before committing to the ogmios
  evaluator mode. The mode is baked into the Store process at startup and
  never re-evaluated, so a short-lived Ogmios would otherwise leave the
  Store unable to evaluate any script for the lifetime of the devnet
- Skip Ogmios/Kupo in yano-only mode; they need the Haskell node's n2c socket
- Don't let an Ogmios failure abort the startup chain before Yaci Store runs
- Treat enableOgmios as optional in the admin API so omitting it keeps the
  configured default rather than forcing Ogmios off

Fix prometheus.port never being applied
The property was read, stored on ClusterInfo and put into the Mustache
values map, but templates/configuration.json hardcoded 12798 with no
placeholder, so the value was silently dropped. A second cardano-node on
the host holding 12798 made the devnet node die at bind with the error
going to stderr, which node.sh does not capture.

Disable the Yano DuckLake projection archive
Yano pre15's devnet profile enables the projection archive by default.
DevKit reads nothing from Yano's history API, and the archive defaults to
./history relative to the working directory - the shared yano home - so it
outlived create-node -o and then failed the startup identity and coverage
guards. Turn it off and pin the dir inside the node folder so it is cleaned
up with the cluster if it is ever re-enabled.

Also bumps Yano to 0.1.0-pre15.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Use Yano's automatic sparse backfill and KES defaults that outlive a devnet

Two devnet defaults learned from Yano's own devnet configuration, both of
which only bite as epoch length grows.

Automatic sparse backfill
Yano's catch-up from the shifted genesis to wall clock places one empty block
per slot by default, so devnet create time grows with epoch length and the
Haskell relay has to copy the whole chain. Yano 0.1.0-pre15 can derive the
spacing itself from genesis (bloxbean/yano#127): it keeps every gap inside the
forecast window a validating node can span, retains the epoch-boundary blocks
needed for nonces, and places a final block at the catch-up target. Everything
in between was empty filler.

DevKit now passes yano.block-producer.backfill-block-interval-slots=0 and lets
Yano decide, rather than deriving an interval itself. Yano knows the forecast
window, the epoch nonce schedule and the producer's eligibility headroom;
a number computed out here would be a heuristic that silently drifts when
those rules change, and Yano validates its own value and fails loudly instead.

yano.backfill.block.interval.slots overrides it: auto (default), dense for one
block per slot, or an integer to force the interval. An unusable value falls
back to automatic rather than to dense, which is the slow one.

KES defaults
slotsPerKESPeriod moves from the mainnet 129600 to 10000000, and
maxKESEvolutions from 60 to the mainnet 62. The node derives the current KES
period as slot / slotsPerKESPeriod, and the companion bootstrap shifts genesis
back by whole epochs before catching up to wall clock, so the chain starts at
a high slot. At 129600 a long-epoch devnet burns a large share of its
evolutions before producing its first real block - a three epoch shift on
14 day epochs is 28 of the 60 - and the share grows with epoch length. The
large period keeps a devnet inside KES period 0 for its whole life.

The trade-off is that a DevKit devnet no longer exercises KES rotation, which
is documented alongside the values to set to get mainnet-like behaviour back.
Only the devnet genesis defaults change; the privnet spec templates, which do
not time travel, keep the mainnet values.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Bump Yano to 0.1.0-pre17 and Yaci Store to 2.0.3

- Yano 0.1.0-pre17 for both the CLI download (download.properties) and the Docker
  image (Earthfile YANO_TAG/YANO_VERSION, download-yano.sh default). The Docker image
  was still pinned to 0.1.0-pre6, which predates the backfill interval property.
- Yaci Store 2.0.3: CLI native binaries from rel-native-2.0.3 and the jar from v2.0.3.
  The Docker image now builds the Store native variants from the v2.0.3 tag instead
  of release/2.0.1_devkit; the devkit-only fixes on that branch (#965, #967, #977,
  #978) are all contained in v2.0.3.

Verified with a native Docker build (Store commit 381dce2 = v2.0.3, Yano pre17
linux-arm64): companion bootstrap, Store synced to tip, PV11 cost models enacted,
Ogmios 7.0.0 synced, and a topup transaction indexed by Store.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* Keep capturing process output when a line cannot be processed

ProcessUtil built each captured line with String.format("[%s] " + line, ...), so the
line itself was used as a format string. After a restart cardano-node prints
"Progress: 95.65%" while it reopens its ChainDB; the format call threw, the reader
thread died, and nothing drained the node's stdout any more. The `logs` command then
stayed frozen at startup and the tee'd node.log stopped growing once the pipe filled.

- append the line as data instead of formatting it
- ProcessStream skips a line whose consumer throws instead of ending the read loop

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* Let cardano-node write and rotate its own node.log

The node scripts piped stdout through `tee -a node.log`, so the rotation settings in
configuration.json never applied (they only cover file scribes) and node.log grew
without bound, about 120 MB/day at 1s blocks.

- configuration.json adds a FileSK scribe for node.log next to stdout; it uses the
  existing rotation block (5 MB per file, 10 files, 24h)
- node.sh, node-2, node-3, node-bp.sh and node-relay.sh no longer pipe through tee

The node now writes timestamped files with node.log as a link to the newest, so use
`tail -F`. The CLI `logs` command reads the process stdout and is unaffected.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* Default traceChainSyncClient to false

#189 turned the node's chain-sync client tracing on by default. On a single-node
companion devnet the node has no upstream peer after the handover, so it costs
little, but on multi-node devnets it logs every header each node receives from each
peer for the life of the devnet. Keep the setting, default it to off, and point to
it in the docs for diagnosing a relay that will not sync.

The unrendered configuration.yaml and spec/config.json templates go back to false
as well; configuration.json takes the value from traceChainSyncClient.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* Drop the stale KES default entries from the node configuration docs

The page still listed slotsPerKESPeriod 129600 and maxKESEvolutions 60 near the
end, contradicting the "maxKESEvolutions and slotsPerKESPeriod" section above it,
which documents the current defaults (62 / 10000000) and the trade-off.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* Bump Yaci Store to 2.0.4

Native binaries from rel-native-2.0.4, jar from v2.0.4, and the Docker
image builds Store from the v2.0.4 tag. 2.0.4 closes the Blockfrost API
gaps the SDKs hit.

Verified on a companion devnet with the 2.0.4 macOS arm64 n2c binary:
all SDK e2e suites pass (Evolution SDK, Lucid Evolution, MeshJS,
PyCardano, cardano-client-lib; 13 tests) through each SDK's Blockfrost
provider, with the SDKs at their latest versions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants