diff --git a/cardano-api/cardano-api.cabal b/cardano-api/cardano-api.cabal index c97be6e6ff..89c4ad7e01 100644 --- a/cardano-api/cardano-api.cabal +++ b/cardano-api/cardano-api.cabal @@ -94,6 +94,7 @@ library Cardano.Api.Ledger.Lens Cardano.Api.Network Cardano.Api.Shelley + Cardano.Api.Tx.UTxO build-depends: FailT, @@ -244,6 +245,7 @@ library Cardano.Api.Internal.StakePoolMetadata Cardano.Api.Internal.Tx.Body Cardano.Api.Internal.Tx.Compatible + Cardano.Api.Internal.Tx.UTxO Cardano.Api.Internal.TxIn Cardano.Api.Internal.TxMetadata Cardano.Api.Internal.Utils diff --git a/cardano-api/src/Cardano/Api.hs b/cardano-api/src/Cardano/Api.hs index f141620f6b..fa8b1e64b0 100644 --- a/cardano-api/src/Cardano/Api.hs +++ b/cardano-api/src/Cardano/Api.hs @@ -1142,6 +1142,7 @@ import Cardano.Api.Internal.SerialiseUsing import Cardano.Api.Internal.StakePoolMetadata import Cardano.Api.Internal.Tx.Body import Cardano.Api.Internal.Tx.Sign +import Cardano.Api.Internal.Tx.UTxO import Cardano.Api.Internal.TxMetadata import Cardano.Api.Internal.Utils import Cardano.Api.Internal.Value diff --git a/cardano-api/src/Cardano/Api/Internal/Convenience/Construction.hs b/cardano-api/src/Cardano/Api/Internal/Convenience/Construction.hs index 7bf1cb3841..6d408ce464 100644 --- a/cardano-api/src/Cardano/Api/Internal/Convenience/Construction.hs +++ b/cardano-api/src/Cardano/Api/Internal/Convenience/Construction.hs @@ -22,6 +22,7 @@ import Cardano.Api.Internal.ProtocolParameters import Cardano.Api.Internal.Query import Cardano.Api.Internal.Tx.Body import Cardano.Api.Internal.Tx.Sign +import Cardano.Api.Internal.Tx.UTxO (UTxO (..)) import Cardano.Api.Internal.Utils import qualified Cardano.Ledger.Api as L diff --git a/cardano-api/src/Cardano/Api/Internal/Convenience/Query.hs b/cardano-api/src/Cardano/Api/Internal/Convenience/Query.hs index dee4e6f0dc..9d4230d7c9 100644 --- a/cardano-api/src/Cardano/Api/Internal/Convenience/Query.hs +++ b/cardano-api/src/Cardano/Api/Internal/Convenience/Query.hs @@ -35,6 +35,7 @@ import Cardano.Api.Internal.ProtocolParameters import Cardano.Api.Internal.Query import Cardano.Api.Internal.Query.Expr import Cardano.Api.Internal.Tx.Body +import Cardano.Api.Internal.Tx.UTxO import Cardano.Api.Internal.Utils import qualified Cardano.Ledger.Api as L diff --git a/cardano-api/src/Cardano/Api/Internal/Fees.hs b/cardano-api/src/Cardano/Api/Internal/Fees.hs index d562ff2b5f..d80a2bcb89 100644 --- a/cardano-api/src/Cardano/Api/Internal/Fees.hs +++ b/cardano-api/src/Cardano/Api/Internal/Fees.hs @@ -67,6 +67,7 @@ import Cardano.Api.Internal.Query import Cardano.Api.Internal.Script import Cardano.Api.Internal.Tx.Body import Cardano.Api.Internal.Tx.Sign +import Cardano.Api.Internal.Tx.UTxO import Cardano.Api.Internal.Value import qualified Cardano.Api.Ledger.Lens as A diff --git a/cardano-api/src/Cardano/Api/Internal/Plutus.hs b/cardano-api/src/Cardano/Api/Internal/Plutus.hs index e6bb3c6d12..0a4ffddf7c 100644 --- a/cardano-api/src/Cardano/Api/Internal/Plutus.hs +++ b/cardano-api/src/Cardano/Api/Internal/Plutus.hs @@ -14,12 +14,13 @@ import Cardano.Api.Internal.Eon.AlonzoEraOnwards (AlonzoEraOnwards (.. import Cardano.Api.Internal.Eon.Convert (convert) import Cardano.Api.Internal.Eon.ShelleyBasedEra (ShelleyLedgerEra) import Cardano.Api.Internal.Pretty (Pretty (pretty), docToText) -import Cardano.Api.Internal.Query (UTxO, toLedgerUTxO) +import Cardano.Api.Internal.Query (toLedgerUTxO) import qualified Cardano.Api.Internal.ReexposeLedger as L import Cardano.Api.Internal.Script (ScriptHash, fromShelleyScriptHash) import qualified Cardano.Api.Internal.Script as Api import Cardano.Api.Internal.Tx.Body (ScriptWitnessIndex (..), toScriptIndex) import Cardano.Api.Internal.Tx.Sign (Tx (..)) +import Cardano.Api.Internal.Tx.UTxO (UTxO) import qualified Cardano.Ledger.Alonzo.Scripts as L import qualified Cardano.Ledger.Alonzo.UTxO as Alonzo diff --git a/cardano-api/src/Cardano/Api/Internal/Query.hs b/cardano-api/src/Cardano/Api/Internal/Query.hs index 93bcab08a1..86d235d904 100644 --- a/cardano-api/src/Cardano/Api/Internal/Query.hs +++ b/cardano-api/src/Cardano/Api/Internal/Query.hs @@ -22,7 +22,6 @@ module Cardano.Api.Internal.Query , QueryInEra (..) , QueryInShelleyBasedEra (..) , QueryUTxOFilter (..) - , UTxO (..) , UTxOInAnyEra (..) -- * Internal conversion functions @@ -80,6 +79,7 @@ import Cardano.Api.Internal.ProtocolParameters import Cardano.Api.Internal.Query.Types import qualified Cardano.Api.Internal.ReexposeLedger as Ledger import Cardano.Api.Internal.Tx.Body +import Cardano.Api.Internal.Tx.UTxO import qualified Cardano.Chain.Update.Validation.Interface as Byron.Update import qualified Cardano.Ledger.Api as L @@ -117,10 +117,6 @@ import Ouroboros.Network.PeerSelection.LedgerPeers.Type (LedgerPeerSna import Ouroboros.Network.Protocol.LocalStateQuery.Client (Some (..)) import Control.Monad.Trans.Except -import Data.Aeson (FromJSON (..), ToJSON (..), withObject) -import qualified Data.Aeson as Aeson -import qualified Data.Aeson.KeyMap as KeyMap -import Data.Aeson.Types (Parser) import Data.Bifunctor (bimap, first) import qualified Data.ByteString.Lazy as LBS import Data.Either.Combinators (rightToMaybe) @@ -374,9 +370,6 @@ instance NodeToClientVersionOf QueryUTxOFilter where newtype ByronUpdateState = ByronUpdateState Byron.Update.State deriving Show -newtype UTxO era = UTxO {unUTxO :: Map TxIn (TxOut CtxUTxO era)} - deriving (Eq, Show) - data UTxOInAnyEra where UTxOInAnyEra :: CardanoEra era @@ -385,25 +378,6 @@ data UTxOInAnyEra where deriving instance Show UTxOInAnyEra -instance IsCardanoEra era => ToJSON (UTxO era) where - toJSON (UTxO m) = toJSON m - toEncoding (UTxO m) = toEncoding m - -instance - (IsShelleyBasedEra era, FromJSON (TxOut CtxUTxO era)) - => FromJSON (UTxO era) - where - parseJSON = withObject "UTxO" $ \hm -> do - let l = toList $ KeyMap.toHashMapText hm - res <- mapM toTxIn l - pure . UTxO $ fromList res - where - toTxIn :: (Text, Aeson.Value) -> Parser (TxIn, TxOut CtxUTxO era) - toTxIn (txinText, txOutVal) = do - (,) - <$> parseJSON (Aeson.String txinText) - <*> parseJSON txOutVal - newtype SerialisedDebugLedgerState era = SerialisedDebugLedgerState (Serialised (Shelley.NewEpochState (ShelleyLedgerEra era))) diff --git a/cardano-api/src/Cardano/Api/Internal/Query/Expr.hs b/cardano-api/src/Cardano/Api/Internal/Query/Expr.hs index a7278d46fb..1fb6011523 100644 --- a/cardano-api/src/Cardano/Api/Internal/Query/Expr.hs +++ b/cardano-api/src/Cardano/Api/Internal/Query/Expr.hs @@ -58,6 +58,7 @@ import Cardano.Api.Internal.NetworkId import Cardano.Api.Internal.ProtocolParameters import Cardano.Api.Internal.Query import qualified Cardano.Api.Internal.ReexposeLedger as Ledger +import Cardano.Api.Internal.Tx.UTxO import qualified Cardano.Ledger.Api as L import qualified Cardano.Ledger.Api.State.Query as L diff --git a/cardano-api/src/Cardano/Api/Internal/Tx/UTxO.hs b/cardano-api/src/Cardano/Api/Internal/Tx/UTxO.hs new file mode 100644 index 0000000000..319c3900d0 --- /dev/null +++ b/cardano-api/src/Cardano/Api/Internal/Tx/UTxO.hs @@ -0,0 +1,79 @@ +{-# LANGUAGE DerivingStrategies #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE GeneralizedNewtypeDeriving #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE UndecidableInstances #-} + +module Cardano.Api.Internal.Tx.UTxO where + +import Cardano.Api.Internal.Eon.ShelleyBasedEra (IsShelleyBasedEra) +import Cardano.Api.Internal.Eras.Core (IsCardanoEra) +import Cardano.Api.Internal.Tx.Body (CtxUTxO, TxOut (..)) +import Cardano.Api.Internal.TxIn (TxIn (..)) + +import Cardano.Ledger.Babbage () + +import Data.Aeson (FromJSON (..), ToJSON (..)) +import qualified Data.Aeson as Aeson +import qualified Data.Aeson.KeyMap as KeyMap +import Data.Aeson.Types (Parser) +import Data.Map (Map) +import qualified Data.Map as Map +import Data.Set (Set) +import Data.Text (Text) +import GHC.Exts (IsList (..)) + +newtype UTxO era = UTxO {unUTxO :: Map TxIn (TxOut CtxUTxO era)} + deriving stock (Eq, Show) + deriving newtype (Semigroup, Monoid, IsList) + +instance IsCardanoEra era => ToJSON (UTxO era) where + toJSON (UTxO m) = toJSON m + toEncoding (UTxO m) = toEncoding m + +instance + IsShelleyBasedEra era + => FromJSON (UTxO era) + where + parseJSON = Aeson.withObject "UTxO" $ \hm -> do + let l = toList $ KeyMap.toHashMapText hm + res <- mapM toTxIn l + pure . UTxO $ Map.fromList res + where + toTxIn :: (Text, Aeson.Value) -> Parser (TxIn, TxOut CtxUTxO era) + toTxIn (txinText, txOutVal) = do + (,) + <$> parseJSON (Aeson.String txinText) + <*> parseJSON txOutVal + +-- | Infix version of `difference`. +(\\) :: UTxO era -> UTxO era -> UTxO era +a \\ b = difference a b + +-- | Create an empty `UTxO`. +empty :: UTxO era +empty = UTxO Map.empty + +-- | Create a `UTxO` from a single unspent transaction output. +singleton :: TxIn -> TxOut CtxUTxO era -> UTxO era +singleton i o = UTxO $ Map.singleton i o + +-- | Find a 'TxOut' for a given 'TxIn'. +lookup :: TxIn -> UTxO era -> Maybe (TxOut CtxUTxO era) +lookup k = Map.lookup k . unUTxO + +-- | Filter all `TxOut` that satisfy the predicate. +filter :: (TxOut CtxUTxO era -> Bool) -> UTxO era -> UTxO era +filter fn = UTxO . Map.filter fn . unUTxO + +-- | Filter all UTxO to only include 'out's satisfying given predicate. +filterWithKey :: (TxIn -> TxOut CtxUTxO era -> Bool) -> UTxO era -> UTxO era +filterWithKey fn = UTxO . Map.filterWithKey fn . unUTxO + +-- | Get the 'UTxO domain input's set +inputSet :: UTxO (TxOut CtxUTxO era) -> Set TxIn +inputSet = Map.keysSet . unUTxO + +-- | Remove the right hand side from the left hand side. +difference :: UTxO era -> UTxO era -> UTxO era +difference a b = UTxO $ Map.difference (unUTxO a) (unUTxO b) diff --git a/cardano-api/src/Cardano/Api/Tx/UTxO.hs b/cardano-api/src/Cardano/Api/Tx/UTxO.hs new file mode 100644 index 0000000000..41463f68cb --- /dev/null +++ b/cardano-api/src/Cardano/Api/Tx/UTxO.hs @@ -0,0 +1,13 @@ +module Cardano.Api.Tx.UTxO + ( UTxO.UTxO (..) + , UTxO.empty + , UTxO.singleton + , UTxO.lookup + , UTxO.filter + , UTxO.filterWithKey + , UTxO.inputSet + , UTxO.difference + ) +where + +import qualified Cardano.Api.Internal.Tx.UTxO as UTxO