Skip to content

Replace parameterized ScriptRequirements GADT with flat unparameterized ADTs#1348

Open
Jimbo4350 wants to merge 9 commits intomasterfrom
jordan/1082-make-NoScriptDatum-uninhabitable
Open

Replace parameterized ScriptRequirements GADT with flat unparameterized ADTs#1348
Jimbo4350 wants to merge 9 commits intomasterfrom
jordan/1082-make-NoScriptDatum-uninhabitable

Conversation

@Jimbo4350
Copy link
Contributor

@Jimbo4350 Jimbo4350 commented Mar 13, 2026

Changelog

- description: |
    Replace parameterized ScriptRequirements GADT with flat unparameterized ADTs
  type:
  - refactoring

Context

Replaces the parameterized ScriptRequirements GADT and its associated type families (OptionalDatum, MintPolicyId) with flat, context-specific ADTs that make invalid states unrepresentable — in particular, NoScriptDatum can no longer appear in types where a datum is expected.

Closes #1082

Commit structure

  1. Introduce flat unparameterized ADTs — core type definitions in Script/Type.hs
  2. Update shared option parsers and read utilitiesCommon/Option.hs, Read/Common.hs, Type/Common.hs
  3. Spend — Type + Read
  4. Mint — Type + Read
  5. Certificate — Type + Read
  6. Vote — Type + Read
  7. Withdrawal — Type + Read
  8. Proposal — Type + Read
  9. Propagate to consumers — Compatible layer, runners, build config, tests

How to trust this PR

Each per-script-type commit touches only the Type.hs and Read.hs for that script context, making it easy to review in isolation. The final consumer propagation commit covers the mechanical updates needed to wire everything together. The overall diff is a net reduction in code (~100 fewer lines) due to eliminating standalone deriving instances and type family machinery.

Checklist

  • Commit sequence broadly makes sense and commits have useful messages
  • New tests are added if needed and existing tests are updated
  • Self-reviewed the diff

@Jimbo4350 Jimbo4350 force-pushed the jordan/1082-make-NoScriptDatum-uninhabitable branch from b6da2fc to 55ab683 Compare March 23, 2026 13:40
Comment on lines +39 to +40
createSimpleReferenceScriptFromCliArgs txin polId =
AnyMintScriptSimpleRef txin polId

Check warning

Code scanning / HLint

Eta reduce Warning

cardano-cli/src/Cardano/CLI/EraBased/Script/Mint/Type.hs:(39,1)-(40,35): Warning: Eta reduce
  
Found:
  createSimpleReferenceScriptFromCliArgs txin polId
    = AnyMintScriptSimpleRef txin polId
  
Perhaps:
  createSimpleReferenceScriptFromCliArgs = AnyMintScriptSimpleRef
@Jimbo4350 Jimbo4350 changed the title Split script datum types to prepare for uninhabitable NoScriptDatum Replace parameterized ScriptRequirements GADT with flat unparameterized ADTs Mar 23, 2026
@Jimbo4350 Jimbo4350 force-pushed the jordan/1082-make-NoScriptDatum-uninhabitable branch 4 times, most recently from dfbd202 to c4f71da Compare March 23, 2026 16:13
@Jimbo4350 Jimbo4350 requested a review from Copilot March 23, 2026 16:21
@Jimbo4350 Jimbo4350 marked this pull request as ready for review March 23, 2026 16:21
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Refactors script witness requirements in cardano-cli by replacing a parameterized ScriptRequirements GADT + type families with flat, context-specific ADTs (AnySpendScript, AnyMintScript, AnyNonAssetScript) to make invalid states unrepresentable and simplify consumers.

Changes:

  • Introduces new flat ADTs for script requirements and updates all script-type modules (spend/mint/cert/vote/withdrawal/proposal) to use them.
  • Updates CLI parsing and witness reading logic to construct/read the new requirement types.
  • Adjusts build/test infrastructure and a few query/ledger/protocol-parameter related call sites to newer APIs.

Reviewed changes

Copilot reviewed 41 out of 42 changed files in this pull request and generated 12 comments.

