Skip to content

test(txbuilder): add a Conway build test harness#781

Open
logicalmechanism wants to merge 8 commits into
txpipe:mainfrom
logicalmechanism:txbuilder/test-harness
Open

test(txbuilder): add a Conway build test harness#781
logicalmechanism wants to merge 8 commits into
txpipe:mainfrom
logicalmechanism:txbuilder/test-harness

Conversation

@logicalmechanism

@logicalmechanism logicalmechanism commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

First in a planned series of small PRs hardening pallas-txbuilder. This one adds an integration-test harness for the Conway builder; later PRs fix the bugs it documents (see Known-bug documentation below).

What

Adds tests/build_conway.rs plus golden snapshots and cardano-cli vectors, exercising build_conway_raw and BuiltTransaction signing with no live node required. No production code changes — the harness rides on the crate's existing [dependencies].

Test oracles:

  • Decode round-trip — every built tx is decoded back with pallas_primitives::conway::Tx and asserted field-by-field against the builder inputs.
  • Golden snapshots — CBOR hex + body hash of representative txs are pinned under tests/golden/, so any encoder change shows up as a diff.
  • Determinism — the same logical tx built 64× must encode identically, exercising the encode-time BTreeMap normalisation of asset/mint bundles at both the policy and asset-name level (the staging maps are HashMap-backed and re-seeded per build).
  • Script-data self-consistency — the embedded script_data_hash is recomputed from the decoded witness set via ScriptData::build_for and asserted equal.
  • cardano-cli cross-checks — real unsigned Conway transactions (datum payment, token transfer, native-script mint, Plutus reference-script spend + burn) under tests/vectors/ are reconstructed by the builder and compared field-by-field: inputs, outputs, fee, validity bounds, mint, native scripts, collateral, reference inputs, and required signers.

Known-bug documentation

Five tests are #[ignore]d on purpose: they fail when un-ignored and pin down current builder bugs as executable specs, each with a comment citing the exact source location. Default cargo test stays green, so CI is unaffected. Each is intended to be un-ignored by the follow-up PR that fixes it:

  • datum-only script_data_hash omitted (gated on language_views)
  • redeemers emitted as a list instead of the Conway map form
  • total_collateral hardcoded to None with no setter
  • remove_signature panics when emptying the witness set
  • datum / redeemer / script ordering is non-deterministic

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Tests
    • Added extensive test suite for Conway transaction builder with comprehensive coverage of transaction structure, signing behavior, deterministic asset encoding, round-trip validation, and compatibility checks against reference implementations
    • Updated golden test snapshots and fixture data
    • Added new test vectors covering multi-asset, native mint, Plutus script interactions, and datum output scenarios

logicalmechanism and others added 8 commits May 29, 2026 14:24
…coverage

Introduce an integration test suite for the Conway builder. This first
commit covers the simplest transaction (one input, one output, a fee) and
establishes the oracles the rest of the suite will reuse:

- decode round-trip via pallas_primitives::conway::Tx
- a golden CBOR + hash snapshot under tests/golden/
- a determinism check (same inputs => same bytes)

No library changes; pure test additions plus the dev-dependencies the
integration test crate needs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add Group B of the Conway build suite:

