Skip to content

Add support for Plutus scripts on compatible Tx - #1282

Open
carbolymer wants to merge 2 commits into
masterfrom
mgalazyn/feature/compatible-plutus
Open

Add support for Plutus scripts on compatible Tx#1282
carbolymer wants to merge 2 commits into
masterfrom
mgalazyn/feature/compatible-plutus

Conversation

@carbolymer

@carbolymer carbolymer commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Description

Adds plutus spending script support to the compatible transaction API, so pre-Conway script transactions (PlutusV1/V2, Alonzo/Babbage) can be built without the deprecated API.
Motivated by the tx-generator migration in IntersectMBO/cardano-node#6602.

Changes:

  • createCompatibleTx supports script-witnessed inputs: spending redeemer pointers, witness datums, script integrity hash, collateral inputs, transaction metadata and validity upper bound.
  • Breaking: all transaction content is now passed as a single CompatibleTxBodyContent record, and failures are reported via the new CompatibleTxError.
  • Breaking: mkSpendingScriptDatum is exported for building spending-purpose datums.
  • Fixes: certificate, proposal and vote script witnesses were missing from the witness set; proposal reference inputs were overwritten.

Review follow-ups included:

Checklist

  • New tests: plutus witness properties for the compatible builder in Test.Cardano.Api.Experimental.Fee
  • Changelog fragment (.changes/20260807_cardano_api_compatible_plutus.yml)
  • Self-reviewed

@carbolymer carbolymer self-assigned this Aug 8, 2026
@carbolymer
carbolymer force-pushed the mgalazyn/feature/compatible-plutus branch 11 times, most recently from 75f0875 to 26aaf4a Compare August 13, 2026 10:40
@carbolymer
carbolymer marked this pull request as ready for review August 13, 2026 15:33
Copilot AI lite review requested due to automatic review settings August 13, 2026 15:33

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Extends the Cardano.Api.Compatible.Tx builder to support Plutus spending scripts (and related era features) so callers can build pre-Conway Plutus script transactions without relying on deprecated APIs, while also fixing redeemer-pointer indexing behavior and adding regression/property coverage.

Changes:

  • Add Plutus spending-witness support and additional threading (collateral, metadata, validity upper bound, script integrity hash) to createCompatibleTx, with a new CompatibleTxBodyContent record and CompatibleTxError.
  • Fix witness/indexing behavior for proposals/certificates/votes by preserving insertion order (OSet/OMap) and ensuring unwitnessed items occupy redeemer index slots.
  • Add/extend property tests to validate redeemer pointer indexing against ledger resolution and cover new compatible-builder behavior.

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
cardano-api/test/cardano-api-test/Test/Cardano/Api/Transaction/Body/Plutus/RedeemerIndex.hs New property suite asserting API redeemer indices match ledger Indexable/redeemerPointer resolution.
cardano-api/test/cardano-api-test/Test/Cardano/Api/Experimental/Fee.hs Updates compatible-tx tests and adds new properties for spending redeemer order, witness set inclusion, pparams requirement, and extra content threading.
cardano-api/test/cardano-api-test/Test/Cardano/Api/Experimental.hs Adds properties verifying proposal insertion-order indexing and certificate indexing that counts unwitnessed certs.
cardano-api/test/cardano-api-test/cardano-api-test.hs Wires the new redeemer-index test group into the test runner.
cardano-api/src/Cardano/Api/Tx/Internal/Body.hs Keeps unwitnessed certificates in witnessable extraction to preserve redeemer index slots; updates proposal-indexing docs.
cardano-api/src/Cardano/Api/Tx.hs Reorders/clarifies export comment for witnessable extractors.
cardano-api/src/Cardano/Api/Internal/Orphans/Serialisation.hs Adds ToJSON for DijkstraLedgerPredFailure.
cardano-api/src/Cardano/Api/Experimental/Tx/Internal/BodyContent/New.hs Includes unwitnessed cert placeholders; makes vote extraction total to avoid index shifts on misses.
cardano-api/src/Cardano/Api/Experimental/Plutus/Internal/ScriptWitness.hs Exports mkSpendingScriptDatum helper for spending-purpose datum construction.
cardano-api/src/Cardano/Api/Experimental/Plutus/Internal/IndexedPlutusScriptWitness.hs Preserves insertion order for certificates/proposals during stable sort by returning EQ intra-category.
cardano-api/src/Cardano/Api/Experimental/Plutus.hs Re-exports mkSpendingScriptDatum.
cardano-api/src/Cardano/Api/Experimental.hs Re-exports mkSpendingScriptDatum.
cardano-api/src/Cardano/Api/Compatible/Tx.hs Major rewrite: createCompatibleTx now takes CompatibleTxBodyContent, supports Plutus spending witnesses, computes script integrity hash, threads metadata/ttl/collateral, and fixes witness inclusion.
cardano-api/cardano-api.cabal Adds cardano-data to test-suite dependencies and includes the new test module.
.changes/20260811_cardano_api_redeemer_pointer_indexing.yml Changelog fragment for redeemer pointer indexing fixes (includes breaking + tests).
.changes/20260807_cardano_api_compatible_plutus.yml Changelog fragment for compatible builder Plutus support and breaking API changes.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread cardano-api/src/Cardano/Api/Compatible/Tx.hs

