Skip to content

Add text envelope serialisation for AnyPlutusScript#1156

Merged
Jimbo4350 merged 2 commits into
masterfrom
jordan/1240-has-text-envelope-any-plutus-script
Mar 30, 2026
Merged

Add text envelope serialisation for AnyPlutusScript#1156
Jimbo4350 merged 2 commits into
masterfrom
jordan/1240-has-text-envelope-any-plutus-script

Conversation

@Jimbo4350
Copy link
Copy Markdown
Contributor

Changelog

- description: |
    Add serialiseAnyPlutusScriptToTextEnvelope and
    deserialiseAnyPlutusScriptFromTextEnvelope for AnyPlutusScript,
    following the existing ScriptInAnyLang pattern using FromSomeType
    and deserialiseFromTextEnvelopeAnyOf.
# uncomment types applicable to the change:
  type:
   - feature        # introduces a new feature
  # - breaking       # the API has changed in a breaking way
  # - compatible     # the API has changed but is non-breaking
  # - optimisation   # measurable performance improvements
  # - refactoring    # QoL changes
  # - bugfix         # fixes a defect
  # - test           # fixes/modifies tests
  # - maintenance    # not directly related to the code
  # - release        # related to a new release preparation
  # - documentation  # change in code docs, haddocks...
# uncomment at least one main project this PR is associated with
  projects:
   - cardano-api
  # - cardano-api-gen
  # - cardano-rpc
  # - cardano-wasm

Context

AnyPlutusScript existentially quantifies the Plutus language, so it cannot have a HasTextEnvelope instance directly (since textEnvelopeType :: AsType a -> TextEnvelopeType has no value to pattern match on to recover the existential lang). Instead, this adds standalone serialisation/deserialisation functions following the same pattern used by ScriptInAnyLang (textEnvelopeToScript in Cardano.Api.Plutus.Internal.Script).

Relates to: IntersectMBO/cardano-cli#1240

How to trust this PR

  • The serialisation function delegates to the existing HasTextEnvelope (PlutusScriptInEra lang era) instance, preserving correct per-language envelope types (PlutusScriptV1, PlutusScriptV2, etc.)
  • The deserialisation function uses deserialiseFromTextEnvelopeAnyOf with FromSomeType entries for all four Plutus language versions
  • Both functions are re-exported from Cardano.Api.Experimental.Plutus and Cardano.Api.Experimental

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 marked this pull request as ready for review March 25, 2026 13:37
Copilot AI review requested due to automatic review settings March 25, 2026 13:37
Copy link
Copy Markdown
Contributor

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

Adds text envelope serialisation/deserialisation helpers for AnyPlutusScript, enabling round-tripping via TextEnvelope despite the existential Plutus language parameter.

Changes:

  • Introduce serialiseAnyPlutusScriptToTextEnvelope delegating to existing HasTextEnvelope (PlutusScriptInEra lang era) instances.
  • Introduce deserialiseAnyPlutusScriptFromTextEnvelope using deserialiseFromTextEnvelopeAnyOf with FromSomeType over supported Plutus versions.
  • Re-export the new helpers from Cardano.Api.Experimental.Plutus and Cardano.Api.Experimental.

Reviewed changes

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

File Description
cardano-api/src/Cardano/Api/Experimental/Plutus/Internal/Script.hs Implements text envelope serialise/deserialise helpers for AnyPlutusScript.
cardano-api/src/Cardano/Api/Experimental/Plutus.hs Re-exports the new API from the experimental Plutus module.
cardano-api/src/Cardano/Api/Experimental.hs Re-exports the new API from the top-level experimental module.

Comment on lines +207 to +218
serialiseAnyPlutusScriptToTextEnvelope
:: Maybe TextEnvelopeDescr -> AnyPlutusScript era -> TextEnvelope
serialiseAnyPlutusScriptToTextEnvelope mbDescr (AnyPlutusScript script) =
obtainLangConstraints (plutusScriptInEraSLanguage script) $
serialiseToTextEnvelope mbDescr script

deserialiseAnyPlutusScriptFromTextEnvelope
:: forall era
. L.Era era
=> TextEnvelope
-> Either TextEnvelopeError (AnyPlutusScript era)
deserialiseAnyPlutusScriptFromTextEnvelope =
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

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

These functions are part of the exported API (re-exported from Cardano.Api.Experimental.*) but currently have no Haddock explaining expected envelope types, version handling, or common failure modes (e.g., wrong TextEnvelopeType). Adding concise Haddock (including that deserialisation supports the enumerated Plutus versions and that the envelope type is determined by the underlying PlutusScriptInEra instance) will make the new API safer and easier to use.

