Skip to content

cardano-testnet: Dijkstra hard fork and nested transaction swap tests - #6709

Draft
Jimbo4350 wants to merge 3 commits into
masterfrom
jordan/dijkstra-testnet-start-test
Draft

Jimbo4350 wants to merge 3 commits into
masterfrom
jordan/dijkstra-testnet-start-test

Conversation

@Jimbo4350

@Jimbo4350 Jimbo4350 commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

Description

Two cardano-testnet integration tests for Dijkstra, plus the config change they need.

Hard fork to Dijkstra starts the default three-node cluster in Conway at protocol version 10 and hard forks it through governance, the way mainnet will: a HardForkInitiation action to PV 11.0 (voted for by the three default DReps and the default SPO, ratified, enacted), then a chained HardForkInitiation action to PV 12.0. It then asserts that the node reports the Dijkstra era and keeps producing blocks.

Nested transaction swap additionally mints 100 TokenA to Alice in Conway and funds Bob, then, once at PV12, settles a multi-asset swap with a Dijkstra nested transaction built with cardano-cli dijkstra transaction sub-transaction (IntersectMBO/cardano-cli#1453, via CARDANO_CLI): Alice's sub-transaction gives 100 TokenA for 53 ADA, Bob's gives 60 ADA for the 100 TokenA plus 7 ADA change, the batcher's top-level transaction embeds both and pays the fee. Each party signs only its own sub-transaction. Proof is read back from query utxo: Bob holds the tokens, Alice gained exactly 50 ADA, Bob lost exactly 50 ADA, the batcher paid the fee.

Testnet/Defaults.hs now sets ExperimentalHardForksEnabled: true for every era. Without it the node declares PV11 as its maximum and, once PV12 is enacted, rejects its own blocks with ObsoleteNode and the chain stalls. Golden config updated. Testnet.Components.Query.stopEpochStateView lets a test stop the client-side ledger fold before the chain enters an era that fold cannot process.

Status

cabal.project temporarily points ouroboros-consensus at IntersectMBO/ouroboros-consensus@0ebed78d (branch jordan/4.2.1.0-allow-hardfork-into-dijkstra): the 4.2.1.0 release plus the cherry-picked commit from IntersectMBO/ouroboros-consensus#2167 ("Allow hardfork into Dijkstra"). No 4.x release contains it; without it the Conway ledger config is built with TriggerHardForkNotDuringThisExecution and the node never enters Dijkstra. To be replaced by a released version.

  • Hard fork to Dijkstra passes with the SRP: PV 10 -> 11 -> 12 is enacted through governance, the node enters Dijkstra, query tip reports Dijkstra, blocks keep coming. On plain 4.2.1.0 it fails at the era assertion with The node is not in the Dijkstra era after protocol version 12 was enacted: Just (String "Conway").
  • Nested transaction swap reaches the Dijkstra ledger and is rejected at submission with SubBadInputsUTxO for every sub-transaction input, plus ValueNotConservedUTxO at the top level. Cause: UTxO-HD key fetching (getTransactionKeySets / getBlockKeySets via allInputsTxBodyF) does not load sub-transaction inputs, so the ledger sees them as missing. Present in consensus 4.2.1.0 and main, and in ledger's Dijkstra allInputsTxBodyF (0.3.0.0 and master). With a consensus-side fix that includes sub-transaction inputs, the swap passes end to end (verified locally, not part of this PR).

Also found: cardano-api's ConvertLedgerEvent instance for the hard fork block has no DijkstraLedgerEvent case (11.7.0.0 and master), so foldBlocks / foldEpochState clients crash on the first Dijkstra block. The tests therefore stop the epoch state view before PV12 and keep the epoch state logger off.

Run with:

DISABLE_RETRIES=1 cabal test cardano-testnet-test --test-options '-p "/Hard fork to Dijkstra/"'
CARDANO_CLI=/path/to/pr-1453/cardano-cli DISABLE_RETRIES=1 cabal test cardano-testnet-test --test-options '-p "/Nested transaction swap/"'

Checklist

  • Commit sequence broadly makes sense and commits have useful messages
  • New tests are added if needed and existing tests are updated.
  • Any changes are noted in the CHANGELOG.md for affected package (changelog fragment in cardano-testnet/.changes/)
  • The version bounds in .cabal files are updated
  • CI passes.
  • Self-reviewed the diff

🤖 Generated with Claude Code

@Jimbo4350
Jimbo4350 force-pushed the jordan/dijkstra-testnet-start-test branch from e917c47 to ad0be01 Compare September 29, 2026 15:16
… era

Add `hprop_hardfork_to_dijkstra` ("Hard fork to Dijkstra"), which starts
the default three-node cluster in Conway at protocol version 10 and hard
forks it through governance, the way mainnet will:

  1. a HardForkInitiation action to PV 11.0 (Conway intra-era hard fork),
     voted for by the three default DReps and the default SPO, ratified
     and enacted;
  2. a chained HardForkInitiation action to PV 12.0, voted, ratified and
     enacted.

It then asserts that `query tip` and the ledger state served over
node-to-client both report the Dijkstra era, and reuses the existing
block-production and clean-shutdown check.

Set `ExperimentalHardForksEnabled: true` in the generated node
configuration for every era. Without it the node declares PV11 as its
maximum protocol version, so once the ledger enacts PV12 it rejects its
own blocks with `ObsoleteNode` and the chain stalls. The golden default
node configuration is updated accordingly.

Note: with the currently pinned ouroboros-consensus 4.2.1.0 the
governance part of this test succeeds (PV 10 -> 11 -> 12 is enacted and
the node keeps forging at PV12) but the era assertion fails: the cluster
stays in Conway at PV12. `protocolInfoCardano` builds the Conway ledger
config with `TriggerHardForkNotDuringThisExecution`, so neither the
version trigger nor `TestDijkstraHardForkAtEpoch` can move it into
Dijkstra. The fix is IntersectMBO/ouroboros-consensus#2167, not yet in a
release.
@Jimbo4350
Jimbo4350 force-pushed the jordan/dijkstra-testnet-start-test branch from ad0be01 to d5c25ac Compare September 29, 2026 18:28
@Jimbo4350 Jimbo4350 changed the title cardano-testnet: add test that starts a cluster in the Dijkstra era cardano-testnet: add test that hard forks a cluster into the Dijkstra era Sep 29, 2026
Add `hprop_nested_transaction_swap` ("Nested transaction swap"). It mints
100 TokenA to Alice in Conway and funds Bob, hard forks the cluster into
Dijkstra through governance (shared with the "Hard fork to Dijkstra"
test), then settles a multi-asset swap with a nested transaction built
with `cardano-cli dijkstra transaction sub-transaction`:

  * Alice's sub-transaction spends her 100 TokenA and pays herself 53 ADA
    (50 ADA price + the 3 ADA that travelled with the tokens);
  * Bob's sub-transaction spends 60 ADA and pays himself the 100 TokenA
    plus 7 ADA change, i.e. exactly 50 ADA;
  * the batcher's top-level transaction embeds both signed
    sub-transactions and pays the fee.

Each sub-transaction is guarded by and signed with its owner's key only.
The proof is read back from `query utxo`: Bob holds the 100 TokenA, Alice
gained exactly 50 ADA, Bob lost exactly 50 ADA, the batcher paid the fee.

The test needs a cardano-cli with the sub-transaction commands
(IntersectMBO/cardano-cli#1453), pointed at via CARDANO_CLI. It does not
assert the era after the hard fork on purpose, so that on a consensus that
never leaves Conway the failure shows up at submission ("The node is
running in the Conway era, but the transaction is for the Dijkstra era").

Supporting changes:

  * `Testnet.Components.Query.stopEpochStateView` stops the client-side
    ledger fold behind an EpochStateView. cardano-api 11.7's ledger event
    conversion has no Dijkstra case and dies on the first Dijkstra block,
    so both Dijkstra tests stop the view before PV12 can be enacted, keep
    the epoch state logger off, and observe the node through the CLI.
  * `hardForkToDijkstra` waits for PV12 via `query protocol-parameters`
    and the era assertion now explains that a Conway answer means the
    pinned consensus ignores the Dijkstra trigger.
@Jimbo4350 Jimbo4350 changed the title cardano-testnet: add test that hard forks a cluster into the Dijkstra era cardano-testnet: Dijkstra hard fork and nested transaction swap tests Sep 29, 2026
… Dijkstra"

Temporarily point ouroboros-consensus at
IntersectMBO/ouroboros-consensus@0ebed78d, which is the 4.2.1.0 release
plus the cherry-picked commit from IntersectMBO/ouroboros-consensus#2167
(branch jordan/4.2.1.0-allow-hardfork-into-dijkstra). No 4.x release
contains that change yet; without it the Conway ledger config is built
with TriggerHardForkNotDuringThisExecution and the node can never enter
the Dijkstra era, so the "Hard fork to Dijkstra" test fails at the era
assertion.

With this SRP the "Hard fork to Dijkstra" test passes: the governance
hard fork to PV12 moves the node into Dijkstra and `query tip` reports
the Dijkstra era. The "Nested transaction swap" test now reaches the
Dijkstra ledger and is rejected with SubBadInputsUTxO, because UTxO-HD
key fetching (getTransactionKeySets via allInputsTxBodyF) does not load
sub-transaction inputs; that is a separate consensus/ledger fix.

Replace with a released ouroboros-consensus once one is available.

This branch has not been deployed

No deployments
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.

1 participant