- sign() embeds exactly one vkey witness and records it in `signatures`
- signing preserves the body hash (witnesses don't change what was signed)
- signing twice accumulates two witnesses
- add_signature embeds an out-of-band witness (HSM / hardware-wallet flow)
- remove_signature leaves the remaining witnesses intact

Signatures are produced from a deterministic, clamped extended Ed25519 key
so the suite needs no RNG.

This surfaced a panic: remove_signature on the *only* witness unwraps
`NonEmptySet::from_vec(vec![])` (None) instead of clearing the set. It is
captured as an #[ignore]d test (remove_last_signature_clears_witness_set)
to be un-ignored by the PR that fixes the panic.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add Group C of the Conway build suite:

- multi-asset outputs build deterministically (asset bundles encode through
  BTreeMap-backed Multiasset, so order is normalised)
- mint bundles build deterministically for the same reason

And document the determinism gap that is not normalised: datums (like
redeemers and scripts) are stored in a HashMap and emitted in iteration
order, so the same transaction can encode to different bytes/hash across
builds. Captured as an #[ignore]d test (multiple_datums_build_deterministically)
that builds the tx fresh 64 times and asserts a single unique encoding; to
be un-ignored by the PR that sorts these collections before encoding.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add Group D of the Conway build suite: a transaction with a native token
in its output plus a mint and a burn. Decode the result and assert the
lovelace, asset name/quantity, mint amount, and burn amount survive the
round-trip, and pin a golden CBOR + hash snapshot.

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

Add Group E of the Conway build suite, mirroring the self-consistency check
pallas-primitives runs on real transactions: build a tx with datums, a spend
redeemer, and a cost model, then assert the embedded script_data_hash equals
the value recomputed from the decoded witness set via ScriptData::build_for.

Also document the gating bug: the builder computes script_data_hash only when
language_views is set, but the ledger requires it whenever the witness set
carries datums or redeemers. A datum-only transaction silently gets None and
is rejected by the node. Captured as an #[ignore]d test
(datum_only_sets_script_data_hash); to be un-ignored by the PR that switches
the builder to ScriptData::build_for.

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

Add Group F: reconstruct three real, unsigned Conway transactions produced by
cardano-cli (stored under tests/vectors/) through the builder and assert the
results match.

- datum_output: inline-datum payment + change
- token_output: two inputs, inline-datum + token output, plain and token change
- native_mint: native-script mint, token output + change, script in the
  witness set

cardano-cli emits plain/token outputs in the legacy [address, value] array
form while the builder always emits the post-Alonzo map form (both valid per
the Conway CDDL), so the comparison is semantic — inputs, fee, validity
bounds, mint, native scripts, and per-output address/coin/assets/datum — and
additionally requires outputs that are post-Alonzo in both to be
byte-identical. The inline-datum output reproduces byte-for-byte, including
the indefinite-array datum encoding.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a fourth real cardano-cli fixture (tests/vectors/plutus_spend_burn.tx): a
Plutus spend whose script is supplied via a reference input, with a spend
redeemer, a mint (burn) redeemer, collateral, collateral return, and required
signers.

Extend the comparator to also check collateral inputs, reference inputs,
required signers, and the collateral-return output — all of which the builder
reproduces faithfully here.

Two things the builder cannot yet reproduce are captured as #[ignore]d tests
documenting the gaps:

- plutus_tx_sets_total_collateral: the builder hardcodes total_collateral to
  None with no setter, so it drops the field (fixture sets 579653).
- plutus_tx_emits_map_form_redeemers: the builder emits redeemers in the
  legacy list form, while Conway cardano-cli uses the map form; the two hash
  differently, so the builder's script_data_hash is incompatible with cli.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Address review feedback on the Conway build test harness:

- Strengthen multi_asset_output_is_deterministic / mint_is_deterministic to
  assert a single unique encoding across 64 fresh builds (collected into a
  HashSet) and to stage two asset names under one policy, so both the outer
  (policy) and inner (asset-name) BTreeMap sorts are exercised. Each build
  constructs a fresh, per-instance re-seeded HashMap, which is what drives the
  pre-encode order variation; the previous form compared one fixed-order build
  to itself and never varied the bundle order.
- Assert bundle sizes in output_asset_value_round_trips and
  mint_and_burn_round_trip so a spuriously added asset/policy cannot slip past
  the single-entry .next() checks.
- Reword the script_data_hash_matches_recomputation doc comment to make clear it
  is a self-consistency check, not a cross-check against cardano-cli (it reuses
  the builder's legacy list-form redeemer encoding).
- Remove the [dev-dependencies] block from pallas-txbuilder/Cargo.toml:
  pallas-crypto, pallas-primitives, pallas-addresses, and hex are all already in
  [dependencies], which Cargo makes available to integration tests.

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

coderabbitai Bot commented Jun 3, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 97e44e68-db99-453f-a459-672f6c06346e

📥 Commits

Reviewing files that changed from the base of the PR and between ee3df46 and ac9c101.

📒 Files selected for processing (9)
  • pallas-txbuilder/tests/build_conway.rs
  • pallas-txbuilder/tests/golden/minimal.hash
  • pallas-txbuilder/tests/golden/minimal.tx
  • pallas-txbuilder/tests/golden/multi_asset.hash
  • pallas-txbuilder/tests/golden/multi_asset.tx
  • pallas-txbuilder/tests/vectors/datum_output.tx
  • pallas-txbuilder/tests/vectors/native_mint.tx
  • pallas-txbuilder/tests/vectors/plutus_spend_burn.tx
  • pallas-txbuilder/tests/vectors/token_output.tx

📝 Walkthrough

Walkthrough

This PR adds a comprehensive integration test suite (build_conway.rs) for the Conway transaction builder in Pallas. The test file validates transaction structure, signing behavior, determinism guarantees, multi-asset handling, script data consistency, and cross-checks built transactions against real cardano-cli fixtures, while documenting known builder gaps via ignored tests.

Changes

Conway Transaction Builder Integration Test Suite

Layer / File(s) Summary
Test Infrastructure & Minimal Transaction
pallas-txbuilder/tests/build_conway.rs (lines 1–135), pallas-txbuilder/tests/golden/minimal.*
Initializes test module with helper utilities, builds minimal unsigned transaction fixture, validates basic structure (inputs/outputs/fee/TTL/witnesses), verifies repeat-build determinism, and asserts golden CBOR and tx-hash snapshots.
Signing & Witness Management
pallas-txbuilder/tests/build_conway.rs (lines 140–256)
Tests vkey witness embedding and persistence across signing operations, body-hash immutability during signing, witness accumulation across multiple signers, witness removal semantics, and documents known panic case when removing final witness.
Determinism Guarantees
pallas-txbuilder/tests/build_conway.rs (lines 257–367)
Validates encoding determinism for asset and mint bundles despite randomized staging-map insertion order via repeated builds and encoding comparison, with ignored test documenting non-deterministic behavior in multi-datum ordering.
Multi-Asset Handling & Round-Trip Validation
pallas-txbuilder/tests/build_conway.rs (lines 368–449), pallas-txbuilder/tests/golden/multi_asset.*
Introduces asset fixture with round-trip decoding tests for multi-asset output values and mint/burn amounts, plus golden snapshot asserting exact CBOR and tx-hash for multi-asset + mint transaction.
Script Data Hash Validation
pallas-txbuilder/tests/build_conway.rs (lines 450–529)
Validates script_data_hash self-consistency by recomputing from decoded witness set and asserting equality with embedded value, with ignored datum-only test documenting missing hash when language views/cost models not configured.
Cross-Check Framework & Fixture Validation
pallas-txbuilder/tests/build_conway.rs (lines 531–796), pallas-txbuilder/tests/vectors/datum_output.tx, pallas-txbuilder/tests/vectors/native_mint.tx, pallas-txbuilder/tests/vectors/token_output.tx
Implements comparison infrastructure against cardano-cli fixture vectors: output summarization, input/signer normalization, multi-asset flattening, and main cross_check function that asserts semantic equality plus post-Alonzo byte-identical output encoding, then applies it to reconstruction tests for datum payments, token transfers, and native-script mints.
Plutus Scripting Tests
pallas-txbuilder/tests/build_conway.rs (lines 798–865), pallas-txbuilder/tests/vectors/plutus_spend_burn.tx
Adds plutus_spend_burn staging fixture with reference input, collateral, mint/burn redeemers with ex-units cost, and reconstruction test cross-checking against corresponding fixture vector.
Known Gaps Documentation
pallas-txbuilder/tests/build_conway.rs (lines 867–906)
Ignored tests documenting builder limitations: total_collateral hardcoded to None, and Conway redeemers emitted in legacy list form instead of map form.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • txpipe/pallas#712: Fixes script_data_hash computation for datum-only transactions, which is the exact scenario covered by the ignored test in this PR.

Suggested reviewers

  • scarmuega

Poem

🐰 A test suite built with Conway's might,
Golden fixtures shining ever bright,
Witness dancing, mints align,
Determinism through the line,
Transaction truth, checked just right!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'test(txbuilder): add a Conway build test harness' directly and clearly summarizes the main change: addition of a comprehensive test suite for the Conway transaction builder. The conventional commit format and specificity make the primary intent immediately clear.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

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