Skip to content

Commit 6a611d8

Browse files
committed
docs: add comprehensive inline documentation for TxOut JSON parsing refactoring
This commit adds detailed inline documentation to explain the design decisions, assumptions, and potential issues in the refactored TxOut JSON parsing code. Key documentation areas: 1. parseBabbageOnwardsTxOut: - MOTIVATION: Explains this eliminates ~100 lines of duplication - DESIGN: Documents the two-phase parsing strategy (Alonzo + Babbage reconciliation) - ASSUMPTION: Notes BabbageEraOnwards covers exactly three eras 2. parseInlineDatum: - CRITICAL DISTINCTION: Explains why Babbage uses scriptDataJsonToHashable vs Conway+ using scriptDataFromJson (CBOR encoding preservation requirement) - VALIDATION: Documents hash verification logic - POTENTIAL ISSUE: Warns about wildcard pattern assumption 3. reconcileDatums: - BACKWARDS COMPATIBILITY: Lists the three valid JSON formats accepted - ERROR HANDLING: Explains conflicting datum detection and error messages - EXHAUSTIVENESS: Documents how direct GADT matching enables compiler verification when new eras are added to BabbageEraOnwards 4. eraName helper: - Documents switch from ShelleyBasedEra to direct BabbageEraOnwards matching - Explains benefit: compiler enforces exhaustiveness, preventing incomplete updates
1 parent 4c118ad commit 6a611d8

File tree

1 file changed

+48
-4
lines changed
  • cardano-api/src/Cardano/Api/Tx/Internal

1 file changed

+48
-4
lines changed

cardano-api/src/Cardano/Api/Tx/Internal/Output.hs

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -459,8 +459,21 @@ instance IsShelleyBasedEra era => FromJSON (TxOut CtxTx era) where
459459
ShelleyBasedEraConway -> parseBabbageOnwardsTxOut BabbageEraOnwardsConway o
460460
ShelleyBasedEraDijkstra -> parseBabbageOnwardsTxOut BabbageEraOnwardsDijkstra o
461461
where
462-
-- Parse TxOut for Babbage+ eras
463-
-- Handles both Alonzo-style (datumhash/datum) and Babbage-style (inlineDatumhash/inlineDatum) fields
462+
-- Parse TxOut for Babbage+ eras (Babbage, Conway, Dijkstra)
463+
--
464+
-- MOTIVATION: This unified helper eliminates ~100 lines of duplication that previously
465+
-- existed across the three Babbage+ era cases.
466+
--
467+
-- DESIGN: Uses a two-phase parsing strategy:
468+
-- 1. Parse Alonzo-style fields (datumhash/datum) via alonzoTxOutParser
469+
-- 2. Parse Babbage-style fields (inlineDatumhash/inlineDatum) via parseInlineDatum
470+
-- 3. Reconcile both via reconcileDatums, which validates no conflicting datums exist
471+
--
472+
-- This approach maintains backwards compatibility - old JSON with only Alonzo fields
473+
-- still parses correctly, while new JSON can use inline datums.
474+
--
475+
-- ASSUMPTION: BabbageEraOnwards will always cover exactly these three eras. If a new
476+
-- era is added, this code must be updated.
464477
parseBabbageOnwardsTxOut
465478
:: BabbageEraOnwards era
466479
-> Aeson.Object
@@ -472,7 +485,20 @@ instance IsShelleyBasedEra era => FromJSON (TxOut CtxTx era) where
472485
reconcileDatums w alonzoTxOut inlineDatum mReferenceScript
473486

474487
-- Parse inline datum fields from JSON object
475-
-- Handles both inlineDatumhash and inlineDatum fields, validating they match
488+
--
489+
-- Handles both inlineDatumhash and inlineDatum fields, validating they match.
490+
--
491+
-- CRITICAL DISTINCTION: Babbage era uses scriptDataJsonToHashable (returns HashableScriptData)
492+
-- while Conway+ uses scriptDataFromJson (returns ScriptData). This difference exists because
493+
-- Babbage required preserving the original CBOR encoding for hash validation, while Conway+
494+
-- can reconstruct it.
495+
--
496+
-- VALIDATION: When both hash and datum are present, we verify the datum hashes to the
497+
-- provided hash. This catches malformed JSON where they don't match.
498+
--
499+
-- POTENTIAL ISSUE: The wildcard pattern (_ -> scriptDataFromJson) assumes all non-Babbage
500+
-- eras in BabbageEraOnwards use scriptDataFromJson. If a future era needs different handling,
501+
-- this must be updated to explicitly match all constructors.
476502
parseInlineDatum
477503
:: BabbageEraOnwards era
478504
-> Aeson.Object
@@ -500,7 +526,22 @@ instance IsShelleyBasedEra era => FromJSON (TxOut CtxTx era) where
500526
"Should not be possible to create a tx output with either an inline datum hash or an inline datum"
501527

502528
-- Reconcile Alonzo-style and Babbage-style datums and reference scripts
503-
-- This handles the two-phase parsing where both old and new style fields may be present
529+
--
530+
-- This handles the two-phase parsing where both old and new style fields may be present.
531+
--
532+
-- BACKWARDS COMPATIBILITY: Accepts JSON with either:
533+
-- - Only Alonzo fields (datumhash/datum) - common in older transactions
534+
-- - Only Babbage fields (inlineDatumhash/inlineDatum) - modern format
535+
-- - Neither (TxOutDatumNone) - simple payment outputs
536+
--
537+
-- ERROR HANDLING: If *both* Alonzo and Babbage style datums are present, this is a
538+
-- malformed JSON and we fail with a detailed error message showing both datums.
539+
-- This should never happen in correctly formed JSON but protects against corruption.
540+
--
541+
-- EXHAUSTIVENESS: The eraName helper now matches directly on BabbageEraOnwards GADT
542+
-- constructors instead of converting to ShelleyBasedEra. This allows the compiler to
543+
-- verify exhaustiveness - if a new era is added to BabbageEraOnwards, this will fail
544+
-- to compile, forcing developers to update the code.
504545
reconcileDatums
505546
:: BabbageEraOnwards era
506547
-> TxOut CtxTx era
@@ -533,6 +574,9 @@ instance IsShelleyBasedEra era => FromJSON (TxOut CtxTx era) where
533574
Just anyScript -> return $ ReferenceScript w anyScript
534575
return $ TxOut addr v finalDat finalRefScript
535576
where
577+
-- Pattern match directly on GADT instead of converting to ShelleyBasedEra.
578+
-- This enables exhaustiveness checking - adding a new era to BabbageEraOnwards
579+
-- will cause a compile error here, preventing bugs from incomplete updates.
536580
eraName = case w of
537581
BabbageEraOnwardsBabbage -> "Babbage"
538582
BabbageEraOnwardsConway -> "Conway"

0 commit comments

Comments
 (0)