Show a summary per file
File Description
flake.nix Updates dev-shell package set (consensus package rename).
cardano-cli/test/cardano-cli-golden/files/golden/help/query_ledger-peer-snapshot.cli Updates golden help output (removes --all-ledger-peers).
cardano-cli/test/cardano-cli-golden/files/golden/help/latest_query_ledger-peer-snapshot.cli Updates golden help output (removes --all-ledger-peers).
cardano-cli/test/cardano-cli-golden/files/golden/help/conway_query_ledger-peer-snapshot.cli Updates golden help output (removes --all-ledger-peers).
cardano-cli/test/cardano-cli-golden/files/golden/help.cli Updates aggregated golden help output accordingly.
cardano-cli/test/cardano-cli-golden/Test/Golden/Legacy/Genesis/Create.hs Changes golden test to assert V2 cost model parameter count.
cardano-cli/test/cardano-cli-golden/Test/Golden/CreateTestnetData.hs Updates stake pool relay accessor names.
cardano-cli/src/Cardano/CLI/Type/Common.hs Updates stake pool state construction to new ledger API signature.
cardano-cli/src/Cardano/CLI/Read.hs Refactors experimental script reading imports and plumbs through updated Plutus helpers.
cardano-cli/src/Cardano/CLI/EraBased/Transaction/Run.hs Updates submit result constructors and fee parameter accessors/types.
cardano-cli/src/Cardano/CLI/EraBased/Transaction/Command.hs Swaps GADT requirements for new Any*Script types in tx command args.
cardano-cli/src/Cardano/CLI/EraBased/Script/Withdrawal/Type.hs Constructs new AnyNonAssetScript requirements for withdrawals.
cardano-cli/src/Cardano/CLI/EraBased/Script/Withdrawal/Read.hs Reads withdrawal witnesses from new requirement types.
cardano-cli/src/Cardano/CLI/EraBased/Script/Vote/Type.hs Constructs new AnyNonAssetScript requirements for votes.
cardano-cli/src/Cardano/CLI/EraBased/Script/Vote/Read.hs Reads vote witnesses from new requirement types.
cardano-cli/src/Cardano/CLI/EraBased/Script/Type.hs Replaces ScriptRequirements GADT with flat context-specific ADTs.
cardano-cli/src/Cardano/CLI/EraBased/Script/Spend/Type.hs Constructs new AnySpendScript requirements for spending.
cardano-cli/src/Cardano/CLI/EraBased/Script/Spend/Read.hs Reads spending witnesses from new requirement types.
cardano-cli/src/Cardano/CLI/EraBased/Script/Read/Common.hs Simplifies simple-script JSON fallback path.
cardano-cli/src/Cardano/CLI/EraBased/Script/Proposal/Type.hs Constructs new AnyNonAssetScript requirements for proposals.
cardano-cli/src/Cardano/CLI/EraBased/Script/Proposal/Read.hs Reads proposal witnesses from new requirement types.
cardano-cli/src/Cardano/CLI/EraBased/Script/Mint/Type.hs Constructs new AnyMintScript requirements for minting.
cardano-cli/src/Cardano/CLI/EraBased/Script/Mint/Read.hs Reads mint witnesses from new requirement types.
cardano-cli/src/Cardano/CLI/EraBased/Script/Certificate/Type.hs Constructs new AnyNonAssetScript requirements for certs.
cardano-cli/src/Cardano/CLI/EraBased/Script/Certificate/Read.hs Reads cert witnesses from new requirement types.
cardano-cli/src/Cardano/CLI/EraBased/Query/Run.hs Drops “all ledger peers” path and refactors some era handling + decoders.
cardano-cli/src/Cardano/CLI/EraBased/Query/Option.hs Removes --all-ledger-peers flag parsing.
cardano-cli/src/Cardano/CLI/EraBased/Query/Command.hs Removes CliLedgerPeers and field from the command args.
cardano-cli/src/Cardano/CLI/EraBased/Governance/Actions/Option.hs Updates conversion for utxo-cost-per-byte.
cardano-cli/src/Cardano/CLI/EraBased/Genesis/Run.hs Updates stake pool params types/accessors to new ledger API.
cardano-cli/src/Cardano/CLI/EraBased/Genesis/CreateTestnetData/Run.hs Updates stake pool params types/accessors in testnet data generator.
cardano-cli/src/Cardano/CLI/EraBased/Common/Option.hs Updates parsers and switches to Any*Script requirement types.
cardano-cli/src/Cardano/CLI/Compatible/Transaction/ScriptWitness.hs Reworks compatible certificate-witness reading around new script requirement types.
cardano-cli/src/Cardano/CLI/Compatible/Transaction/Run.hs Updates compatible tx flow for new cert-witness requirements and Plutus decoding path.
cardano-cli/src/Cardano/CLI/Compatible/Transaction/Option.hs Updates compatible tx option typing for votes.
cardano-cli/src/Cardano/CLI/Compatible/Transaction/Command.hs Updates compatible tx command args to new script requirement types.
cardano-cli/src/Cardano/CLI/Compatible/Read.hs Adds AnyPlutusScript wrapper and refactors Plutus script deserialisation.
cardano-cli/src/Cardano/CLI/Compatible/Json/Friendly.hs Updates ledger tx type parameters and ledger-role kind annotations.
cardano-cli/src/Cardano/CLI/Byron/Tx.hs Updates submit result constructors (network namespace).
cardano-cli/cardano-cli.cabal Adjusts dependency bounds and adds test deps (e.g., containers, cardano-ledger-core).
cabal.project Updates index-state pins for Hackage/CHaP.
Comments suppressed due to low confidence (5)