@palas palas left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think there are a couple of issues that should be resolved before merging, and I also included a couple of potential readability improvement opportunities that I saw.

I still haven't had time to look at the tests yet too.

But it is looking good 👍

Comment on lines +179 to +186
-- Order must stay OMap insertion order; the shared
-- Witnessable-based indexing (via 'extractWitnessableProposals') preserves it.
proposalWitnesses
:: [(Witnessable ProposalItem (ShelleyLedgerEra era), AnyWitness (ShelleyLedgerEra era))]
proposalWitnesses =
[ (ix, witness)
| (_, (ix, witness)) <-
indexWitnessedTxProposalProcedures conwayOnwards proposalProcedures
]
Exp.obtainCommonConstraints (convert conwayOnwards) $
Exp.extractWitnessableProposals $
Just proposalProcedures

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think the function is getting too large (even ignoring the where bits).

And proposalWitnesses doesn't need to be in the case, it could be moved to the where (having its own small case), and that would allow moving allWitnesses and sData to the where too (txAuxData can moved to the where already), and I think that would make the body of the function much more manageable.

Actually, updateTxBody wouldn't need to be here either, because I think it doesn't make use of the Either monad, so it wouldn't need to be monadic, it could be moved to the where too, but that is out of scope of the PR

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done in d2c152c. proposalWitnesses, updateTxBody, allWitnesses, sData and txAuxData moved to the where clause, so the Either block is now just the integrity hash step. One subtlety: the ProposalProcedures arm needed its own shelleyBasedEraConstraints wrap once hoisted, since it had been borrowing the constraint from the do block's wrapper.

Comment thread cardano-api/src/Cardano/Api/Compatible/Tx.hs Outdated
Comment thread cardano-api/src/Cardano/Api/Compatible/Tx.hs Outdated
Comment thread cardano-api/src/Cardano/Api/Compatible/Tx.hs Outdated
:: L.AlonzoEraScript ledgerera
=> [(TxIn, AnyWitness ledgerera)]
-> [(Witnessable TxInItem ledgerera, AnyWitness ledgerera)]
witnessableTxIns txIns' = L.nub [(WitTxIn txIn, wit) | (txIn, wit) <- txIns']

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We should validate there are no repeated TxIns in the list. Or at least that there are no two TxIns with different witnesses, because that would mess up the redeemer pointers

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good catch. I checked how this behaves across the builders: witnessableTxIns is a faithful copy of the experimental extractWitnessableTxIns, which is itself identical to the legacy one, so all three share this gap. Two entries with the same TxIn but different witnesses both survive the nub, and the pointer indices shift against the body's deduplicated input set. The result is rejected client-side by transaction build during execution-unit evaluation, or at submission with ExtraRedeemers for build-raw-style paths; in one narrow case it validates with the extra witness silently ignored, provably never misassigned. A proper fix touches the compatible, experimental and legacy APIs, plus arguably cardano-cli, which already dedupes collateral but not spending inputs, so I split it out into #1324. I also fixed the stale dedupInputsByTxIn reference in the comment here.

@carbolymer
carbolymer changed the base branch from master to mgalazyn/fix/experimental-redeemer-pointer-indexing August 21, 2026 13:27
@carbolymer
carbolymer force-pushed the mgalazyn/feature/compatible-plutus branch from 26aaf4a to 70d5345 Compare August 21, 2026 13:28
@carbolymer
carbolymer requested a review from a team as a code owner August 21, 2026 13:28
Base automatically changed from mgalazyn/fix/experimental-redeemer-pointer-indexing to master August 27, 2026 14:22
createCompatibleTx now takes a CompatibleTxBodyContent record with
per-input AnyWitness values, and computes spending redeemer pointers,
witness datums, the script integrity hash, collateral inputs,
transaction metadata and the validity upper bound. Witness indexing is
shared with the experimental transaction builder. Also export the
mkSpendingScriptDatum smart constructor from Cardano.Api.Experimental.
- Include vote script witnesses in createCompatibleTx: voting
  redeemers, scripts, script integrity hash contribution and
  reference inputs, with a regression test
- Remove the unreachable
  CompatibleTxProtocolParametersConversionError constructor
- Simplify createCompatibleTx: hoist the pure bindings out of the
  Either block, collapse setRefInputs into a single comprehension,
  rewrite setScriptWitnesses without Endo
- Correct the stale dedupInputsByTxIn reference in the redeemer
  pointer ordering comment
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.

3 participants