Copilot uses AI. Check for mistakes.
Comment on lines +213 to +227
deserialiseAnyPlutusScriptFromTextEnvelope
:: forall era
. L.Era era
=> TextEnvelope
-> Either TextEnvelopeError (AnyPlutusScript era)
deserialiseAnyPlutusScriptFromTextEnvelope =
deserialiseFromTextEnvelopeAnyOf textEnvTypes
where
textEnvTypes :: [FromSomeType HasTextEnvelope (AnyPlutusScript era)]
textEnvTypes =
[ FromSomeType (asType @(PlutusScriptInEra L.PlutusV1 era)) AnyPlutusScript
, FromSomeType (asType @(PlutusScriptInEra L.PlutusV2 era)) AnyPlutusScript
, FromSomeType (asType @(PlutusScriptInEra L.PlutusV3 era)) AnyPlutusScript
, FromSomeType (asType @(PlutusScriptInEra L.PlutusV4 era)) AnyPlutusScript
]
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

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

The supported Plutus versions are hard-coded here; when a new Plutus language version is introduced, this list must be updated or deserialisation will silently not support the new envelope type. Consider centralising this list (e.g., a single top-level allAnyPlutusScriptTextEnvelopeTypes value reused anywhere similar logic exists) and/or adding an explicit comment that this must be kept in sync with the set of supported Plutus language versions.

Suggested change
deserialiseAnyPlutusScriptFromTextEnvelope
:: forall era
. L.Era era
=> TextEnvelope
-> Either TextEnvelopeError (AnyPlutusScript era)
deserialiseAnyPlutusScriptFromTextEnvelope =
deserialiseFromTextEnvelopeAnyOf textEnvTypes
where
textEnvTypes :: [FromSomeType HasTextEnvelope (AnyPlutusScript era)]
textEnvTypes =
[ FromSomeType (asType @(PlutusScriptInEra L.PlutusV1 era)) AnyPlutusScript
, FromSomeType (asType @(PlutusScriptInEra L.PlutusV2 era)) AnyPlutusScript
, FromSomeType (asType @(PlutusScriptInEra L.PlutusV3 era)) AnyPlutusScript
, FromSomeType (asType @(PlutusScriptInEra L.PlutusV4 era)) AnyPlutusScript
]
-- | List of all supported Plutus script text envelope types for 'AnyPlutusScript'.
-- NOTE: This must be kept in sync with the set of supported 'Plutus.PlutusLanguage'
-- / 'L.PlutusLanguage' versions in this module.
allAnyPlutusScriptTextEnvelopeTypes
:: forall era. L.Era era
=> [FromSomeType HasTextEnvelope (AnyPlutusScript era)]
allAnyPlutusScriptTextEnvelopeTypes =
[ FromSomeType (asType @(PlutusScriptInEra L.PlutusV1 era)) AnyPlutusScript
, FromSomeType (asType @(PlutusScriptInEra L.PlutusV2 era)) AnyPlutusScript
, FromSomeType (asType @(PlutusScriptInEra L.PlutusV3 era)) AnyPlutusScript
, FromSomeType (asType @(PlutusScriptInEra L.PlutusV4 era)) AnyPlutusScript
]
deserialiseAnyPlutusScriptFromTextEnvelope
:: forall era
. L.Era era
=> TextEnvelope
-> Either TextEnvelopeError (AnyPlutusScript era)
deserialiseAnyPlutusScriptFromTextEnvelope =
deserialiseFromTextEnvelopeAnyOf allAnyPlutusScriptTextEnvelopeTypes

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor

@palas palas left a comment

Choose a reason for hiding this comment

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

Looks good 👍 . There are two things that bother me, but I cannot think of any easy way of solving them:

  • The fact that we are not using the HasTextEnvelope instance
  • What copilot pointed out, that we won't get compiler errors when adding a new version of Plutus

Well and, yes, maybe it would also be good to add a roundtrip test and haddock

@Jimbo4350 Jimbo4350 force-pushed the jordan/1240-has-text-envelope-any-plutus-script branch 2 times, most recently from 0b6b10b to bf6c10d Compare March 26, 2026 14:33
Use nonNativeLanguages and withSLanguage to derive textEnvTypes
so new Plutus versions are picked up automatically and GHC
enforces handling in constraint witness functions.
@Jimbo4350 Jimbo4350 force-pushed the jordan/1240-has-text-envelope-any-plutus-script branch from bf6c10d to ca16748 Compare March 26, 2026 15:08
@Jimbo4350 Jimbo4350 enabled auto-merge March 26, 2026 15:22
Fix serialiseToCBOR to extract raw script bytes from PlutusRunnable
instead of using L.serialize' which adds CBOR framing that
deserialiseFromCBOR does not expect.

Add CBOR and TextEnvelope roundtrip tests for PlutusScriptInEra and
AnyPlutusScript. Add haddocks for the text envelope functions.
@Jimbo4350 Jimbo4350 force-pushed the jordan/1240-has-text-envelope-any-plutus-script branch from ca16748 to 9239e07 Compare March 26, 2026 15:39
@Jimbo4350 Jimbo4350 added this pull request to the merge queue Mar 26, 2026
@github-merge-queue github-merge-queue Bot removed this pull request from the merge queue due to no response for status checks Mar 26, 2026
@Jimbo4350 Jimbo4350 added this pull request to the merge queue Mar 30, 2026
Merged via the queue into master with commit 0880e7e Mar 30, 2026
33 checks passed
@Jimbo4350 Jimbo4350 deleted the jordan/1240-has-text-envelope-any-plutus-script branch March 30, 2026 16:31
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