cardano-cli/src/Cardano/CLI/EraBased/Query/Run.hs:1

  • When decodeBigLedgerPeerSnapshot fails, the decoder error is discarded (_decoderError) and only the CBOR is printed. Previously, the decoder error was emitted to stderr, which is useful for diagnosing incompatibilities. Consider preserving the warning behavior (e.g., log the decoder error) while still dumping CBOR as a fallback.
{-# LANGUAGE DataKinds #-}

cardano-cli/src/Cardano/CLI/EraBased/Transaction/Run.hs:1

  • This mixes Lovelace and ledger Coin (L.Coin) in a way that is unlikely to typecheck (e.g., toInteger txFeePerByte typically won’t compile for Lovelace) and also muddies the unit semantics (ledger fee coefficient minFeeA is conceptually 'coin per byte', not an arbitrary lovelace amount). Consider changing calculateByronWitnessFees to accept/return a consistent coin type (either ledger Coin or API Lovelace) and convert explicitly at the boundary (e.g., unwrap Lovelace or wrap Coin), so the multiplication uses the correct numeric representation.
    cardano-cli/src/Cardano/CLI/EraBased/Transaction/Run.hs:1
  • This mixes Lovelace and ledger Coin (L.Coin) in a way that is unlikely to typecheck (e.g., toInteger txFeePerByte typically won’t compile for Lovelace) and also muddies the unit semantics (ledger fee coefficient minFeeA is conceptually 'coin per byte', not an arbitrary lovelace amount). Consider changing calculateByronWitnessFees to accept/return a consistent coin type (either ledger Coin or API Lovelace) and convert explicitly at the boundary (e.g., unwrap Lovelace or wrap Coin), so the multiplication uses the correct numeric representation.
    cardano-cli/test/cardano-cli-golden/Test/Golden/Legacy/Genesis/Create.hs:1
  • This golden test changes from asserting the presence/shape of the Plutus V1 cost model in an Alonzo genesis to asserting Plutus V2 with 175 parameters. That’s a significant behavioral expectation shift and looks unrelated to the stated PR goal (script-requirements refactor). If this is intentional, it should be justified in the PR description/changelog (and ideally linked to a specific issue/requirement); otherwise, consider keeping this PR focused by moving this test change into a separate PR.
    cardano-cli/test/cardano-cli-golden/Test/Golden/Legacy/Genesis/Create.hs:1
  • This golden test changes from asserting the presence/shape of the Plutus V1 cost model in an Alonzo genesis to asserting Plutus V2 with 175 parameters. That’s a significant behavioral expectation shift and looks unrelated to the stated PR goal (script-requirements refactor). If this is intentional, it should be justified in the PR description/changelog (and ideally linked to a specific issue/requirement); otherwise, consider keeping this PR focused by moving this test change into a separate PR.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 446 to 455
pQueryLedgerPeerSnapshotCmd envCli =
fmap QueryLedgerPeerSnapshotCmd $
QueryLedgerPeerSnapshotCmdArgs
<$> pQueryCommons @era envCli
<*> pLedgerPeersKind
<*> pFormatQueryOutputFlags
"ledger-peer-snapshot"
[ flagFormatJson & setDefault
, flagFormatYaml
]
<*> pMaybeOutputFile
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

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

This PR is described as a refactor of ScriptRequirements, but it also removes the --all-ledger-peers CLI flag (and the associated behavior) from query ledger-peer-snapshot. If this behavior removal is intentional, it should be explicitly called out in the PR description/changelog as a user-facing breaking change; otherwise, consider restoring the flag and plumbing it through to the query decoder as before.

Copilot uses AI. Check for mistakes.
era <- hoist liftIO $ supportedEra cEra
let sbe = convert era

result <- easyRunQuery (queryLedgerPeerSnapshot sbe)
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

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

When decodeBigLedgerPeerSnapshot fails, the decoder error is discarded (_decoderError) and only the CBOR is printed. Previously, the decoder error was emitted to stderr, which is useful for diagnosing incompatibilities. Consider preserving the warning behavior (e.g., log the decoder error) while still dumping CBOR as a fallback.

Copilot uses AI. Check for mistakes.
hoist liftIO $
obtainCommonConstraints era $
case decodeBigLedgerPeerSnapshot shelleyNtcVersion result of
Left (bs, _decoderError) -> pure $ Left bs
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

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

When decodeBigLedgerPeerSnapshot fails, the decoder error is discarded (_decoderError) and only the CBOR is printed. Previously, the decoder error was emitted to stderr, which is useful for diagnosing incompatibilities. Consider preserving the warning behavior (e.g., log the decoder error) while still dumping CBOR as a fallback.

Suggested change
Left (bs, _decoderError) -> pure $ Left bs
Left (bs, decoderError) -> do
putStrLn ("Warning: failed to decode LedgerPeerSnapshot: " ++ show decoderError)
pure $ Left bs

Copilot uses AI. Check for mistakes.
Comment on lines +905 to +908
case result of
Left (bs :: LBS.ByteString) -> do
fromExceptTCli $ pPrintCBOR bs
Right (SomeLedgerPeerSnapshot snapshot) -> do
Right (snapshot :: LedgerPeerSnapshot) -> do
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

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

When decodeBigLedgerPeerSnapshot fails, the decoder error is discarded (_decoderError) and only the CBOR is printed. Previously, the decoder error was emitted to stderr, which is useful for diagnosing incompatibilities. Consider preserving the warning behavior (e.g., log the decoder error) while still dumping CBOR as a fallback.

Copilot uses AI. Check for mistakes.
Comment on lines +38 to +46
readFileSimpleScript file era = do
bs <- readFileCli file
case deserialiseFromJSON bs of
Left _ -> case era of
Exp.DijkstraEra -> error "TODO Dijkstra: Simple script not supported"
Exp.ConwayEra -> Exp.obtainConwayConstraints era $ do
-- In addition to the TextEnvelope format, we also try to
-- deserialize the JSON representation of SimpleScripts..
script :: SimpleScript <- fromEitherCli $ Aeson.eitherDecodeStrict' bs
let s :: L.NativeScript (Exp.LedgerEra era) = obtainCommonConstraints era $ toAllegraTimelock script
return $ Exp.SimpleScript s
Left _ -> do
-- In addition to the TextEnvelope format, we also try to
-- deserialize the JSON representation of SimpleScripts..
script :: SimpleScript <- fromEitherCli $ Aeson.eitherDecodeStrict' bs
let s :: L.NativeScript (Exp.LedgerEra era) = obtainCommonConstraints era $ toAllegraTimelock script
return $ obtainCommonConstraints (era :: Exp.Era era) $ Exp.SimpleScript s
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

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

This removes the earlier era-based guard that explicitly rejected simple scripts for DijkstraEra (previously an error \"TODO Dijkstra: Simple script not supported\"). If simple scripts are still unsupported in Dijkstra, this change will now attempt to construct/return a script anyway, which can lead to incorrect behavior or later failures. Either reintroduce the explicit rejection for unsupported eras, or implement the intended Dijkstra support end-to-end (including constraints and witness creation).

Copilot uses AI. Check for mistakes.
cardano-crypto-class ^>=2.3,
cardano-crypto-wrapper ^>=1.7,
cardano-crypto-class ^>=2.2.3.2,
cardano-crypto-wrapper ^>=1.6,
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

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

The PR introduces/uses newer API surface in several places (e.g., new namespaced submit result constructors, additional Plutus script versions/types), but the cabal bounds are moved down (e.g., cardano-api ^>=10.25^>=10.24, plus downgrades for cardano-ping and crypto libs). Please verify the chosen lower bounds actually provide the constructors/types referenced in this PR; otherwise, raise the bounds (or add appropriate CPP/compat shims) to keep the build plan consistent.

Suggested change
cardano-crypto-wrapper ^>=1.6,
cardano-crypto-wrapper ^>=1.7,

Copilot uses AI. Check for mistakes.
cardano-ledger-core,
cardano-ledger-dijkstra,
cardano-ping ^>=0.10,
cardano-ping ^>=0.9,
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

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

The PR introduces/uses newer API surface in several places (e.g., new namespaced submit result constructors, additional Plutus script versions/types), but the cabal bounds are moved down (e.g., cardano-api ^>=10.25^>=10.24, plus downgrades for cardano-ping and crypto libs). Please verify the chosen lower bounds actually provide the constructors/types referenced in this PR; otherwise, raise the bounds (or add appropriate CPP/compat shims) to keep the build plan consistent.

Suggested change
cardano-ping ^>=0.9,
cardano-ping ^>=0.10.0.0,

Copilot uses AI. Check for mistakes.
ordered-containers,
ouroboros-consensus:{cardano, ouroboros-consensus},
ouroboros-consensus,
ouroboros-consensus-cardano,
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

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

The PR introduces/uses newer API surface in several places (e.g., new namespaced submit result constructors, additional Plutus script versions/types), but the cabal bounds are moved down (e.g., cardano-api ^>=10.25^>=10.24, plus downgrades for cardano-ping and crypto libs). Please verify the chosen lower bounds actually provide the constructors/types referenced in this PR; otherwise, raise the bounds (or add appropriate CPP/compat shims) to keep the build plan consistent.

Suggested change
ouroboros-consensus-cardano,
ouroboros-consensus-cardano ^>=0.17.0.0,

Copilot uses AI. Check for mistakes.
Comment on lines +2715 to +2717
pMinFeePerByteFactor :: Parser Lovelace
pMinFeePerByteFactor =
Opt.option (readerFromParsecParser parseCoinPerByte) $
Opt.option (readerFromParsecParser parseLovelace) $
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

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

These options represent 'per-byte' fee parameters, but are now parsed as plain Lovelace, which loses unit safety and makes it easier to accidentally pass the wrong value/type through the stack. Since other call sites still appear to expect/construct CoinPerByte (e.g., via L.CoinPerByte), consider restoring a dedicated CoinPerByte parser type (or introducing a small newtype wrapper for CLI) and only converting to/from raw lovelace at the precise API boundary.

Copilot uses AI. Check for mistakes.
Comment on lines +2938 to +2940
pUTxOCostPerByte :: Parser Lovelace
pUTxOCostPerByte =
Opt.option (readerFromParsecParser parseCoinPerByte) $
Opt.option (readerFromParsecParser parseLovelace) $
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

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

These options represent 'per-byte' fee parameters, but are now parsed as plain Lovelace, which loses unit safety and makes it easier to accidentally pass the wrong value/type through the stack. Since other call sites still appear to expect/construct CoinPerByte (e.g., via L.CoinPerByte), consider restoring a dedicated CoinPerByte parser type (or introducing a small newtype wrapper for CLI) and only converting to/from raw lovelace at the precise API boundary.

Copilot uses AI. Check for mistakes.
@Jimbo4350 Jimbo4350 force-pushed the jordan/1082-make-NoScriptDatum-uninhabitable branch 3 times, most recently from ce64a75 to a369f55 Compare March 23, 2026 17:49
The previous ScriptRequirements GADT and associated type families
(OptionalDatum, MintPolicyId) forced callers to pattern match on
nullary constructors like NoPolicyId and NoScriptDatumAllowed that
carry no information. For example, in the old Certificate/Read.hs:

    PlutusRefScriptCliArgs
        refInput
        (AnySLanguage lang)
        Exp.NoScriptDatumAllowed  -- meaningless
        NoPolicyId                -- meaningless
        redeemerFile
        execUnits

These constructors exist only to fill slots demanded by the type
families in contexts where those fields don't apply. This is an
inherent cost of a single GADT polymorphic over all script contexts.

Replace with flat, context-specific ADTs that simply omit fields
irrelevant to their context:
- PlutusSpendingScriptRequirements: carries an optional datum
- PlutusMintingScriptRequirements: carries a PolicyId
- PlutusNonAssetScriptRequirements: needs neither (certificates,
  voting, withdrawals, proposals)
Update Compatible layer, Transaction runners, and option parsers
to use the new flat script types.
@Jimbo4350 Jimbo4350 force-pushed the jordan/1082-make-NoScriptDatum-uninhabitable branch from a369f55 to 22dc166 Compare March 23, 2026 17:52
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.

[FR] - Integrate QueryLedgerConfig

2 participants