Skip to content

chore(tx-generator): pin to upstream supervisor branch + Antithesis re-run#98

Draft
paolino wants to merge 5 commits intomainfrom
feat/tx-generator-n2c-reconnect-bump
Draft

chore(tx-generator): pin to upstream supervisor branch + Antithesis re-run#98
paolino wants to merge 5 commits intomainfrom
feat/tx-generator-n2c-reconnect-bump

Conversation

@paolino
Copy link
Copy Markdown
Collaborator

@paolino paolino commented Apr 30, 2026

Bumps cardano-node-clients pin to upstream main d0928a6,
which now carries:

Plus three composer-side fixes folded into one commit:

The submit-rejected paths keep their sdk_unreachable framing — the daemon's freshness gate is the actual fix, and any leftover submit-rejecteds should still surface as findings.

Verification

Image at tx-generator:8325fc2 is pre-pushed to GHCR (digest sha256:aeb64083316d4b88a2f2803be2a60ae61e40d2639ff543fe37f566ea78ea1ee1); publish-images will skip the rebuild.

The 1h cardano-node.yaml workflow_dispatch on this branch is the gate. Expectation:

If all of those hold the PR is mergeable; per the pins-main-only rule the upstream pin is already at d0928a6 on main so no repoint is needed.

Related

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 30, 2026

🚀 Documentation preview

Preview: https://cf-cna-pr-98.surge.sh

Built from 56de9d1.
The preview updates on every push to this branch.

paolino added a commit that referenced this pull request Apr 30, 2026
PR 1 of 2 toward the real asteria workload. Scope-limited to the
rename + Haskell source lift + nix scaffolding so the binaries
build alongside the existing utxo-indexer. Bootstrap is iteration
5b — *not safe for repeat invocation* — that gap is explicitly the
subject of PR 2.

Rename:
  components/asteria-stub/ → components/asteria-game/
  service asteria-stub      → asteria-game
  volume  asteria-stub-db   → asteria-game-db

