diff --git a/cardano-api/src/Cardano/Api/Tx/Internal/Output.hs b/cardano-api/src/Cardano/Api/Tx/Internal/Output.hs index c000b7dead..8c1f4173ce 100644 --- a/cardano-api/src/Cardano/Api/Tx/Internal/Output.hs +++ b/cardano-api/src/Cardano/Api/Tx/Internal/Output.hs @@ -1,10 +1,12 @@ {-# LANGUAGE DataKinds #-} +{-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DerivingVia #-} {-# LANGUAGE DisambiguateRecordFields #-} {-# LANGUAGE EmptyCase #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GADTs #-} +{-# LANGUAGE InstanceSigs #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} @@ -12,6 +14,7 @@ {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} +{-# LANGUAGE UndecidableInstances #-} module Cardano.Api.Tx.Internal.Output ( -- * Transaction outputs @@ -62,7 +65,7 @@ import Cardano.Api.Era.Internal.Eon.BabbageEraOnwards import Cardano.Api.Era.Internal.Eon.Convert import Cardano.Api.Era.Internal.Eon.ShelleyBasedEra import Cardano.Api.Error (Error (..), displayError) -import Cardano.Api.Hash +import Cardano.Api.HasTypeProxy qualified as HTP import Cardano.Api.Ledger.Internal.Reexport qualified as Ledger import Cardano.Api.Monad.Error import Cardano.Api.Parser.Text qualified as P @@ -81,11 +84,11 @@ import Cardano.Ledger.Alonzo.Core qualified as L import Cardano.Ledger.Api qualified as L import Cardano.Ledger.BaseTypes (StrictMaybe (..)) import Cardano.Ledger.Coin qualified as L -import Cardano.Ledger.Core () import Cardano.Ledger.Core qualified as Core import Cardano.Ledger.Core qualified as Ledger import Cardano.Ledger.Plutus.Data qualified as Plutus +import Codec.CBOR.Encoding (Encoding) import Data.Aeson (object, withObject, (.:), (.:?), (.=)) import Data.Aeson qualified as Aeson import Data.Aeson.Key qualified as Aeson @@ -99,6 +102,7 @@ import Data.Sequence.Strict qualified as Seq import Data.Text (Text) import Data.Text.Encoding qualified as Text import Data.Type.Equality +import Data.Typeable (Typeable) import Data.Word import GHC.Exts (IsList (..)) import GHC.Stack @@ -120,6 +124,24 @@ data TxOut ctx era (TxOutValue era) (TxOutDatum ctx era) (ReferenceScript era) + deriving SerialiseAsCBOR + +instance (Typeable ctx, IsShelleyBasedEra era) => HTP.HasTypeProxy (TxOut ctx era) where + data AsType (TxOut ctx era) = AsTxOut (AsType era) + proxyToAsType :: HTP.Proxy (TxOut ctx era) -> AsType (TxOut ctx era) + proxyToAsType _ = AsTxOut (HTP.asType @era) + +instance (Typeable ctx, IsShelleyBasedEra era) => ToCBOR (TxOut ctx era) where + toCBOR :: TxOut ctx era -> Encoding + toCBOR txOut = + shelleyBasedEraConstraints (shelleyBasedEra @era) $ + Ledger.toEraCBOR @(ShelleyLedgerEra era) (toShelleyTxOutAny shelleyBasedEra txOut) + +instance (Typeable ctx, IsShelleyBasedEra era) => FromCBOR (TxOut ctx era) where + fromCBOR :: Ledger.Decoder s (TxOut ctx era) + fromCBOR = + shelleyBasedEraConstraints (shelleyBasedEra @era) $ + pure (fromShelleyTxOut shelleyBasedEra) <*> L.fromEraCBOR @(ShelleyLedgerEra era) deriving instance Eq (TxOut ctx era) diff --git a/cardano-api/test/cardano-api-test/Test/Cardano/Api/CBOR.hs b/cardano-api/test/cardano-api-test/Test/Cardano/Api/CBOR.hs index 1c1208e957..45d2e5c17d 100644 --- a/cardano-api/test/cardano-api-test/Test/Cardano/Api/CBOR.hs +++ b/cardano-api/test/cardano-api-test/Test/Cardano/Api/CBOR.hs @@ -110,6 +110,21 @@ prop_roundtrip_tx_CBOR = H.property $ do x <- H.forAll $ genTx era shelleyBasedEraConstraints era $ H.trippingCbor (proxyToAsType Proxy) x +prop_roundtrip_tx_out_CBOR :: Property +prop_roundtrip_tx_out_CBOR = H.property $ do + AnyShelleyBasedEra era <- H.noteShowM . H.forAll $ Gen.element [minBound .. maxBound] + x <- H.forAll $ genTx era + txOut <- H.forAll $ Gen.element $ txOuts $ getTxBodyContent $ getTxBody x + let fixedTxOut = hashDatum txOut + shelleyBasedEraConstraints era $ H.trippingCbor (proxyToAsType Proxy) fixedTxOut + where + hashDatum :: TxOut CtxTx era -> TxOut CtxTx era + hashDatum txOut@(TxOut aie val datum rs) = + case datum of + (TxOutSupplementalDatum aeo d) -> + TxOut aie val (TxOutDatumHash aeo (hashScriptDataBytes d)) rs + _ -> txOut + prop_roundtrip_witness_CBOR :: Property prop_roundtrip_witness_CBOR = H.property $ do AnyShelleyBasedEra era <- H.noteShowM . H.forAll $ Gen.element [minBound .. maxBound] @@ -521,6 +536,7 @@ tests = , testProperty "roundtrip ScriptData CBOR" prop_roundtrip_ScriptData_CBOR , testProperty "roundtrip TxWitness Cddl" prop_roundtrip_TxWitness_Cddl , testProperty "roundtrip tx CBOR" prop_roundtrip_tx_CBOR + , testProperty "roundtrip tx out CBOR" prop_roundtrip_tx_out_CBOR , testProperty "roundtrip GovernancePoll CBOR" prop_roundtrip_GovernancePoll_CBOR