Lift from #67 (asteria-spawn-v2):
  components/asteria-game/aiken/         (validators + apply-params)
  components/asteria-game/src/Asteria/   (game state, datums, validators, wallet, providers, RNG, SDK)
  components/asteria-game/app/{BootstrapMain.hs, PlayerMain.hs}
  components/asteria-game/asteria-game.cabal      (renamed package)
  components/asteria-game/cabal.project           (cardano-node-clients SRP bumped to PR #98 head 5707836b)

Build infra:
  flake.nix — extends prior asteria-stub flake with haskell.nix /
    iohk-nix overlays so local Haskell packages compile, while
    keeping the upstream cardano-node-clients flake input that
    supplies the prebuilt utxo-indexer (PR #98 supervisor).
  nix/project.nix — lifted from PR #67, package renamed.
  nix/docker-image.nix — bundles utxo-indexer + asteria-bootstrap
    + asteria-game (player) execs + composer scripts + bash/jq/
    socat; entrypoint stays utxo-indexer.

KNOWN GAP — admin_mint validator is the always-true placeholder
PR #67 ships. Without an on-chain one-shot guarantee, every
container restart could mint another admin NFT. Bootstrap is *not*
wired into compose in this PR for that reason. PR 2 patches the
Aiken admin_mint to take an OutputReference parameter, runs
apply-params at bootstrap-time, and adds defence-in-depth detection
in Bootstrap.hs.

Composer scripts (composer/stub/{parallel_driver_heartbeat,
eventually_alive, finally_alive, helper_sdk}.sh) unchanged from
the green stub baseline so this PR stays bisect-safe and in
property terms identical to commit 3b6fb0e (PR #74's merged head).
paolino added a commit that referenced this pull request Apr 30, 2026
PR 1 of 2 toward the real asteria workload. Scope-limited to the
rename + Haskell source lift + nix scaffolding so the binaries
build alongside the existing utxo-indexer. Bootstrap is iteration
5b — *not safe for repeat invocation* — that gap is explicitly the
subject of PR 2.

Rename:
  components/asteria-stub/ → components/asteria-game/
  service asteria-stub      → asteria-game
  volume  asteria-stub-db   → asteria-game-db

Lift from #67 (asteria-spawn-v2):
  components/asteria-game/aiken/         (validators + apply-params)
  components/asteria-game/src/Asteria/   (game state, datums, validators, wallet, providers, RNG, SDK)
  components/asteria-game/app/{BootstrapMain.hs, PlayerMain.hs}
  components/asteria-game/asteria-game.cabal      (renamed package)
  components/asteria-game/cabal.project           (cardano-node-clients SRP bumped to PR #98 head 5707836b)

Build infra:
  flake.nix — extends prior asteria-stub flake with haskell.nix /
    iohk-nix overlays so local Haskell packages compile, while
    keeping the upstream cardano-node-clients flake input that
    supplies the prebuilt utxo-indexer (PR #98 supervisor).
  nix/project.nix — lifted from PR #67, package renamed.
  nix/docker-image.nix — bundles utxo-indexer + asteria-bootstrap
    + asteria-game (player) execs + composer scripts + bash/jq/
    socat; entrypoint stays utxo-indexer.

KNOWN GAP — admin_mint validator is the always-true placeholder
PR #67 ships. Without an on-chain one-shot guarantee, every
container restart could mint another admin NFT. Bootstrap is *not*
wired into compose in this PR for that reason. PR 2 patches the
Aiken admin_mint to take an OutputReference parameter, runs
apply-params at bootstrap-time, and adds defence-in-depth detection
in Bootstrap.hs.

Composer scripts (composer/stub/{parallel_driver_heartbeat,
eventually_alive, finally_alive, helper_sdk}.sh) unchanged from
the green stub baseline so this PR stays bisect-safe and in
property terms identical to commit 3b6fb0e (PR #74's merged head).
paolino added a commit that referenced this pull request Apr 30, 2026
PR 1 of 2 toward the real asteria workload. Scope-limited to the
rename + Haskell source lift + nix scaffolding so the binaries
build alongside the existing utxo-indexer. Bootstrap is iteration
5b — *not safe for repeat invocation* — that gap is explicitly the
subject of PR 2.

Rename:
  components/asteria-stub/ → components/asteria-game/
  service asteria-stub      → asteria-game
  volume  asteria-stub-db   → asteria-game-db

Lift from #67 (asteria-spawn-v2):
  components/asteria-game/aiken/         (validators + apply-params)
  components/asteria-game/src/Asteria/   (game state, datums, validators, wallet, providers, RNG, SDK)
  components/asteria-game/app/{BootstrapMain.hs, PlayerMain.hs}
  components/asteria-game/asteria-game.cabal      (renamed package)
  components/asteria-game/cabal.project           (cardano-node-clients SRP bumped to PR #98 head 5707836b)

Build infra:
  flake.nix — extends prior asteria-stub flake with haskell.nix /
    iohk-nix overlays so local Haskell packages compile, while
    keeping the upstream cardano-node-clients flake input that
    supplies the prebuilt utxo-indexer (PR #98 supervisor).
  nix/project.nix — lifted from PR #67, package renamed.
  nix/docker-image.nix — bundles utxo-indexer + asteria-bootstrap
    + asteria-game (player) execs + composer scripts + bash/jq/
    socat; entrypoint stays utxo-indexer.

KNOWN GAP — admin_mint validator is the always-true placeholder
PR #67 ships. Without an on-chain one-shot guarantee, every
container restart could mint another admin NFT. Bootstrap is *not*
wired into compose in this PR for that reason. PR 2 patches the
Aiken admin_mint to take an OutputReference parameter, runs
apply-params at bootstrap-time, and adds defence-in-depth detection
in Bootstrap.hs.

Composer scripts (composer/stub/{parallel_driver_heartbeat,
eventually_alive, finally_alive, helper_sdk}.sh) unchanged from
the green stub baseline so this PR stays bisect-safe and in
property terms identical to commit 3b6fb0e (PR #74's merged head).
paolino added a commit that referenced this pull request May 1, 2026
PR 1 of 2 toward the real asteria workload. Scope-limited to the
rename + Haskell source lift + nix scaffolding so the binaries
build alongside the existing utxo-indexer. Bootstrap is iteration
5b — *not safe for repeat invocation* — that gap is explicitly the
subject of PR 2.

Rename:
  components/asteria-stub/ → components/asteria-game/
  service asteria-stub      → asteria-game
  volume  asteria-stub-db   → asteria-game-db

Lift from #67 (asteria-spawn-v2):
  components/asteria-game/aiken/         (validators + apply-params)
  components/asteria-game/src/Asteria/   (game state, datums, validators, wallet, providers, RNG, SDK)
  components/asteria-game/app/{BootstrapMain.hs, PlayerMain.hs}
  components/asteria-game/asteria-game.cabal      (renamed package)
  components/asteria-game/cabal.project           (cardano-node-clients SRP bumped to PR #98 head 5707836b)

Build infra:
  flake.nix — extends prior asteria-stub flake with haskell.nix /
    iohk-nix overlays so local Haskell packages compile, while
    keeping the upstream cardano-node-clients flake input that
    supplies the prebuilt utxo-indexer (PR #98 supervisor).
  nix/project.nix — lifted from PR #67, package renamed.
  nix/docker-image.nix — bundles utxo-indexer + asteria-bootstrap
    + asteria-game (player) execs + composer scripts + bash/jq/
    socat; entrypoint stays utxo-indexer.

KNOWN GAP — admin_mint validator is the always-true placeholder
PR #67 ships. Without an on-chain one-shot guarantee, every
container restart could mint another admin NFT. Bootstrap is *not*
wired into compose in this PR for that reason. PR 2 patches the
Aiken admin_mint to take an OutputReference parameter, runs
apply-params at bootstrap-time, and adds defence-in-depth detection
in Bootstrap.hs.

Composer scripts (composer/stub/{parallel_driver_heartbeat,
eventually_alive, finally_alive, helper_sdk}.sh) unchanged from
the green stub baseline so this PR stays bisect-safe and in
property terms identical to commit 3b6fb0e (PR #74's merged head).
paolino added 3 commits May 1, 2026 09:33
Picks up the full reconnect-resilience stack on upstream
main:
  * #105 — N2C reconnect supervisor + BlockedIndefinitely catch
  * #110 — post-reconnect indexer freshness gate (rsIndexFresh)

The freshness gate closes the stale-UTxO window between
bearer reconnect and chain-sync re-sync that produced
the residual tx_generator_*_submit_rejected and
tx_generator_population_did_not_grow Always-assertion
failures on the previous Antithesis run (329a599).
Three composer-side fixes for findings carried over on
the previous Antithesis run (329a599 — see issues #105,
#106, #107):

1. (B / #105) The not-applicable case in
   parallel_driver_transact.sh and parallel_driver_refill.sh
   was emitting `sdk_sometimes false ...`. Antithesis grades
   a Sometimes assertion as PASSING when at least one sample
   has condition=true; we always emitted condition=false, so
   this assertion could never satisfy and was always failed.
   Switch to `sdk_reachable` — accumulates samples without a
   pass/fail grade, the right type for "documented
   not-applicable response".

2. (C / #106) The composer scripts intentionally exited 1 on
   not-applicable to mark the tick as "skipped". Antithesis's
   built-in 'Always: Commands finish with zero exit code'
   property has no opt-out and grades every non-zero exit as
   a failure. Switch to the asteria-stub convention: always
   exit 0, encode tick state purely via SDK assertions
   (parallel_driver_heartbeat.sh and eventually_alive.sh in
   components/asteria-stub/composer/stub/ do this). Same in
   eventually_population_grew.sh — fire the unreachability
   on did-not-grow and exit 0.

3. (D-adjacent / #107) Add 'index-not-ready' to the refill
   driver's not-applicable case set. After
   cardano-node-clients#110 the daemon's freshness gate
   returns IndexNotReady for refills during the post-
   reconnect stale-UTxO window; the composer should treat
   this as a documented not-applicable, not an unknown
   failure.

The submit-rejected paths keep their `sdk_unreachable`
(strict) framing — the daemon-side freshness gate (#110)
is the actual fix, and we want any leftover
submit-rejecteds to surface as findings, not be silenced.

Verification gate: a fresh 1h Antithesis run on this
branch should show 0 failures from these three findings,
plus the supervisor still triggering its full reconnect
load.
@paolino paolino force-pushed the feat/tx-generator-n2c-reconnect-bump branch from 329a599 to 685fa5e Compare May 1, 2026 08:36
paolino added a commit that referenced this pull request May 1, 2026
Renames components/asteria-player/ → components/asteria-game/ and
upgrades the lifted PR #67 sources so the bootstrap is safe to
re-run on container restart.

  - cabal package + executable renamed asteria-player → asteria-game.
  - cabal.project SRP pinned to cardano-node-clients PR #98 head
    5707836b (utxo-indexer supervisor + N2C reconnect).
  - flake.nix pulls cardano-node-clients utxo-indexer as a flake
    input so dockerTools bundles the prebuilt binary.
  - nix/docker-image.nix bundles utxo-indexer + asteria-bootstrap +
    asteria-game (player) execs + composer/stub scripts; entrypoint
    is the indexer, the bootstrap runs as a serial driver.
  - composer/stub/ shape replaces composer/asteria/: green-baseline
    heartbeat / eventually_alive / finally_alive plus a new
    serial_driver_asteria_bootstrap that execs /bin/asteria-bootstrap.
  - app/BootstrapMain.hs gains Asteria.Bootstrap.isAlreadyDeployed:
    queries Provider for UTxOs at the asteria spend address and
    short-circuits if any UTxO carries the @"asteriaAdmin"@ token.
    Antithesis can restart the asteria-game container at will and
    bootstrap exits 0 quickly on subsequent invocations.

The asteria_game testnet that wires this image into Antithesis is
added in the next commit.

KNOWN GAP — admin_mint validator is the always-true placeholder
PR #67 ships. The Haskell-side detection plus Antithesis's
@serial_driver_@ scheduling are the contract until a follow-up PR
replaces admin_mint with a one-shot policy parameterised on a seed
@OutputReference@.

Tracks: #67 (asteria-spawn-v2), #98 (utxo-indexer supervisor).
Closes companion: #108 (idempotent bootstrap, content folded here).
paolino added 2 commits May 1, 2026 11:30
Antithesis run on 685fa5e (https://cardano.antithesis.com/report/tilehuSggX4cnuy5qyXfwpqI/CVALsMOlHQdIyvQsc0sKyxZ79mapUIksHP-v0XZcVds.html)
still flagged tx-generator/parallel_driver_*.sh against the
"Always: Commands finish with zero exit code" property.
Example log lines show command_return_code=1 with a
runtime of ~30-60ms and an empty additional_stderr —
i.e. the script never reached any of our 'exit 0' lines.

Root cause: 'set -euo pipefail' + 'nc -U -q 1 $sock' fails
the assignment when the daemon's control socket isn't yet
bound (early boot, supervisor mid-cycle), and 'set -e'
kills the script before any 'exit 0' branch runs.

Same shape applies to eventually_population_grew.sh: an
empty RSP made jq emit 0, and we then incorrectly fired
the 'tx_generator_population_did_not_grow' Always
assertion against a daemon we never successfully queried.

Fix:

- Replace 'set -euo pipefail' with 'set -u' (matches
  components/asteria-stub/composer/stub/parallel_driver_heartbeat.sh).
- Wrap nc in '|| true', check for empty RSP, and if empty
  emit a 'tx_generator_*_daemon_unreachable' reachability
  event then exit 0. Composer's "Always exit 0" property
  holds; assertion ingestion still records the path was
  taken; daemon is retried on the next tick.
- eventually_population_grew.sh: distinguish "daemon
  unreachable" from "daemon says populationSize=0". Fire
  did_not_grow only when the snapshot RSP is non-empty
  AND parses as JSON.

The remaining tx_generator_*_submit_rejected Always
failures from the 685fa5e run are a separate
duplicate-submit-after-reconnect race tracked at
lambdasistemi/cardano-node-clients#111.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant