diff --git a/cabal.project b/cabal.project index 1155d1ff94e..2c6b930698b 100644 --- a/cabal.project +++ b/cabal.project @@ -12,8 +12,8 @@ repository cardano-haskell-packages -- See CONTRIBUTING.md for information about when and how to update these. index-state: - , hackage.haskell.org 2025-06-11T21:55:55Z - , cardano-haskell-packages 2025-06-12T11:07:25Z + , hackage.haskell.org 2025-09-15T21:16:16Z + , cardano-haskell-packages 2025-09-16T10:10:31Z packages: **/*.cabal diff --git a/flake.lock b/flake.lock index 25d24b51b55..d5dc8a2fc61 100644 --- a/flake.lock +++ b/flake.lock @@ -3,11 +3,11 @@ "CHaP": { "flake": false, "locked": { - "lastModified": 1749727790, - "narHash": "sha256-yCKoVpny9PSGTcSrCtXq77FuKFlq9Hf81ULVgCvkfmc=", + "lastModified": 1758019900, + "narHash": "sha256-e+avZgySRCz8VyI1m/lmNT45DP3e9gs+MFoMZ2y+Tt0=", "owner": "IntersectMBO", "repo": "cardano-haskell-packages", - "rev": "b1b559392d6fc44626cef9d5b7821421cc7adcdc", + "rev": "a6d287cdc826a7a8d4de86b60d0443e45472ca28", "type": "github" }, "original": { @@ -632,23 +632,6 @@ "type": "github" } }, - "ghc-8.6.5-iohk_2": { - "flake": false, - "locked": { - "lastModified": 1600920045, - "narHash": "sha256-DO6kxJz248djebZLpSzTGD6s8WRpNI9BTwUeOf5RwY8=", - "owner": "input-output-hk", - "repo": "ghc", - "rev": "95713a6ecce4551240da7c96b6176f980af75cae", - "type": "github" - }, - "original": { - "owner": "input-output-hk", - "ref": "release/8.6.5-iohk", - "repo": "ghc", - "type": "github" - } - }, "ghc910X": { "flake": false, "locked": { @@ -713,11 +696,11 @@ "hackage": { "flake": false, "locked": { - "lastModified": 1749687986, - "narHash": "sha256-cEt2Hhbc0w0SqiadjZg4TJyn2+rKxW/15nmu4an79wo=", + "lastModified": 1757982288, + "narHash": "sha256-qnfIgU4ILEoUdSXNJT1FqI9vClMw+7bzawryci1b7kM=", "owner": "input-output-hk", "repo": "hackage.nix", - "rev": "0949afe39e6d249b6db126a96646d3f51a4a4c11", + "rev": "93b934a7c4309811c07d0184d2502642aacbefeb", "type": "github" }, "original": { @@ -729,11 +712,11 @@ "hackage-for-stackage": { "flake": false, "locked": { - "lastModified": 1749687976, - "narHash": "sha256-CIy7o8PDJObfuBc0UTUXGpySA1cxPFp46A8Bi/fWzh4=", + "lastModified": 1757982278, + "narHash": "sha256-Dog1K0lrVYqWqs1/nMLMpJYdRaedSpMm9RjUoFJK4rI=", "owner": "input-output-hk", "repo": "hackage.nix", - "rev": "c0ec5d2de9aed5d63ee86d5c9c753d62f860d362", + "rev": "3eec113f323d3d275ad4e8315e66630d93599488", "type": "github" }, "original": { @@ -743,6 +726,22 @@ "type": "github" } }, + "hackage-internal": { + "flake": false, + "locked": { + "lastModified": 1750307553, + "narHash": "sha256-iiafNoeLHwlSLQTyvy8nPe2t6g5AV4PPcpMeH/2/DLs=", + "owner": "input-output-hk", + "repo": "hackage.nix", + "rev": "f7867baa8817fab296528f4a4ec39d1c7c4da4f3", + "type": "github" + }, + "original": { + "owner": "input-output-hk", + "repo": "hackage.nix", + "type": "github" + } + }, "hackageNix": { "flake": false, "locked": { @@ -825,13 +824,14 @@ "cabal-36": "cabal-36_2", "cardano-shell": "cardano-shell_2", "flake-compat": "flake-compat_3", - "ghc-8.6.5-iohk": "ghc-8.6.5-iohk_2", "hackage": "hackage", "hackage-for-stackage": "hackage-for-stackage", + "hackage-internal": "hackage-internal", "hls": "hls", "hls-1.10": "hls-1.10_2", "hls-2.0": "hls-2.0_2", "hls-2.10": "hls-2.10", + "hls-2.11": "hls-2.11", "hls-2.2": "hls-2.2_2", "hls-2.3": "hls-2.3_2", "hls-2.4": "hls-2.4_2", @@ -856,11 +856,11 @@ "stackage": "stackage_2" }, "locked": { - "lastModified": 1749714245, - "narHash": "sha256-7Bj/WrzaaZV1eg8x5CUfXxyBZKX/OB//spY2xjOlXWM=", + "lastModified": 1757983887, + "narHash": "sha256-Ai7+aYpVCjFPObJvWsOyvC5e3B3xdd4CPI2CWnXAtj0=", "owner": "input-output-hk", "repo": "haskell.nix", - "rev": "2243adfe1e2d7b8666afb1288a0fef908f873d19", + "rev": "4cf808684da04f619adb63059b4336b450fb2370", "type": "github" }, "original": { @@ -970,6 +970,23 @@ "type": "github" } }, + "hls-2.11": { + "flake": false, + "locked": { + "lastModified": 1747306193, + "narHash": "sha256-/MmtpF8+FyQlwfKHqHK05BdsxC9LHV70d/FiMM7pzBM=", + "owner": "haskell", + "repo": "haskell-language-server", + "rev": "46ef4523ea4949f47f6d2752476239f1c6d806fe", + "type": "github" + }, + "original": { + "owner": "haskell", + "ref": "2.11.0.0", + "repo": "haskell-language-server", + "type": "github" + } + }, "hls-2.2": { "flake": false, "locked": { @@ -1470,11 +1487,11 @@ "iserv-proxy_2": { "flake": false, "locked": { - "lastModified": 1749443511, - "narHash": "sha256-asfdanBoIUcJ9XQWB3a/5wQGFG/6Uq6l2s9r8OuamkY=", + "lastModified": 1755243078, + "narHash": "sha256-GLbl1YaohKdpzZVJFRdcI1O1oE3F3uBer4lFv3Yy0l8=", "owner": "stable-haskell", "repo": "iserv-proxy", - "rev": "e40eddb1ca1e3e906e018c7e6b0d1e51c930ec9d", + "rev": "150605195cb7183a6fb7bed82f23fedf37c6f52a", "type": "github" }, "original": { @@ -1792,11 +1809,11 @@ }, "nixpkgs-2505": { "locked": { - "lastModified": 1748852332, - "narHash": "sha256-r/wVJWmLYEqvrJKnL48r90Wn9HWX9SHFt6s4LhuTh7k=", + "lastModified": 1754477006, + "narHash": "sha256-suIgZZHXdb4ca9nN4MIcmdjeN+ZWsTwCtYAG4HExqAo=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "a8167f3cc2f991dd4d0055746df53dae5fd0c953", + "rev": "4896699973299bffae27d0d9828226983544d9e9", "type": "github" }, "original": { @@ -1927,11 +1944,11 @@ }, "nixpkgs-unstable_2": { "locked": { - "lastModified": 1748856973, - "narHash": "sha256-RlTsJUvvr8ErjPBsiwrGbbHYW8XbB/oek0Gi78XdWKg=", + "lastModified": 1754393734, + "narHash": "sha256-fbnmAwTQkuXHKBlcL5Nq1sMAzd3GFqCOQgEQw6Hy0Ak=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "e4b09e47ace7d87de083786b404bf232eb6c89d8", + "rev": "a683adc19ff5228af548c6539dbc3440509bfed3", "type": "github" }, "original": { @@ -2339,11 +2356,11 @@ "stackage_2": { "flake": false, "locked": { - "lastModified": 1749687194, - "narHash": "sha256-q8sDch6qHpICjnhJfZ72N7LHqlT693kf4i3RKon52oY=", + "lastModified": 1757981556, + "narHash": "sha256-3ZC1NvBzECcFTrK6UqZujubC55nrXjlZKRPgzcn/t/c=", "owner": "input-output-hk", "repo": "stackage.nix", - "rev": "1e7f1004b1e151bea95bb6808fe4178e0b3b6b22", + "rev": "cfa1d41b89c4e47e93702324ffd596ff8ac90482", "type": "github" }, "original": { diff --git a/hydra-cardano-api/hydra-cardano-api.cabal b/hydra-cardano-api/hydra-cardano-api.cabal index 42ca18638ec..ca85b4c53a9 100644 --- a/hydra-cardano-api/hydra-cardano-api.cabal +++ b/hydra-cardano-api/hydra-cardano-api.cabal @@ -40,11 +40,9 @@ library hs-source-dirs: src ghc-options: -haddock exposed-modules: - Cardano.Api.UTxO Hydra.Cardano.Api Hydra.Cardano.Api.Address Hydra.Cardano.Api.AddressInEra - Hydra.Cardano.Api.BlockHeader Hydra.Cardano.Api.ChainPoint Hydra.Cardano.Api.ExecutionUnits Hydra.Cardano.Api.Hash @@ -58,6 +56,7 @@ library Hydra.Cardano.Api.ScriptData Hydra.Cardano.Api.ScriptDatum Hydra.Cardano.Api.ScriptHash + Hydra.Cardano.Api.Serialise Hydra.Cardano.Api.StakeAddress Hydra.Cardano.Api.Tx Hydra.Cardano.Api.TxBody @@ -77,7 +76,7 @@ library , aeson >=2 , base >=4.14 , bytestring - , cardano-api ^>=10.16 + , cardano-api ^>=10.18 , cardano-api:gen , cardano-binary , cardano-crypto-class @@ -91,6 +90,7 @@ library , cardano-ledger-shelley , containers , hedgehog-quickcheck + , io-classes , lens , plutus-ledger-api , QuickCheck diff --git a/hydra-cardano-api/src/Cardano/Api/UTxO.hs b/hydra-cardano-api/src/Cardano/Api/UTxO.hs deleted file mode 100644 index b6ef95a54b7..00000000000 --- a/hydra-cardano-api/src/Cardano/Api/UTxO.hs +++ /dev/null @@ -1,153 +0,0 @@ --- | NOTE (1): This module is meant to be imported qualified as 'UTxO'. --- --- NOTE (2): This module is name-spaces slightly different from the rest --- because it is meant to be used as a replacement of the UTxO type of the --- cardano-api which is not convenient enough to work with. Having it as --- 'Hydra.Cardano.Api.UTxO' causes cyclic imports with other modules also --- relying on this newtype. So instead, we do 'as if' it was part of the --- cardano-api in the first place. -module Cardano.Api.UTxO where - -import Cardano.Api hiding (UTxO, toLedgerUTxO) -import Cardano.Api qualified -import Cardano.Api.Ledger (Coin) -import Cardano.Api.Shelley (ReferenceScript (..)) -import Cardano.Ledger.Babbage () -import Data.Bifunctor (second) -import Data.Coerce (coerce) -import Data.List qualified as List -import Data.Map (Map) -import Data.Map qualified as Map -import Data.Set (Set) -import Data.Text (Text) -import Data.Text qualified as T -import Prelude - -type Era = ConwayEra - -type UTxO = UTxO' (TxOut CtxUTxO Era) - --- | Newtype with phantom types mostly required to work around the poor interface --- of 'Ledger.UTXO' and provide 'Monoid' and 'Foldable' instances to make utxo --- manipulation bareable. -newtype UTxO' out = UTxO - { toMap :: Map TxIn out - } - deriving newtype - ( Eq - , Show - , Semigroup - , Monoid - , ToJSON - , FromJSON - ) - --- | Create a 'UTxO' from a list of 'TxIn' and 'out' pairs. -fromList :: [(TxIn, out)] -> UTxO' out -fromList = UTxO . Map.fromList - --- | Create a 'UTxO' from a single unspent transaction output. -singleton :: TxIn -> out -> UTxO' out -singleton i o = UTxO $ Map.singleton i o - --- | Find an 'out' for a given 'TxIn'. -resolveTxIn :: TxIn -> UTxO' out -> Maybe out -resolveTxIn k = Map.lookup k . toMap - --- | Turn a 'UTxO' into a list of pairs. -toList :: UTxO' out -> [(TxIn, out)] -toList = Map.toList . toMap - --- | Find first 'UTxO' using the output in predicate. -find :: (out -> Bool) -> UTxO' out -> Maybe (TxIn, out) -find fn = findBy (fn . snd) - --- | Find first 'UTxO' using both input and output in predicate. -findBy :: ((TxIn, out) -> Bool) -> UTxO' out -> Maybe (TxIn, out) -findBy fn utxo = List.find fn $ toList utxo - --- | Filter UTxO to only include 'out's satisfying given predicate. -filter :: (out -> Bool) -> UTxO' out -> UTxO' out -filter fn = UTxO . Map.filter fn . toMap - --- | Get the 'UTxO' domain input's set -inputSet :: UTxO' out -> Set TxIn -inputSet = Map.keysSet . toMap - --- | Get a human-readable pretty text representation of a UTxO. -render :: (TxIn, TxOut ctx era) -> Text -render (k, TxOut _ (txOutValueToValue -> v) _ _) = - T.drop 54 (renderTxIn k) <> " ↦ " <> renderValue v - --- | Remove the right hand side from the left hand side. -difference :: UTxO' out -> UTxO' out -> UTxO' out -difference a b = UTxO $ Map.difference (toMap a) (toMap b) - --- | Check if the first 'UTxO' contains all **outputs** of the second 'UTxO'. --- First argument is the 'UTxO' to search in, second argument is the 'UTxO' --- to search for. -containsOutputs :: UTxO -> UTxO -> Bool -containsOutputs utxoForSearching utxo = - let allOutputs = txOutputs utxoForSearching - expectedOutputs = txOutputs utxo - in all (`elem` allOutputs) expectedOutputs - -map :: (TxOut CtxUTxO Era -> TxOut CtxUTxO Era) -> UTxO -> UTxO -map f = UTxO . Map.map f . toMap - -foldMap :: Monoid m => (TxOut CtxUTxO Era -> m) -> UTxO -> m -foldMap fn = Prelude.foldMap fn . toMap - -txOutputs :: UTxO -> [TxOut CtxUTxO Era] -txOutputs = Map.elems . toMap - -null :: UTxO -> Bool -null = Map.null . toMap - -size :: UTxO -> Int -size = Map.size . toMap - -totalValue :: UTxO -> Value -totalValue = Cardano.Api.UTxO.foldMap (\(TxOut _ (txOutValueToValue -> v) _ _) -> v) - -totalLovelace :: UTxO -> Coin -totalLovelace = selectLovelace . totalValue - --- * Type Conversions - --- | Transforms a UTxO containing tx outs from any era into Babbage era. -fromApi :: Cardano.Api.UTxO era -> UTxO -fromApi (Cardano.Api.UTxO eraUTxO) = - fromList $ second convertOutputToEra <$> Map.toList eraUTxO - where - -- NOTE: At latest the TxOutValue is an existential where we need to case on - -- the 'sbe' witness to get constraints on the contained 'value', but the - -- 'cardano-api' does that already when allowing conversion of their - -- (complicated) constrained types to the cardano-ledger types - so we just - -- convert forth and back. - convertOutputToEra :: TxOut CtxUTxO era -> TxOut CtxUTxO Era - convertOutputToEra (TxOut eraAddress eraValue eraDatum eraRefScript) = - TxOut - (convertAddressToEra eraAddress) - (convertValueToEra eraValue) - (convertDatumToEra eraDatum) - (convertRefScriptToEra eraRefScript) - - convertAddressToEra :: AddressInEra era -> AddressInEra Era - convertAddressToEra (AddressInEra _ eraAddress) = anyAddressInShelleyBasedEra shelleyBasedEra (toAddressAny eraAddress) - - convertValueToEra :: TxOutValue era -> TxOutValue Era - convertValueToEra (TxOutValueByron lovelace) = lovelaceToTxOutValue shelleyBasedEra lovelace - convertValueToEra (TxOutValueShelleyBased sbe value) = TxOutValueShelleyBased shelleyBasedEra (toLedgerValue (maryBasedEra @Era) $ fromLedgerValue sbe value) - - convertDatumToEra :: TxOutDatum CtxUTxO era -> TxOutDatum CtxUTxO Era - convertDatumToEra TxOutDatumNone = TxOutDatumNone - convertDatumToEra (TxOutDatumHash _ hashScriptData) = TxOutDatumHash alonzoBasedEra hashScriptData - convertDatumToEra (TxOutDatumInline _ hashableScriptData) = TxOutDatumInline babbageBasedEra hashableScriptData - - convertRefScriptToEra :: ReferenceScript era -> ReferenceScript Era - convertRefScriptToEra ReferenceScriptNone = ReferenceScriptNone - convertRefScriptToEra (ReferenceScript _ scriptInAnyLang) = ReferenceScript babbageBasedEra scriptInAnyLang - -toApi :: UTxO -> Cardano.Api.UTxO Era -toApi = coerce diff --git a/hydra-cardano-api/src/Hydra/Cardano/Api.hs b/hydra-cardano-api/src/Hydra/Cardano/Api.hs index 516ebe93459..6553965818d 100644 --- a/hydra-cardano-api/src/Hydra/Cardano/Api.hs +++ b/hydra-cardano-api/src/Hydra/Cardano/Api.hs @@ -23,10 +23,6 @@ module Hydra.Cardano.Api ( -- * Wrapped Types module Hydra.Cardano.Api, - -- ** UTxO - UTxO, - UTxO' (UTxO), - -- * Extras module Extras, @@ -38,9 +34,10 @@ import Cardano.Api as X hiding ( AddressInEra (..), AddressTypeInEra (..), BalancedTxBody (..), - Key (..), - KeyWitness, + KeyWitness (..), PlutusScript, + PlutusScriptSerialised, + ReferenceScript (..), Script (..), ScriptInEra (..), ScriptLanguage (..), @@ -85,45 +82,15 @@ import Cardano.Api as X hiding ( import Cardano.Api.Ledger as X ( PParams, ) -import Cardano.Api.Ledger.Lens as X ( - mkAdaValue, - ) -import Cardano.Api.Shelley as X ( - AcquiringFailure (..), - Hash (HeaderHash), - Key (..), - PlutusScriptOrReferenceInput (PScript), - PoolId, - ShelleyGenesis (..), - ShelleyLedgerEra, - SigningKey (..), - StakeCredential (..), - VerificationKey (..), - fromAlonzoCostModels, - fromAlonzoPrices, - fromPlutusData, - fromShelleyMetadata, - toAlonzoPrices, - toPlutusData, - toShelleyMetadata, - toShelleyNetwork, - ) -import Cardano.Api.UTxO ( - UTxO, - UTxO' (..), - ) -import Cardano.Ledger.Coin as X (Coin (..)) import Hydra.Cardano.Api.Prelude ( Era, LedgerEra, - LedgerProtocolParameters, Map, ledgerEraVersion, ) import Hydra.Cardano.Api.Address () import Hydra.Cardano.Api.AddressInEra as Extras -import Hydra.Cardano.Api.BlockHeader as Extras import Hydra.Cardano.Api.ChainPoint as Extras import Hydra.Cardano.Api.ExecutionUnits as Extras import Hydra.Cardano.Api.Hash as Extras @@ -135,6 +102,7 @@ import Hydra.Cardano.Api.ReferenceScript as Extras import Hydra.Cardano.Api.ScriptData as Extras import Hydra.Cardano.Api.ScriptDatum as Extras import Hydra.Cardano.Api.ScriptHash as Extras +import Hydra.Cardano.Api.Serialise as Extras import Hydra.Cardano.Api.StakeAddress as Extras import Hydra.Cardano.Api.Tx as Extras hiding (Tx) import Hydra.Cardano.Api.TxBody as Extras @@ -149,8 +117,6 @@ import Hydra.Cardano.Api.Value as Extras import Hydra.Cardano.Api.Witness as Extras import Cardano.Api qualified -import Cardano.Api.Internal.Tx.Body (TxInsReferenceDatums) -import Cardano.Api.Shelley qualified import Cardano.Ledger.Alonzo.TxAuxData qualified as Ledger import Cardano.Ledger.Alonzo.TxWits qualified as Ledger import Cardano.Ledger.BaseTypes as X (Network) @@ -216,17 +182,17 @@ type KeyWitness = Cardano.Api.KeyWitness Era pattern ShelleyBootstrapWitness :: Ledger.BootstrapWitness -> KeyWitness pattern ShelleyBootstrapWitness{shelleyBootstrapWitness} <- - Cardano.Api.Shelley.ShelleyBootstrapWitness _ shelleyBootstrapWitness + Cardano.Api.ShelleyBootstrapWitness _ shelleyBootstrapWitness where ShelleyBootstrapWitness = - Cardano.Api.Shelley.ShelleyBootstrapWitness shelleyBasedEra + Cardano.Api.ShelleyBootstrapWitness shelleyBasedEra pattern ShelleyKeyWitness :: Ledger.WitVKey 'Ledger.Witness -> KeyWitness pattern ShelleyKeyWitness{shelleyKeyWitness} <- - Cardano.Api.Shelley.ShelleyKeyWitness _ shelleyKeyWitness + Cardano.Api.ShelleyKeyWitness _ shelleyKeyWitness where ShelleyKeyWitness = - Cardano.Api.Shelley.ShelleyKeyWitness shelleyBasedEra + Cardano.Api.ShelleyKeyWitness shelleyBasedEra -- ** PlutusScript @@ -235,10 +201,10 @@ type PlutusScript = Cardano.Api.PlutusScript PlutusScriptV3 pattern PlutusScriptSerialised :: ShortByteString -> PlutusScript pattern PlutusScriptSerialised{plutusScriptSerialised} <- - Cardano.Api.Shelley.PlutusScriptSerialised plutusScriptSerialised + Cardano.Api.PlutusScriptSerialised plutusScriptSerialised where PlutusScriptSerialised = - Cardano.Api.Shelley.PlutusScriptSerialised + Cardano.Api.PlutusScriptSerialised -- ** Script @@ -247,10 +213,10 @@ type Script = Cardano.Api.Script PlutusScriptV3 pattern PlutusScript :: PlutusScript -> Script pattern PlutusScript{plutusScript} <- - Cardano.Api.Shelley.PlutusScript _ plutusScript + Cardano.Api.PlutusScript _ plutusScript where PlutusScript = - Cardano.Api.Shelley.PlutusScript PlutusScriptV3 + Cardano.Api.PlutusScript PlutusScriptV3 -- ** ScriptInEra @@ -263,10 +229,10 @@ type ScriptLanguage = Cardano.Api.ScriptLanguage PlutusScriptV3 pattern PlutusScriptLanguage :: ScriptLanguage pattern PlutusScriptLanguage <- - Cardano.Api.Shelley.PlutusScriptLanguage _ + Cardano.Api.PlutusScriptLanguage _ where PlutusScriptLanguage = - Cardano.Api.Shelley.PlutusScriptLanguage PlutusScriptV3 + Cardano.Api.PlutusScriptLanguage PlutusScriptV3 -- ** ScriptWitness @@ -326,7 +292,7 @@ pattern ShelleyTxBody , txBodyAuxiliaryData , txBodyScriptValidity } <- - Cardano.Api.Shelley.ShelleyTxBody + Cardano.Api.ShelleyTxBody _ txBodyLedgerTxBody txBodyScripts @@ -335,7 +301,7 @@ pattern ShelleyTxBody txBodyScriptValidity where ShelleyTxBody = - Cardano.Api.Shelley.ShelleyTxBody shelleyBasedEra + Cardano.Api.ShelleyTxBody shelleyBasedEra signShelleyTransaction :: TxBody -> [ShelleyWitnessSigningKey] -> Tx signShelleyTransaction = Cardano.Api.signShelleyTransaction shelleyBasedEra @@ -604,25 +570,25 @@ pattern TxOut{txOutAddress, txOutValue, txOutDatum, txOutReferenceScript} <- -- ** ReferenceScript -type ReferenceScript = Cardano.Api.Shelley.ReferenceScript Era +type ReferenceScript = Cardano.Api.ReferenceScript Era {-# COMPLETE ReferenceScript, ReferenceScriptNone #-} pattern ReferenceScript :: ScriptInAnyLang -> ReferenceScript pattern ReferenceScript{referenceScript} <- - Cardano.Api.Shelley.ReferenceScript + Cardano.Api.ReferenceScript _ referenceScript where ReferenceScript = - Cardano.Api.Shelley.ReferenceScript + Cardano.Api.ReferenceScript babbageBasedEra -pattern ReferenceScriptNone :: Cardano.Api.Shelley.ReferenceScript Era +pattern ReferenceScriptNone :: Cardano.Api.ReferenceScript Era pattern ReferenceScriptNone <- - Cardano.Api.Shelley.ReferenceScriptNone + Cardano.Api.ReferenceScriptNone where ReferenceScriptNone = - Cardano.Api.Shelley.ReferenceScriptNone + Cardano.Api.ReferenceScriptNone -- ** TxOutDatum @@ -733,3 +699,15 @@ pattern ScriptWitness scriptWitnessInCtx scriptWitness <- makeShelleyKeyWitness :: TxBody -> ShelleyWitnessSigningKey -> KeyWitness makeShelleyKeyWitness = Cardano.Api.makeShelleyKeyWitness shelleyBasedEra + +type UTxO = Cardano.Api.UTxO Era + +{-# COMPLETE UTxO #-} +pattern UTxO :: + Map TxIn (TxOut CtxUTxO) -> + UTxO +pattern UTxO{utxo} <- + Cardano.Api.UTxO utxo + where + UTxO = + Cardano.Api.UTxO diff --git a/hydra-cardano-api/src/Hydra/Cardano/Api/BlockHeader.hs b/hydra-cardano-api/src/Hydra/Cardano/Api/BlockHeader.hs deleted file mode 100644 index 666dff0daa3..00000000000 --- a/hydra-cardano-api/src/Hydra/Cardano/Api/BlockHeader.hs +++ /dev/null @@ -1,45 +0,0 @@ -{-# OPTIONS_GHC -Wno-orphans #-} - -module Hydra.Cardano.Api.BlockHeader where - -import Hydra.Cardano.Api.Prelude - -import Data.ByteString qualified as BS -import Test.QuickCheck (vectorOf) - --- * Generators - --- | Fully arbitrary block header with completely random hash. -genBlockHeader :: Gen BlockHeader -genBlockHeader = do - slotNo <- SlotNo <$> arbitrary - genBlockHeaderAt slotNo - --- | Generate a random block header with completely random hash, but at a --- certain slot. -genBlockHeaderAt :: SlotNo -> Gen BlockHeader -genBlockHeaderAt slotNo = do - headerHash <- genBlockHeaderHash - blockNo <- BlockNo <$> arbitrary - pure $ BlockHeader slotNo headerHash blockNo - --- | Generate a random block header hash. -genBlockHeaderHash :: Gen (Hash BlockHeader) -genBlockHeaderHash = - unsafeBlockHeaderHashFromBytes . BS.pack <$> vectorOf 32 arbitrary - where - unsafeBlockHeaderHashFromBytes :: ByteString -> Hash BlockHeader - unsafeBlockHeaderHashFromBytes bytes = - case deserialiseFromRawBytes (proxyToAsType Proxy) bytes of - Left e -> - error $ - "unsafeBlockHeaderHashFromBytes: failed on bytes " - <> show bytes - <> " with error " - <> show e - Right h -> h - --- * Orphans - -instance Arbitrary BlockHeader where - arbitrary = genBlockHeader diff --git a/hydra-cardano-api/src/Hydra/Cardano/Api/ChainPoint.hs b/hydra-cardano-api/src/Hydra/Cardano/Api/ChainPoint.hs index 21995cfe8dc..33d72a4d085 100644 --- a/hydra-cardano-api/src/Hydra/Cardano/Api/ChainPoint.hs +++ b/hydra-cardano-api/src/Hydra/Cardano/Api/ChainPoint.hs @@ -4,8 +4,8 @@ module Hydra.Cardano.Api.ChainPoint where import Hydra.Cardano.Api.Prelude -import Hydra.Cardano.Api.BlockHeader (genBlockHeaderHash) -import Test.QuickCheck (frequency) +import Test.Gen.Cardano.Api.Typed (genChainPoint) +import Test.QuickCheck.Hedgehog (hedgehog) -- | Get the chain point corresponding to a given 'BlockHeader'. getChainPoint :: BlockHeader -> ChainPoint @@ -14,22 +14,7 @@ getChainPoint header = where (BlockHeader slotNo headerHash _) = header --- * Generators - --- | Generate a chain point with a likely invalid block header hash. -genChainPoint :: Gen ChainPoint -genChainPoint = - frequency - [ (1, pure ChainPointAtGenesis) - , (5, arbitrary >>= genChainPointAt . SlotNo) - ] - --- | Generate a chain point at given slot with a likely invalid block header hash. -genChainPointAt :: SlotNo -> Gen ChainPoint -genChainPointAt s = - ChainPoint s <$> genBlockHeaderHash - -- * Orphans instance Arbitrary ChainPoint where - arbitrary = genChainPoint + arbitrary = hedgehog genChainPoint diff --git a/hydra-cardano-api/src/Hydra/Cardano/Api/Prelude.hs b/hydra-cardano-api/src/Hydra/Cardano/Api/Prelude.hs index 3100752bbd7..3abf620cba3 100644 --- a/hydra-cardano-api/src/Hydra/Cardano/Api/Prelude.hs +++ b/hydra-cardano-api/src/Hydra/Cardano/Api/Prelude.hs @@ -1,12 +1,10 @@ module Hydra.Cardano.Api.Prelude ( module Cardano.Api, - module Cardano.Api.Shelley, module Data.Aeson, HasCallStack, Proxy (..), Typeable, - UTxO, - UTxO' (UTxO), + UTxO (UTxO), Era, LedgerEra, ledgerEraVersion, @@ -28,12 +26,7 @@ import Cardano.Api hiding ( scriptLanguageSupportedInEra, toLedgerUTxO, ) -import Cardano.Api.Shelley hiding ( - UTxO, - scriptLanguageSupportedInEra, - toLedgerUTxO, - ) -import Cardano.Api.UTxO (UTxO, UTxO' (..)) +import Cardano.Api.UTxO (UTxO (..)) import Cardano.Crypto.Hash.Class qualified as CC import Cardano.Ledger.Binary qualified as Ledger import Cardano.Ledger.Core qualified as Ledger @@ -41,7 +34,6 @@ import Data.Aeson (FromJSON (..), ToJSON (..)) import Data.ByteString (ByteString) import Data.ByteString.Lazy (fromStrict, toStrict) import Data.Map (Map) -import Data.Proxy (Proxy (..)) import Data.Set (Set) import Data.Text (Text) import Data.Text.Encoding (decodeUtf8, encodeUtf8) diff --git a/hydra-cardano-api/src/Hydra/Cardano/Api/Pretty.hs b/hydra-cardano-api/src/Hydra/Cardano/Api/Pretty.hs index d8d5335b7ed..1b79959a934 100644 --- a/hydra-cardano-api/src/Hydra/Cardano/Api/Pretty.hs +++ b/hydra-cardano-api/src/Hydra/Cardano/Api/Pretty.hs @@ -23,8 +23,12 @@ import Hydra.Cardano.Api.ScriptData (fromLedgerData) renderTx :: Api.Tx -> String renderTx = renderTxWithUTxO mempty +renderUTxO :: (TxIn, TxOut ctx era) -> Text +renderUTxO (k, TxOut _ (txOutValueToValue -> v) _ _) = + T.drop 54 (renderTxIn k) <> " ↦ " <> renderValue v + -- | Like 'renderTx', but uses the given UTxO to resolve inputs. -renderTxWithUTxO :: UTxO -> Api.Tx -> String +renderTxWithUTxO :: UTxO Era -> Api.Tx -> String renderTxWithUTxO utxo (Tx body _wits) = unlines $ intercalate diff --git a/hydra-cardano-api/src/Hydra/Cardano/Api/Serialise.hs b/hydra-cardano-api/src/Hydra/Cardano/Api/Serialise.hs new file mode 100644 index 00000000000..3a0448be84d --- /dev/null +++ b/hydra-cardano-api/src/Hydra/Cardano/Api/Serialise.hs @@ -0,0 +1,14 @@ +module Hydra.Cardano.Api.Serialise where + +import Control.Monad.Class.MonadThrow (Exception, MonadThrow (..)) +import Hydra.Cardano.Api.Prelude + +data SerialiseFromRawBytesException = SerialiseFromRawBytesException ByteString String + deriving stock (Show) + +instance Exception SerialiseFromRawBytesException + +deserialiseFromRawBytesThrow :: forall a m. SerialiseAsRawBytes a => MonadThrow m => ByteString -> m a +deserialiseFromRawBytesThrow bs = case deserialiseFromRawBytes (proxyToAsType (Proxy @a)) bs of + Left e -> throwIO $ SerialiseFromRawBytesException bs (show e) + Right x -> pure x diff --git a/hydra-cardano-api/src/Hydra/Cardano/Api/Tx.hs b/hydra-cardano-api/src/Hydra/Cardano/Api/Tx.hs index 33bbf2eb426..119ba5253cb 100644 --- a/hydra-cardano-api/src/Hydra/Cardano/Api/Tx.hs +++ b/hydra-cardano-api/src/Hydra/Cardano/Api/Tx.hs @@ -38,7 +38,7 @@ signTx signingKey (Tx body wits) = witness = makeShelleyKeyWitness shelleyBasedEra body (WitnessPaymentKey signingKey) -- | Create a transaction spending all given `UTxO`. -txSpendingUTxO :: UTxO -> Tx Era +txSpendingUTxO :: UTxO Era -> Tx Era txSpendingUTxO utxo = fromLedgerTx $ mkBasicTx @@ -50,7 +50,7 @@ txSpendingUTxO utxo = -- | Get the UTxO that are produced by some transaction. -- XXX: Defined here to avoid cyclic module dependency -utxoProducedByTx :: Tx Era -> UTxO +utxoProducedByTx :: Tx Era -> UTxO Era utxoProducedByTx tx = UTxO.fromList $ zip [0 ..] (txOuts body) diff --git a/hydra-cardano-api/src/Hydra/Cardano/Api/TxId.hs b/hydra-cardano-api/src/Hydra/Cardano/Api/TxId.hs index f97a2293949..f7d4fad501e 100644 --- a/hydra-cardano-api/src/Hydra/Cardano/Api/TxId.hs +++ b/hydra-cardano-api/src/Hydra/Cardano/Api/TxId.hs @@ -4,7 +4,6 @@ module Hydra.Cardano.Api.TxId where import Hydra.Cardano.Api.Prelude -import Cardano.Binary (FromCBOR (..), ToCBOR (..)) import Cardano.Crypto.Hash.Class qualified as CC import Cardano.Ledger.Hashes qualified as Ledger import Cardano.Ledger.TxIn qualified as Ledger diff --git a/hydra-cardano-api/src/Hydra/Cardano/Api/TxIn.hs b/hydra-cardano-api/src/Hydra/Cardano/Api/TxIn.hs index 7a4cdca7c0f..65e8ffbed77 100644 --- a/hydra-cardano-api/src/Hydra/Cardano/Api/TxIn.hs +++ b/hydra-cardano-api/src/Hydra/Cardano/Api/TxIn.hs @@ -17,8 +17,8 @@ import Test.QuickCheck (choose, vectorOf) -- | Create a 'TxIn' (a.k.a UTXO) from a transaction and output index. mkTxIn :: Tx era -> Word -> TxIn -mkTxIn (getTxId . getTxBody -> txId) index = - TxIn txId (TxIx index) +mkTxIn (getTxId . getTxBody -> a) index = + TxIn a (TxIx index) -- | Attach some verification-key witness to a 'TxIn'. withWitness :: TxIn -> (TxIn, BuildTxWith BuildTx (Witness WitCtxTxIn Era)) diff --git a/hydra-cardano-api/src/Hydra/Cardano/Api/TxOut.hs b/hydra-cardano-api/src/Hydra/Cardano/Api/TxOut.hs index 3fe677d8179..27945dce7f3 100644 --- a/hydra-cardano-api/src/Hydra/Cardano/Api/TxOut.hs +++ b/hydra-cardano-api/src/Hydra/Cardano/Api/TxOut.hs @@ -87,7 +87,7 @@ findTxOutByAddress address tx = findTxOutByScript :: forall lang. IsPlutusScriptLanguage lang => - UTxO -> + UTxO Era -> PlutusScript lang -> Maybe (TxIn, TxOut CtxUTxO Era) findTxOutByScript utxo script = diff --git a/hydra-cardano-api/src/Hydra/Cardano/Api/UTxO.hs b/hydra-cardano-api/src/Hydra/Cardano/Api/UTxO.hs index 76990cf7df5..3ec3ba4edb4 100644 --- a/hydra-cardano-api/src/Hydra/Cardano/Api/UTxO.hs +++ b/hydra-cardano-api/src/Hydra/Cardano/Api/UTxO.hs @@ -4,7 +4,6 @@ import Hydra.Cardano.Api.Prelude hiding (fromLedgerUTxO) import Hydra.Cardano.Api.TxId (toLedgerTxId) import Hydra.Cardano.Api.TxIn (txIns') -import Cardano.Api.Tx.UTxO qualified as Api.UTxO import Cardano.Api.UTxO qualified as UTxO import Cardano.Ledger.Api (outputsTxBodyL) import Cardano.Ledger.BaseTypes qualified as Ledger @@ -14,36 +13,21 @@ import Control.Lens ((^.)) import Data.Foldable (toList) import Data.Map qualified as Map import Data.Maybe (mapMaybe) -import Data.String (IsString (..)) -import Data.Text qualified as Text - --- | Get a human-readable pretty text representation of a UTxO. -renderUTxO :: IsString str => UTxO -> str -renderUTxO = - fromString . Text.unpack . Text.intercalate "\n" . fmap UTxO.render . UTxO.toList -- | Construct a UTxO from a transaction. This constructs artificial `TxIn` -- (a.k.a output reference) from the transaction itself, zipping them to the -- outputs they correspond to. -utxoFromTx :: Tx Era -> UTxO +utxoFromTx :: Tx Era -> UTxO Era utxoFromTx (Tx body@(ShelleyTxBody _ ledgerBody _ _ _ _) _) = let txOuts = toList $ ledgerBody ^. outputsTxBodyL txIns = [ Ledger.TxIn (toLedgerTxId $ getTxId body) ix | ix <- [Ledger.TxIx 0 .. toEnum (length txOuts)] ] - in fromLedgerUTxO $ Ledger.UTxO $ Map.fromList $ zip txIns txOuts + in UTxO.fromShelleyUTxO shelleyBasedEra $ Ledger.UTxO $ Map.fromList $ zip txIns txOuts -- | Resolve tx inputs in a given UTxO -resolveInputsUTxO :: UTxO -> Tx Era -> UTxO +resolveInputsUTxO :: UTxO Era -> Tx Era -> UTxO Era resolveInputsUTxO utxo tx = UTxO.fromList $ mapMaybe (\txIn -> (txIn,) <$> UTxO.resolveTxIn txIn utxo) (txIns' tx) - --- * Type Conversions - -toLedgerUTxO :: UTxO -> Ledger.UTxO LedgerEra -toLedgerUTxO = Api.UTxO.toShelleyUTxO shelleyBasedEra . UTxO.toApi - -fromLedgerUTxO :: Ledger.UTxO LedgerEra -> UTxO -fromLedgerUTxO = UTxO.fromApi . Api.UTxO.fromShelleyUTxO shelleyBasedEra diff --git a/hydra-cardano-api/src/Hydra/Cardano/Api/Value.hs b/hydra-cardano-api/src/Hydra/Cardano/Api/Value.hs index ee073311fb3..94ebc705b26 100644 --- a/hydra-cardano-api/src/Hydra/Cardano/Api/Value.hs +++ b/hydra-cardano-api/src/Hydra/Cardano/Api/Value.hs @@ -2,7 +2,7 @@ module Hydra.Cardano.Api.Value where import Hydra.Cardano.Api.Prelude hiding (toLedgerValue) -import Cardano.Api.Ledger (Coin (..), PParams) +import Cardano.Api.Ledger (PParams) import Cardano.Ledger.Core (getMinCoinTxOut) import Cardano.Ledger.Mary.Value qualified as Ledger import Data.Word (Word64) @@ -91,4 +91,4 @@ fromPlutusValue plutusValue = do pure (AssetId pid (toAssetName tk), Quantity i) toAssetName :: Plutus.TokenName -> AssetName - toAssetName = AssetName . fromBuiltin . unTokenName + toAssetName = UnsafeAssetName . fromBuiltin . unTokenName diff --git a/hydra-chain-observer/hydra-chain-observer.cabal b/hydra-chain-observer/hydra-chain-observer.cabal index a883e006455..4846c1c9253 100644 --- a/hydra-chain-observer/hydra-chain-observer.cabal +++ b/hydra-chain-observer/hydra-chain-observer.cabal @@ -55,6 +55,7 @@ library , optparse-applicative , ouroboros-network-protocols , retry + , text exposed-modules: Hydra.Blockfrost.ChainObserver diff --git a/hydra-chain-observer/src/Hydra/Blockfrost/ChainObserver.hs b/hydra-chain-observer/src/Hydra/Blockfrost/ChainObserver.hs index 83efcbd3815..862d57c8e4e 100644 --- a/hydra-chain-observer/src/Hydra/Blockfrost/ChainObserver.hs +++ b/hydra-chain-observer/src/Hydra/Blockfrost/ChainObserver.hs @@ -15,6 +15,7 @@ import Control.Concurrent.Class.MonadSTM ( ) import Control.Retry (RetryPolicyM, RetryStatus, constantDelay, retrying) import Data.ByteString.Base16 qualified as Base16 +import Data.Text qualified as T import Hydra.Cardano.Api ( ChainPoint (..), HasTypeProxy (..), @@ -25,6 +26,7 @@ import Hydra.Cardano.Api ( SlotNo (..), Tx, UTxO, + deserialiseFromRawBytes, serialiseToRawBytes, ) import Hydra.Cardano.Api.Prelude ( @@ -87,7 +89,7 @@ blockfrostClient tracer projectPath blockConfirmations = do case startChainFrom of Just point -> pure point Nothing -> do - toChainPoint <$> runBlockfrostM prj Blockfrost.getLatestBlock + toChainPoint =<< runBlockfrostM prj Blockfrost.getLatestBlock traceWith tracer StartObservingFrom{chainPoint} @@ -165,7 +167,7 @@ rollForward tracer prj networkId observerHandler blockConfirmations (blockHash, -- Convert to cardano-api Tx receivedTxs <- mapM (toTx . (\(Blockfrost.TxHashCBOR (_txHash, cbor)) -> cbor)) txHashesCBOR let receivedTxIds = txId <$> receivedTxs - let point = toChainPoint block + point <- toChainPoint block traceWith tracer RollForward{point, receivedTxIds} -- Collect head observations @@ -193,16 +195,16 @@ isRetryable (NotEnoughBlockConfirmations _) = True isRetryable (MissingBlockNo _) = True isRetryable (MissingNextBlockHash _) = True -toChainPoint :: Blockfrost.Block -> ChainPoint -toChainPoint Blockfrost.Block{_blockSlot, _blockHash} = - ChainPoint slotNo headerHash +toChainPoint :: MonadThrow m => Blockfrost.Block -> m ChainPoint +toChainPoint Blockfrost.Block{_blockSlot, _blockHash} = do + blockHash' <- case deserialiseFromRawBytes (proxyToAsType (Proxy @(Hash BlockHeader))) $ fromString $ T.unpack $ Blockfrost.unBlockHash _blockHash of + Left _ -> throwIO $ DecodeError $ Blockfrost.unBlockHash _blockHash + Right x -> pure x + pure $ ChainPoint slotNo blockHash' where slotNo :: SlotNo slotNo = maybe 0 (fromInteger . Blockfrost.unSlot) _blockSlot - headerHash :: Hash BlockHeader - headerHash = fromString . toString $ Blockfrost.unBlockHash _blockHash - fromNetworkMagic :: Integer -> NetworkId fromNetworkMagic = \case 0 -> Mainnet diff --git a/hydra-cluster/hydra-cluster.cabal b/hydra-cluster/hydra-cluster.cabal index 2f0e772f051..04792d913f6 100644 --- a/hydra-cluster/hydra-cluster.cabal +++ b/hydra-cluster/hydra-cluster.cabal @@ -87,6 +87,7 @@ library , async , base >=4.7 && <5 , bytestring + , cardano-api , cardano-ledger-alonzo , cardano-ledger-api , cardano-ledger-core @@ -164,6 +165,7 @@ test-suite tests , async , base >=4.7 && <5 , bytestring + , cardano-api , cardano-ledger-api , containers , directory diff --git a/hydra-cluster/src/Hydra/Cluster/Faucet.hs b/hydra-cluster/src/Hydra/Cluster/Faucet.hs index 3ef33949034..680d47327d4 100644 --- a/hydra-cluster/src/Hydra/Cluster/Faucet.hs +++ b/hydra-cluster/src/Hydra/Cluster/Faucet.hs @@ -129,8 +129,8 @@ seedFromFaucetBlockfrost receivingVerificationKey lovelace = do case eResult of Left err -> liftIO $ throwIO $ FaucetBlockfrostError{blockFrostError = show err} Right _ -> do - void $ Blockfrost.awaitUTxO networkId [changeAddress] (txId signedTx) 200 - Blockfrost.awaitUTxO networkId [receivingAddress] (txId signedTx) 200 + void $ Blockfrost.awaitUTxO networkId [changeAddress] (Hydra.Tx.txId signedTx) 200 + Blockfrost.awaitUTxO networkId [receivingAddress] (Hydra.Tx.txId signedTx) 200 where findUTxO networkId address lovelace' = do faucetUTxO <- Blockfrost.queryUTxO networkId [address] diff --git a/hydra-cluster/src/Hydra/Cluster/Scenarios.hs b/hydra-cluster/src/Hydra/Cluster/Scenarios.hs index 373b8eb6094..9ac56d51950 100644 --- a/hydra-cluster/src/Hydra/Cluster/Scenarios.hs +++ b/hydra-cluster/src/Hydra/Cluster/Scenarios.hs @@ -400,7 +400,7 @@ nodeReObservesOnChainTxs tracer workDir backend hydraScriptsTxId = do guard $ v ^? key "headId" == Just (toJSON headId) v ^? key "distributedUTxO" . _JSON - guard $ distributedUTxO `UTxO.containsOutputs` utxoFromTx decommitTx + guard $ distributedUTxO `UTxO.containsOutputs` UTxO.txOutputs (utxoFromTx decommitTx) pure (headId, decommitUTxO) @@ -424,7 +424,7 @@ nodeReObservesOnChainTxs tracer workDir backend hydraScriptsTxId = do guard $ v ^? key "headId" == Just (toJSON headId2) v ^? key "distributedUTxO" . _JSON - guard $ distributedUTxO `UTxO.containsOutputs` decrementOuts + guard $ distributedUTxO `UTxO.containsOutputs` UTxO.txOutputs decrementOuts send n1 $ input "Close" [] @@ -1443,13 +1443,13 @@ rejectCommit tracer workDir blockTime backend hydraScriptsTxId = commitUTxO' <- seedFromFaucet backend walletVk (lovelaceToValue 1_000_000) (contramap FromFaucet tracer) TxOut _ _ _ refScript <- generate genTxOutWithReferenceScript datum <- generate genDatum - let commitUTxO :: UTxO.UTxO = + let commitUTxO :: UTxO = UTxO.fromList $ (\(i, TxOut addr _ _ _) -> (i, TxOut addr (lovelaceToValue 0) datum refScript)) <$> UTxO.toList commitUTxO' response <- L.parseRequest ("POST " <> hydraNodeBaseUrl n1 <> "/commit") - <&> setRequestBodyJSON (commitUTxO :: UTxO.UTxO) + <&> setRequestBodyJSON (commitUTxO :: UTxO) >>= httpJSON let expectedError = getResponseBody response :: PostTxError Tx @@ -1838,7 +1838,7 @@ canDecommit tracer workDir backend hydraScriptsTxId = guard $ v ^? key "headId" == Just (toJSON headId) v ^? key "distributedUTxO" . _JSON - guard $ distributedUTxO `UTxO.containsOutputs` decommitUTxO + guard $ distributedUTxO `UTxO.containsOutputs` UTxO.txOutputs decommitUTxO expectFailureOnUnsignedDecommitTx :: HydraClient -> HeadId -> Tx -> IO () expectFailureOnUnsignedDecommitTx n headId decommitTx = do @@ -2166,7 +2166,7 @@ checkFanout expectedHeadId expectedUTxO v = do headId' <- v ^? key "headId" >>= parseMaybe parseJSON utxo <- v ^? key "utxo" >>= parseMaybe parseJSON guard (headId' == expectedHeadId) - guard (UTxO.containsOutputs utxo expectedUTxO) + guard (UTxO.containsOutputs utxo (UTxO.txOutputs expectedUTxO)) expectErrorStatus :: -- | Expected http status code diff --git a/hydra-cluster/test/Test/BlockfrostChainSpec.hs b/hydra-cluster/test/Test/BlockfrostChainSpec.hs index 9924c62f0a8..ed55af0d6f6 100644 --- a/hydra-cluster/test/Test/BlockfrostChainSpec.hs +++ b/hydra-cluster/test/Test/BlockfrostChainSpec.hs @@ -137,7 +137,7 @@ spec = around (onlyWithBlockfrostProjectFile . showLogsOnFailure "BlockfrostChai observesInTimeSatisfying' aliceChain 500 $ \case OnFanoutTx{headId = headId', fanoutUTxO} | headId' == headId -> - if UTxO.containsOutputs fanoutUTxO expectedUTxO + if UTxO.containsOutputs fanoutUTxO (UTxO.txOutputs expectedUTxO) then pure () else failure "OnFanoutTx does not contain expected UTxO" _ -> failure "expected OnFanoutTx" diff --git a/hydra-cluster/test/Test/ChainObserverSpec.hs b/hydra-cluster/test/Test/ChainObserverSpec.hs index 98408123944..66889e0be17 100644 --- a/hydra-cluster/test/Test/ChainObserverSpec.hs +++ b/hydra-cluster/test/Test/ChainObserverSpec.hs @@ -92,7 +92,7 @@ spec = do guard $ v ^? key "headId" == Just (toJSON headId) v ^? key "distributedUTxO" . _JSON - guard $ distributedUTxO `UTxO.containsOutputs` utxoFromTx decommitTx + guard $ distributedUTxO `UTxO.containsOutputs` UTxO.txOutputs (utxoFromTx decommitTx) send hydraNode $ input "Close" [] diff --git a/hydra-cluster/test/Test/DirectChainSpec.hs b/hydra-cluster/test/Test/DirectChainSpec.hs index 248c761f151..2db074e7979 100644 --- a/hydra-cluster/test/Test/DirectChainSpec.hs +++ b/hydra-cluster/test/Test/DirectChainSpec.hs @@ -19,11 +19,10 @@ import Data.List.Split (splitWhen) import Data.Set qualified as Set import Hydra.Cardano.Api ( ChainPoint (..), - CtxUTxO, Key (SigningKey), PaymentKey, - TxOut, - UTxO', + UTxO, + deserialiseFromRawBytesThrow, fromLedgerTx, lovelaceToValue, signTx, @@ -356,7 +355,7 @@ spec = around (showLogsOnFailure "DirectChainSpec") $ do `withoutUTxO` fromMaybe mempty (Snapshot.utxoToDecommit snapshot) aliceChain `observesInTimeSatisfying` \case OnFanoutTx _ finalUTxO -> - if UTxO.containsOutputs finalUTxO expectedUTxO + if UTxO.containsOutputs finalUTxO (UTxO.txOutputs expectedUTxO) then pure () else failure "OnFanoutTx does not contain expected UTxO" _ -> failure "expected OnFanoutTx" @@ -396,7 +395,7 @@ spec = around (showLogsOnFailure "DirectChainSpec") $ do seedFromFaucet_ backend aliceCardanoVk 100_000_000 (contramap FromFaucet tracer) hydraScriptsTxId <- publishHydraScriptsAs backend Faucet - let headerHash = fromString (replicate 64 '0') + headerHash <- deserialiseFromRawBytesThrow $ fromString (replicate 64 '0') let fakeTip = ChainPoint 42 headerHash aliceChainConfig <- chainConfigFor Alice tmp backend hydraScriptsTxId [] cperiod @@ -425,7 +424,7 @@ spec = around (showLogsOnFailure "DirectChainSpec") $ do ) ) "" - let hydraScriptsTxId = fromString <$> splitWhen (== ',') (filter (/= '\n') hydraScriptsTxIdStr) + hydraScriptsTxId <- mapM deserialiseFromRawBytesThrow (fromString <$> splitWhen (== ',') (filter (/= '\n') hydraScriptsTxIdStr)) failAfter 5 $ void $ Backend.queryScriptRegistry backend hydraScriptsTxId it "can only contest once" $ \tracer -> do @@ -616,7 +615,7 @@ externalCommit :: CardanoChainTest Tx IO -> SigningKey PaymentKey -> HeadId -> - UTxO' (TxOut CtxUTxO) -> + UTxO -> IO () externalCommit backend hydraClient externalSk headId utxoToCommit = do let blueprintTx = txSpendingUTxO utxoToCommit @@ -628,7 +627,7 @@ externalCommit' :: CardanoChainTest Tx IO -> [SigningKey PaymentKey] -> HeadId -> - UTxO' (TxOut CtxUTxO) -> + UTxO -> Tx -> IO () externalCommit' backend hydraClient externalSks headId utxoToCommit blueprintTx = do diff --git a/hydra-cluster/test/Test/EndToEndSpec.hs b/hydra-cluster/test/Test/EndToEndSpec.hs index 2ed324f1984..28ac15e77e7 100644 --- a/hydra-cluster/test/Test/EndToEndSpec.hs +++ b/hydra-cluster/test/Test/EndToEndSpec.hs @@ -26,7 +26,7 @@ import Data.Map qualified as Map import Data.Set qualified as Set import Data.Text (isInfixOf) import Data.Time (secondsToDiffTime) -import Hydra.Cardano.Api hiding (Value, cardanoEra, queryGenesisParameters) +import Hydra.Cardano.Api hiding (Value, cardanoEra, queryGenesisParameters, txId) import Hydra.Chain.Backend (ChainBackend) import Hydra.Chain.Backend qualified as Backend import Hydra.Chain.Direct.State () @@ -510,7 +510,7 @@ spec = around (showLogsOnFailure "EndToEndSpec") $ do waitForAllMatch 20 [n1, n2, n3] $ \v -> do guard $ v ^? key "tag" == Just "SnapshotConfirmed" - headUTxO :: UTxO.UTxO <- + headUTxO :: UTxO <- parseUrlThrow ("GET " <> hydraNodeBaseUrl n1 <> "/snapshot/utxo") >>= httpJSON <&> getResponseBody diff --git a/hydra-cluster/test/Test/Hydra/Cluster/HydraClientSpec.hs b/hydra-cluster/test/Test/Hydra/Cluster/HydraClientSpec.hs index 2d17124b78c..8493b006b29 100644 --- a/hydra-cluster/test/Test/Hydra/Cluster/HydraClientSpec.hs +++ b/hydra-cluster/test/Test/Hydra/Cluster/HydraClientSpec.hs @@ -15,7 +15,7 @@ import Data.Aeson ((.=)) import Data.Aeson.Lens (key) import Data.Set qualified as Set import Data.Text qualified as Text -import Hydra.Cardano.Api hiding (Value, cardanoEra, queryGenesisParameters) +import Hydra.Cardano.Api hiding (Value, cardanoEra, queryGenesisParameters, txId) import Hydra.Chain.Backend (ChainBackend) import Hydra.Chain.Backend qualified as Backend import Hydra.Chain.Direct (DirectBackend (..)) @@ -320,7 +320,7 @@ prepareScenario backend nodes tracer = do pure (expectedSnapshotNumber, txId tx, headId, aliceKeys, bobKeys) -- NOTE: this is partial and will fail if we are not able to generate a payment -sendTx :: NonEmpty HydraClient -> UTxO' (TxOut CtxUTxO) -> SigningKey PaymentKey -> VerificationKey PaymentKey -> Lovelace -> IO Tx +sendTx :: NonEmpty HydraClient -> UTxO -> SigningKey PaymentKey -> VerificationKey PaymentKey -> Lovelace -> IO Tx sendTx nodes senderUTxO sender receiver amount = do let utxo = Prelude.head $ UTxO.toList senderUTxO let Right tx = diff --git a/hydra-node/hydra-node.cabal b/hydra-node/hydra-node.cabal index 5c313330b94..236fa705227 100644 --- a/hydra-node/hydra-node.cabal +++ b/hydra-node/hydra-node.cabal @@ -153,7 +153,6 @@ library , network , optparse-applicative , ouroboros-consensus - , ouroboros-consensus-cardano , ouroboros-network-api >=0.7.1 , ouroboros-network-protocols >=0.8 , process @@ -257,6 +256,7 @@ benchmark tx-cost build-depends: , base , bytestring + , cardano-api , cardano-binary , directory , filepath @@ -350,6 +350,7 @@ test-suite tests , amazonka-s3 , base , bytestring + , cardano-api , cardano-api:gen , cardano-binary , cardano-crypto-class diff --git a/hydra-node/src/Hydra/Chain/Backend.hs b/hydra-node/src/Hydra/Chain/Backend.hs index 149687bc1ec..20347148b5f 100644 --- a/hydra-node/src/Hydra/Chain/Backend.hs +++ b/hydra-node/src/Hydra/Chain/Backend.hs @@ -165,7 +165,7 @@ buildTransactionWithBody pparams systemStart eraHistory stakePools changeAddress stakePools mempty mempty - (UTxO.toApi utxoToSpend) + utxoToSpend body changeAddress Nothing diff --git a/hydra-node/src/Hydra/Chain/Blockfrost.hs b/hydra-node/src/Hydra/Chain/Blockfrost.hs index 83cb4b21e43..cd8a03248c0 100644 --- a/hydra-node/src/Hydra/Chain/Blockfrost.hs +++ b/hydra-node/src/Hydra/Chain/Blockfrost.hs @@ -14,6 +14,7 @@ import Hydra.Cardano.Api ( SlotNo (..), Tx, deserialiseFromCBOR, + deserialiseFromRawBytes, getTxBody, getTxId, proxyToAsType, @@ -271,12 +272,14 @@ rollForward tracer prj handler wallet blockConfirmations blockHash = do -- Convert to cardano-api Tx receivedTxs <- mapM (toTx . (\(Blockfrost.TxHashCBOR (_txHash, cbor)) -> cbor)) txHashesCBOR let receivedTxIds = getTxId . getTxBody <$> receivedTxs - let point = toChainPoint block + point <- toChainPoint block traceWith tracer RolledForward{point, receivedTxIds} blockNo <- maybe (throwIO $ MissingBlockNo _blockHash) (pure . fromInteger) _blockHeight let Blockfrost.BlockHash blockHash' = _blockHash - let blockHash'' = fromString $ T.unpack blockHash' + blockHash'' <- case deserialiseFromRawBytes (proxyToAsType (Proxy @(Hash BlockHeader))) $ fromString $ T.unpack blockHash' of + Left _ -> throwIO $ DecodeError blockHash' + Right x -> pure x blockSlot <- maybe (throwIO $ MissingBlockSlot _blockSlot) (pure . fromInteger . Blockfrost.unSlot) _blockSlot let header = BlockHeader (SlotNo blockSlot) blockHash'' blockNo -- wallet update @@ -311,16 +314,16 @@ blockfrostSubmissionClient prj tracer queue = bfClient atomically (putTMVar response Nothing) bfClient -toChainPoint :: Blockfrost.Block -> ChainPoint -toChainPoint Blockfrost.Block{_blockSlot, _blockHash} = - ChainPoint slotNo headerHash +toChainPoint :: MonadThrow m => Blockfrost.Block -> m ChainPoint +toChainPoint Blockfrost.Block{_blockSlot, _blockHash} = do + blockHash' <- case deserialiseFromRawBytes (proxyToAsType (Proxy @(Hash BlockHeader))) $ fromString $ T.unpack $ Blockfrost.unBlockHash _blockHash of + Left _ -> throwIO $ DecodeError $ Blockfrost.unBlockHash _blockHash + Right x -> pure x + pure $ ChainPoint slotNo blockHash' where slotNo :: SlotNo slotNo = maybe 0 (fromInteger . Blockfrost.unSlot) _blockSlot - headerHash :: Hash BlockHeader - headerHash = fromString . toString $ Blockfrost.unBlockHash _blockHash - -- * Helpers data APIBlockfrostError diff --git a/hydra-node/src/Hydra/Chain/Blockfrost/Client.hs b/hydra-node/src/Hydra/Chain/Blockfrost/Client.hs index 5e01aec705b..6b6acde22ce 100644 --- a/hydra-node/src/Hydra/Chain/Blockfrost/Client.hs +++ b/hydra-node/src/Hydra/Chain/Blockfrost/Client.hs @@ -37,7 +37,7 @@ import Hydra.Cardano.Api hiding (LedgerState, fromNetworkMagic, queryGenesisPara import Cardano.Api.UTxO qualified as UTxO import Cardano.Ledger.Api.PParams -import Cardano.Ledger.BaseTypes (EpochInterval (..), EpochSize (..), NonNegativeInterval, UnitInterval, boundRational, unsafeNonZero) +import Cardano.Ledger.BaseTypes (EpochInterval (..), NonNegativeInterval, UnitInterval, boundRational, unsafeNonZero) import Cardano.Ledger.Binary.Version (mkVersion) import Cardano.Ledger.Conway.Core ( DRepVotingThresholds (..), @@ -61,7 +61,7 @@ import Data.List qualified as List import Data.SOP.NonEmpty (nonEmptyFromList) import Data.Set qualified as Set import Data.Text qualified as T -import Hydra.Cardano.Api.Prelude (StakePoolKey, fromNetworkMagic) +import Hydra.Cardano.Api.Prelude (fromNetworkMagic) import Hydra.Tx (ScriptRegistry, newScriptRegistry) import Money qualified import Ouroboros.Consensus.Block (GenesisWindow (..)) @@ -70,6 +70,8 @@ import Ouroboros.Consensus.HardFork.History (Bound (..), EraEnd (..), EraParams data BlockfrostException = TimeoutOnUTxO TxId | FailedToDecodeAddress Text + | FailedToDecodeBlockHeader Text + | FailedToDecodeDatum Text | ByronAddressNotSupported | FailedUTxOForHash Text | FailedEraHistory @@ -190,7 +192,7 @@ queryProtocolParameters = do & ppDRepActivityL .~ EpochInterval (fromIntegral $ Blockfrost.unQuantity drepActivity) & ppMinFeeRefScriptCostPerByteL .~ minFeeRefScriptCostPerByte where - convertCostModels :: Blockfrost.CostModelsRaw -> CostModels + convertCostModels :: Blockfrost.CostModelsRaw -> Cardano.Ledger.Plutus.CostModels.CostModels convertCostModels costModels = let costModelsMap = Blockfrost.unCostModelsRaw costModels in foldMap @@ -208,7 +210,7 @@ queryProtocolParameters = do -- ** Helpers -toCardanoUTxO :: NetworkId -> TxIn -> Blockfrost.Address -> Maybe Blockfrost.ScriptHash -> Maybe Blockfrost.DatumHash -> [Blockfrost.Amount] -> Maybe Blockfrost.InlineDatum -> BlockfrostClientT IO (UTxO' (TxOut ctx)) +toCardanoUTxO :: NetworkId -> TxIn -> Blockfrost.Address -> Maybe Blockfrost.ScriptHash -> Maybe Blockfrost.DatumHash -> [Blockfrost.Amount] -> Maybe Blockfrost.InlineDatum -> BlockfrostClientT IO UTxO toCardanoUTxO networkId txIn address scriptHash datumHash amount inlineDatum = do let addrTxt = Blockfrost.unAddress address let datumHash' = Blockfrost.unDatumHash <$> datumHash @@ -239,16 +241,18 @@ toCardanoTxIn txHash i = toCardanoTxOut :: NetworkId -> Text -> Value -> Maybe Text -> Maybe Text -> Maybe PlutusScript -> BlockfrostClientT IO (TxOut ctx) toCardanoTxOut networkId addrTxt val mDatumHash mInlineDatum plutusScript = do - let datum = - case mInlineDatum of - Nothing -> - case mDatumHash of - Nothing -> TxOutDatumNone - Just datumHash -> TxOutDatumHash (fromString $ T.unpack datumHash) - Just cborDatum -> - case deserialiseFromCBOR (proxyToAsType (Proxy @HashableScriptData)) (encodeUtf8 cborDatum) of - Left _ -> TxOutDatumNone - Right hashableScriptData -> TxOutDatumInline hashableScriptData + datum <- + case mInlineDatum of + Nothing -> + case mDatumHash of + Nothing -> pure TxOutDatumNone + Just datumHash -> case deserialiseFromRawBytes (proxyToAsType (Proxy @(Hash ScriptData))) (fromString . T.unpack $ datumHash) of + Left _ -> liftIO $ throwIO $ FailedToDecodeDatum datumHash + Right x -> pure $ TxOutDatumHash x + Just cborDatum -> pure $ + case deserialiseFromCBOR (proxyToAsType (Proxy @HashableScriptData)) (encodeUtf8 cborDatum) of + Left _ -> TxOutDatumNone + Right hashableScriptData -> TxOutDatumInline hashableScriptData case plutusScript of Nothing -> do case toCardanoAddress addrTxt of @@ -508,11 +512,14 @@ queryTip = do Nothing -> pure $ chainTipToChainPoint ChainTipAtGenesis Just (blockSlot, blockNo) -> do let Blockfrost.BlockHash blockHash = _blockHash + bh <- case deserialiseFromRawBytes (proxyToAsType (Proxy @(Hash BlockHeader))) (fromString $ T.unpack blockHash) of + Left _ -> liftIO $ throwIO $ FailedToDecodeBlockHeader blockHash + Right x -> pure x pure $ chainTipToChainPoint $ ChainTip (SlotNo $ fromIntegral $ Blockfrost.unSlot blockSlot) - (fromString $ T.unpack blockHash) + bh (BlockNo $ fromIntegral blockNo) queryStakePools :: diff --git a/hydra-node/src/Hydra/Chain/Cardano.hs b/hydra-node/src/Hydra/Chain/Cardano.hs index 124d71b1d60..38c7277ad23 100644 --- a/hydra-node/src/Hydra/Chain/Cardano.hs +++ b/hydra-node/src/Hydra/Chain/Cardano.hs @@ -4,6 +4,7 @@ module Hydra.Chain.Cardano where import Hydra.Prelude +import Cardano.Api.UTxO qualified as UTxO import Cardano.Ledger.Shelley.API qualified as Ledger import Cardano.Ledger.Slot (EpochInfo) import Cardano.Slotting.EpochInfo (hoistEpochInfo) @@ -11,7 +12,7 @@ import Control.Monad.Trans.Except (runExcept) import Hydra.Cardano.Api ( EraHistory (EraHistory), Tx, - toLedgerUTxO, + shelleyBasedEra, ) import Hydra.Chain (ChainComponent, ChainStateHistory) import Hydra.Chain.Backend (ChainBackend (..)) @@ -106,7 +107,7 @@ mkTinyWallet backend tracer config = do point <- case queryPoint of QueryAt point -> pure point QueryTip -> queryTip backend - walletUTxO <- Ledger.unUTxO . toLedgerUTxO <$> queryUTxO backend [address] + walletUTxO <- Ledger.unUTxO . UTxO.toShelleyUTxO shelleyBasedEra <$> queryUTxO backend [address] systemStart <- querySystemStart backend QueryTip pure $ WalletInfoOnChain{walletUTxO, systemStart, tip = point} diff --git a/hydra-node/src/Hydra/Chain/CardanoClient.hs b/hydra-node/src/Hydra/Chain/CardanoClient.hs index 293dd192b37..bbfeeff485d 100644 --- a/hydra-node/src/Hydra/Chain/CardanoClient.hs +++ b/hydra-node/src/Hydra/Chain/CardanoClient.hs @@ -12,14 +12,11 @@ import Cardano.Api.UTxO qualified as UTxO import Data.Aeson (eitherDecode', encode) import Data.Set qualified as Set import Data.Text qualified as Text -import Ouroboros.Consensus.Cardano.Block (EraMismatch (..)) import Text.Printf (printf) -- XXX: This should be re-exported by cardano-api -- https://github.com/IntersectMBO/cardano-api/issues/447 -import Ouroboros.Network.Protocol.LocalStateQuery.Type (Target (..)) - data QueryException = QueryAcquireException AcquiringFailure | QueryEraMismatchException EraMismatch @@ -29,6 +26,7 @@ data QueryException | QueryProtocolParamsEncodingFailureOnEra AnyCardanoEra Text | QueryEraNotInCardanoModeFailure AnyCardanoEra | QueryNotShelleyBasedEraException AnyCardanoEra + | QueryNotConwayEraOnwardsException AnyCardanoEra deriving stock (Show, Eq) instance Exception QueryException where @@ -47,6 +45,8 @@ instance Exception QueryException where printf "Error while querying using era %s not in cardano mode." (show eraName :: Text) QueryNotShelleyBasedEraException eraName -> printf "Error while querying using era %s not in shelley based era." (show eraName :: Text) + QueryNotConwayEraOnwardsException eraName -> + printf "Error while querying using era %s not in conway based era." (show eraName :: Text) -- * CardanoClient handle @@ -161,9 +161,7 @@ queryEpochNo :: IO EpochNo queryEpochNo networkId socket queryPoint = do runQueryExpr networkId socket queryPoint $ do - (AnyCardanoEra era) <- queryCurrentEraExpr - (sbe :: ShelleyBasedEra e) <- liftIO $ assumeShelleyBasedEraOrThrow era - queryInShelleyBasedEraExpr sbe QueryEpoch + queryForCurrentEraInShelleyBasedEraExpr (`queryInShelleyBasedEraExpr` QueryEpoch) -- | Query the protocol parameters at given point and convert them to Babbage -- era protocol parameters. @@ -178,10 +176,9 @@ queryProtocolParameters :: IO (PParams LedgerEra) queryProtocolParameters networkId socket queryPoint = runQueryExpr networkId socket queryPoint $ do - (AnyCardanoEra era) <- queryCurrentEraExpr - sbe <- liftIO $ assumeShelleyBasedEraOrThrow era - eraPParams <- queryInShelleyBasedEraExpr sbe QueryProtocolParameters - liftIO $ coercePParamsToLedgerEra era eraPParams + queryForCurrentEraInShelleyBasedEraExpr $ \sbe -> do + eraPParams <- queryInShelleyBasedEraExpr sbe QueryProtocolParameters + liftIO $ coercePParamsToLedgerEra (convert sbe) eraPParams where encodeToEra :: ToJSON a => CardanoEra era -> a -> IO (PParams LedgerEra) encodeToEra eraToEncode pparams = @@ -212,9 +209,7 @@ queryGenesisParameters :: IO (GenesisParameters ShelleyEra) queryGenesisParameters networkId socket queryPoint = runQueryExpr networkId socket queryPoint $ do - (AnyCardanoEra era) <- queryCurrentEraExpr - sbe <- liftIO $ assumeShelleyBasedEraOrThrow era - queryInShelleyBasedEraExpr sbe QueryGenesisParameters + queryForCurrentEraInShelleyBasedEraExpr (`queryInShelleyBasedEraExpr` QueryGenesisParameters) -- | Query UTxO for all given addresses at given point. -- @@ -222,14 +217,12 @@ queryGenesisParameters networkId socket queryPoint = queryUTxO :: NetworkId -> SocketPath -> QueryPoint -> [Address ShelleyAddr] -> IO UTxO queryUTxO networkId socket queryPoint addresses = runQueryExpr networkId socket queryPoint $ do - (AnyCardanoEra era) <- queryCurrentEraExpr - sbe <- liftIO $ assumeShelleyBasedEraOrThrow era - queryUTxOExpr sbe addresses + queryForCurrentEraInConwayEraOnwardsExpr + (`queryUTxOExpr` addresses) -queryUTxOExpr :: ShelleyBasedEra era -> [Address ShelleyAddr] -> LocalStateQueryExpr b p QueryInMode r IO UTxO -queryUTxOExpr sbe addresses = do - eraUTxO <- queryInShelleyBasedEraExpr sbe $ QueryUTxO (QueryUTxOByAddress (Set.fromList $ map AddressShelley addresses)) - pure $ UTxO.fromApi eraUTxO +queryUTxOExpr :: ConwayEraOnwards era -> [Address ShelleyAddr] -> LocalStateQueryExpr b p QueryInMode r IO UTxO +queryUTxOExpr ceo addresses = case ceo of + ConwayEraOnwardsConway -> queryInShelleyBasedEraExpr (convert ceo) $ QueryUTxO (QueryUTxOByAddress (Set.fromList $ map AddressShelley addresses)) -- | Query UTxO for given tx inputs at given point. -- @@ -243,18 +236,31 @@ queryUTxOByTxIn :: [TxIn] -> IO UTxO queryUTxOByTxIn networkId socket queryPoint inputs = - runQueryExpr networkId socket queryPoint $ do - (AnyCardanoEra era) <- queryCurrentEraExpr - (sbe :: ShelleyBasedEra e) <- liftIO $ assumeShelleyBasedEraOrThrow era - eraUTxO <- queryInShelleyBasedEraExpr sbe $ QueryUTxO (QueryUTxOByTxIn (Set.fromList inputs)) - pure $ UTxO.fromApi eraUTxO - -assumeShelleyBasedEraOrThrow :: MonadThrow m => CardanoEra era -> m (ShelleyBasedEra era) -assumeShelleyBasedEraOrThrow era = do - x <- requireShelleyBasedEra era - case x of - Just sbe -> pure sbe - Nothing -> throwIO $ QueryNotShelleyBasedEraException (anyCardanoEra era) + runQueryExpr networkId socket queryPoint $ + queryForCurrentEraInConwayEraOnwardsExpr + ( \(ceo :: ConwayEraOnwards era) -> case ceo of + ConwayEraOnwardsConway -> queryInShelleyBasedEraExpr (convert ceo) (QueryUTxO (QueryUTxOByTxIn (Set.fromList inputs))) + ) + +queryForCurrentEraInEonExpr :: + Eon eon => + (AnyCardanoEra -> IO a) -> + (forall era. eon era -> LocalStateQueryExpr b p QueryInMode r IO a) -> + LocalStateQueryExpr b p QueryInMode r IO a +queryForCurrentEraInEonExpr no yes = do + k@(AnyCardanoEra era) <- queryCurrentEraExpr + inEonForEra (liftIO $ no k) yes era + +queryForCurrentEraInShelleyBasedEraExpr :: + (forall era. ShelleyBasedEra era -> LocalStateQueryExpr b p QueryInMode r IO a) -> + LocalStateQueryExpr b p QueryInMode r IO a +queryForCurrentEraInShelleyBasedEraExpr = queryForCurrentEraInEonExpr (throwIO . QueryNotShelleyBasedEraException) + +queryForCurrentEraInConwayEraOnwardsExpr :: + Eon eon => + (forall era. eon era -> LocalStateQueryExpr b p QueryInMode r IO a) -> + LocalStateQueryExpr b p QueryInMode r IO a +queryForCurrentEraInConwayEraOnwardsExpr = queryForCurrentEraInEonExpr (throwIO . QueryNotConwayEraOnwardsException) -- | Query the whole UTxO from node at given point. Useful for debugging, but -- should obviously not be used in production code. @@ -269,10 +275,10 @@ queryUTxOWhole :: IO UTxO queryUTxOWhole networkId socket queryPoint = do runQueryExpr networkId socket queryPoint $ do - (AnyCardanoEra era) <- queryCurrentEraExpr - (sbe :: ShelleyBasedEra e) <- liftIO $ assumeShelleyBasedEraOrThrow era - eraUTxO <- queryInShelleyBasedEraExpr sbe $ QueryUTxO QueryUTxOWhole - pure $ UTxO.fromApi eraUTxO + queryForCurrentEraInConwayEraOnwardsExpr + ( \(ceo :: ConwayEraOnwards era) -> case ceo of + ConwayEraOnwardsConway -> queryInShelleyBasedEraExpr (convert ceo) (QueryUTxO QueryUTxOWhole) + ) -- | Query UTxO for the address of given verification key at point. -- @@ -297,9 +303,7 @@ queryStakePools :: IO (Set PoolId) queryStakePools networkId socket queryPoint = runQueryExpr networkId socket queryPoint $ do - (AnyCardanoEra era) <- queryCurrentEraExpr - (sbe :: ShelleyBasedEra e) <- liftIO $ assumeShelleyBasedEraOrThrow era - queryInShelleyBasedEraExpr sbe QueryStakePools + queryForCurrentEraInShelleyBasedEraExpr (`queryInShelleyBasedEraExpr` QueryStakePools) -- * Helpers diff --git a/hydra-node/src/Hydra/Chain/Direct/Handlers.hs b/hydra-node/src/Hydra/Chain/Direct/Handlers.hs index 429fa7243da..6d93e3c3c5d 100644 --- a/hydra-node/src/Hydra/Chain/Direct/Handlers.hs +++ b/hydra-node/src/Hydra/Chain/Direct/Handlers.hs @@ -23,6 +23,7 @@ import Hydra.Cardano.Api ( LedgerEra, Tx, TxId, + UTxO, calculateMinimumUTxO, chainPointToSlotNo, fromCtxUTxOTxOut, @@ -219,7 +220,7 @@ mkChain tracer queryTimeHandle wallet ctx LocalChainState{getLatest} submitTx = -- Check each UTxO entry against the minADAUTxO value. -- Throws 'DepositTooLow' exception. -rejectLowDeposits :: PParams LedgerEra -> UTxO.UTxO -> Maybe Coin -> Either (PostTxError Tx) () +rejectLowDeposits :: PParams LedgerEra -> UTxO -> Maybe Coin -> Either (PostTxError Tx) () rejectLowDeposits pparams utxo amount = do let insAndOuts = UTxO.toList utxo let providedValues = (\(i, o) -> (i, UTxO.totalLovelace $ UTxO.singleton i o)) <$> insAndOuts @@ -236,7 +237,7 @@ rejectLowDeposits pparams utxo amount = do [] -> pure () (e : _) -> Left e -checkAmount :: UTxO.UTxO -> Maybe Coin -> Either (PostTxError Tx) () +checkAmount :: UTxO -> Maybe Coin -> Either (PostTxError Tx) () checkAmount utxo amount = case amount of Nothing -> pure () @@ -250,8 +251,8 @@ finalizeTx :: MonadThrow m => TinyWallet m -> ChainContext -> - UTxO.UTxO -> - UTxO.UTxO -> + UTxO -> + UTxO -> Tx -> m Tx finalizeTx TinyWallet{sign, coverFee} ctx utxo userUTxO partialTx = do diff --git a/hydra-node/src/Hydra/Chain/Direct/State.hs b/hydra-node/src/Hydra/Chain/Direct/State.hs index dbe7a63bfe7..77acf547a3f 100644 --- a/hydra-node/src/Hydra/Chain/Direct/State.hs +++ b/hydra-node/src/Hydra/Chain/Direct/State.hs @@ -17,7 +17,7 @@ import Data.Maybe (fromJust) import GHC.IsList qualified as IsList import Hydra.Cardano.Api ( AssetId (..), - AssetName (AssetName), + AssetName (..), ChainPoint (..), CtxUTxO, Key (SigningKey, VerificationKey, verificationKeyHash), @@ -33,7 +33,6 @@ import Hydra.Cardano.Api ( TxIn, TxOut, UTxO, - UTxO' (UTxO), Value, chainPointToSlotNo, fromCtxUTxOTxOut, @@ -57,6 +56,7 @@ import Hydra.Cardano.Api ( pattern ShelleyAddressInEra, pattern TxIn, pattern TxOut, + pattern UTxO, ) import Hydra.Chain ( OnChainTx (..), @@ -363,7 +363,7 @@ commit' ctx headId spendableUTxO commitBlueprintTx = do UTxO.find (hasMatchingPT pid . txOutValue) spendableUTxO hasMatchingPT pid val = - selectAsset val (AssetId pid (AssetName (serialiseToRawBytes vkh))) == 1 + selectAsset val (AssetId pid (UnsafeAssetName (serialiseToRawBytes vkh))) == 1 rejectByronAddress :: UTxO -> Either (PostTxError Tx) () rejectByronAddress u = do @@ -470,8 +470,8 @@ increment ctx spendableUTxO headId headParameters incrementingSnapshot depositTx let utxoOfThisHead' = utxoOfThisHead pid spendableUTxO headUTxO <- UTxO.find (isScriptTxOut Head.validatorScript) utxoOfThisHead' ?> CannotFindHeadOutputInIncrement (depositedIn, depositedOut) <- - UTxO.findBy - ( \(TxIn txid _, txout) -> + UTxO.findWithKey + ( \(TxIn txid _) txout -> isScriptTxOut depositValidatorScript txout && txid == depositTxId ) spendableUTxO @@ -560,8 +560,8 @@ recover :: Either RecoverTxError Tx recover ctx headId depositedTxId spendableUTxO lowerValiditySlot = do (_, depositedOut) <- - UTxO.findBy - ( \(TxIn txid _, txout) -> + UTxO.findWithKey + ( \(TxIn txid _) txout -> isScriptTxOut depositValidatorScript txout && txid == depositedTxId ) spendableUTxO diff --git a/hydra-node/src/Hydra/Chain/Direct/Wallet.hs b/hydra-node/src/Hydra/Chain/Direct/Wallet.hs index de9c084422f..9cca373d09a 100644 --- a/hydra-node/src/Hydra/Chain/Direct/Wallet.hs +++ b/hydra-node/src/Hydra/Chain/Direct/Wallet.hs @@ -6,7 +6,7 @@ module Hydra.Chain.Direct.Wallet where import Hydra.Prelude -import Cardano.Api.UTxO (UTxO) +import Cardano.Api.UTxO qualified as UTxO import Cardano.Ledger.Address qualified as Ledger import Cardano.Ledger.Alonzo.Plutus.Context (ContextError, EraPlutusContext) import Cardano.Ledger.Alonzo.Scripts ( @@ -86,13 +86,11 @@ import Hydra.Cardano.Api ( VerificationKey, fromLedgerTx, fromLedgerTxIn, - fromLedgerUTxO, getChainPoint, makeShelleyAddress, shelleyAddressInEra, toLedgerAddr, toLedgerTx, - toLedgerUTxO, verificationKeyHash, ) import Hydra.Cardano.Api qualified as Api @@ -120,7 +118,7 @@ data TinyWallet m = TinyWallet -- a head , sign :: Api.Tx -> Api.Tx , coverFee :: - UTxO -> + Api.UTxO -> Api.Tx -> m (Either ErrCoverFee Api.Tx) , reset :: m () @@ -164,7 +162,7 @@ newTinyWallet tracer networkId (vk, sk) queryWalletInfo queryEpochInfo querySome , getSeedInput = fmap (fromLedgerTxIn . fst) . findLargestUTxO <$> getUTxO , sign = Api.signTx sk , coverFee = \lookupUTxO partialTx -> do - let ledgerLookupUTxO = unUTxO $ toLedgerUTxO lookupUTxO + let ledgerLookupUTxO = unUTxO $ UTxO.toShelleyUTxO Api.shelleyBasedEra lookupUTxO WalletInfoOnChain{walletUTxO, systemStart} <- readTVarIO walletInfoVar epochInfo <- queryEpochInfo -- We query pparams here again as it's possible that a hardfork @@ -186,13 +184,13 @@ newTinyWallet tracer networkId (vk, sk) queryWalletInfo queryEpochInfo querySome let utxo' = applyTxs txs (== ledgerAddress) walletUTxO writeTVar walletInfoVar $ walletInfo{walletUTxO = utxo', tip = point} pure utxo' - traceWith tracer $ EndUpdate (fromLedgerUTxO (Ledger.UTxO utxo')) + traceWith tracer $ EndUpdate (UTxO.fromShelleyUTxO Api.shelleyBasedEra (Ledger.UTxO utxo')) } where initialize = do traceWith tracer BeginInitialize walletInfo@WalletInfoOnChain{walletUTxO, tip} <- queryWalletInfo QueryTip address - traceWith tracer $ EndInitialize{initialUTxO = fromLedgerUTxO (Ledger.UTxO walletUTxO), tip} + traceWith tracer $ EndInitialize{initialUTxO = UTxO.fromShelleyUTxO Api.shelleyBasedEra (Ledger.UTxO walletUTxO), tip} pure walletInfo address = diff --git a/hydra-node/src/Hydra/Chain/Offline.hs b/hydra-node/src/Hydra/Chain/Offline.hs index 251d50d1bb5..0d100a8c561 100644 --- a/hydra-node/src/Hydra/Chain/Offline.hs +++ b/hydra-node/src/Hydra/Chain/Offline.hs @@ -2,8 +2,7 @@ module Hydra.Chain.Offline where import Hydra.Prelude -import Cardano.Api.Internal.Genesis (shelleyGenesisDefaults) -import Cardano.Api.Internal.GenesisParameters (fromShelleyGenesis) +import Cardano.Api.Genesis (fromShelleyGenesis, shelleyGenesisDefaults) import Cardano.Ledger.Slot (unSlotNo) import Cardano.Slotting.Time (SystemStart (SystemStart), mkSlotLength) import Control.Monad.Class.MonadAsync (link) diff --git a/hydra-node/src/Hydra/Ledger/Cardano.hs b/hydra-node/src/Hydra/Ledger/Cardano.hs index 6f04f4a78ce..e1fd7dedb5d 100644 --- a/hydra-node/src/Hydra/Ledger/Cardano.hs +++ b/hydra-node/src/Hydra/Ledger/Cardano.hs @@ -83,7 +83,7 @@ cardanoLedger globals ledgerEnv = Left err -> Left (tx, toValidationError err) Right (Ledger.LedgerState{Ledger.lsUTxOState = us}, _validatedTx) -> - Right . fromLedgerUTxO $ Ledger.utxosUtxo us + Right . UTxO.fromShelleyUTxO shelleyBasedEra $ Ledger.utxosUtxo us where -- As we use applyTx we only expect one ledger rule to run and one tx to -- fail validation, hence using the heads of non empty lists is fine. @@ -104,7 +104,7 @@ cardanoLedger globals ledgerEnv = memPoolState = def - & Ledger.lsUTxOStateL . Ledger.utxoL .~ toLedgerUTxO utxo + & Ledger.lsUTxOStateL . Ledger.utxoL .~ UTxO.toShelleyUTxO shelleyBasedEra utxo & Ledger.lsCertStateL . Ledger.certDStateL %~ mockCertState -- NOTE: Mocked certificate state that simulates any reward accounts for any @@ -238,7 +238,7 @@ mkRangedTx (txin, TxOut owner valueIn datum refScript) (recipient, valueOut) sk -- rules. adjustUTxO :: Tx -> UTxO -> UTxO adjustUTxO tx utxo = - let txid = txId tx + let txid = Hydra.Tx.txId tx consumed = txIns' tx produced = UTxO.fromList ((\(txout, ix) -> (TxIn txid (TxIx ix), toCtxUTxOTxOut txout)) <$> zip (txOuts' tx) [0 ..]) utxo' = UTxO.fromList $ filter (\(txin, _) -> txin `notElem` consumed) $ UTxO.toList utxo diff --git a/hydra-node/test/Hydra/API/HTTPServerSpec.hs b/hydra-node/test/Hydra/API/HTTPServerSpec.hs index 12b74ac9e7e..8189a642dce 100644 --- a/hydra-node/test/Hydra/API/HTTPServerSpec.hs +++ b/hydra-node/test/Hydra/API/HTTPServerSpec.hs @@ -25,6 +25,7 @@ import Hydra.API.HTTPServer ( import Hydra.API.ServerOutput (ClientMessage (..), CommitInfo (..), DecommitInvalidReason (..), ServerOutput (..), TimedServerOutput (..), getConfirmedSnapshot, getSeenSnapshot, getSnapshotUtxo) import Hydra.API.ServerSpec (dummyChainHandle) import Hydra.Cardano.Api ( + UTxO, mkTxOutDatumInline, modifyTxOutDatum, renderTxIn, @@ -576,7 +577,7 @@ apiServerSpec = do } prop "reject deposits with less than min ADA" $ do - forAll (genUTxOAdaOnlyOfSize 1) $ \(utxo :: UTxO.UTxO) -> do + forAll (genUTxOAdaOnlyOfSize 1) $ \(utxo :: UTxO) -> do let result = rejectLowDeposits pparams utxo Nothing case result of Left DepositTooLow{providedValue, minimumValue} -> @@ -586,7 +587,7 @@ apiServerSpec = do _ -> property True prop "reject partial deposits with less ADA then in the UTxO" $ \amt -> - forAll (genUTxOAdaOnlyOfSize 1) $ \(utxo :: UTxO.UTxO) -> do + forAll (genUTxOAdaOnlyOfSize 1) $ \(utxo :: UTxO) -> do let result = checkAmount utxo (Just amt) case result of Left AmountTooLow{providedValue, totalUTxOValue} -> diff --git a/hydra-node/test/Hydra/Chain/Direct/HandlersSpec.hs b/hydra-node/test/Hydra/Chain/Direct/HandlersSpec.hs index c1574729ee3..3f104183c46 100644 --- a/hydra-node/test/Hydra/Chain/Direct/HandlersSpec.hs +++ b/hydra-node/test/Hydra/Chain/Direct/HandlersSpec.hs @@ -19,6 +19,8 @@ import Hydra.Cardano.Api ( getChainPoint, toLedgerTx, ) +import Test.Gen.Cardano.Api.Typed (genBlockHeader) +import Test.QuickCheck.Hedgehog (hedgehog) import Cardano.Ledger.Api (IsValid (..), isValidTxL) import Control.Lens ((.~)) @@ -297,7 +299,7 @@ data TestBlock = TestBlock BlockHeader [Tx] -- | Thin wrapper which generates a 'TestBlock' at some specific slot. genBlockAt :: SlotNo -> [Tx] -> Gen TestBlock genBlockAt sl txs = do - header <- adjustSlot <$> arbitrary + header <- adjustSlot <$> hedgehog genBlockHeader pure $ TestBlock header txs where adjustSlot (BlockHeader _ hash blockNo) = diff --git a/hydra-node/test/Hydra/Chain/Direct/TxSpec.hs b/hydra-node/test/Hydra/Chain/Direct/TxSpec.hs index 56e425efa2a..7a4cdb0866c 100644 --- a/hydra-node/test/Hydra/Chain/Direct/TxSpec.hs +++ b/hydra-node/test/Hydra/Chain/Direct/TxSpec.hs @@ -3,7 +3,7 @@ -- XXX: This does not have a corresponding "source" module which it tests. module Hydra.Chain.Direct.TxSpec where -import Hydra.Cardano.Api +import Hydra.Cardano.Api hiding (referenceInputsTxBodyL, reqSignerHashesTxBodyL) import Hydra.Prelude hiding (label) import Test.Hydra.Prelude diff --git a/hydra-node/test/Hydra/Chain/Direct/TxTraceSpec.hs b/hydra-node/test/Hydra/Chain/Direct/TxTraceSpec.hs index d1a98cc4b24..318974106db 100644 --- a/hydra-node/test/Hydra/Chain/Direct/TxTraceSpec.hs +++ b/hydra-node/test/Hydra/Chain/Direct/TxTraceSpec.hs @@ -21,7 +21,6 @@ module Hydra.Chain.Direct.TxTraceSpec where import Hydra.Prelude hiding (Any, State, label, show) import Test.Hydra.Prelude -import Cardano.Api.UTxO (UTxO, totalLovelace) import Cardano.Api.UTxO qualified as UTxO import Data.List (nub, (\\)) import Data.Map.Strict qualified as Map @@ -33,6 +32,7 @@ import Hydra.Cardano.Api ( SlotNo (..), TxId, TxOutDatum, + UTxO, VerificationKey, getTxBody, getTxId, @@ -818,7 +818,7 @@ newDepositTx _ utxoToDeposit = do let validBefore = SlotNo 0 deadline <- liftIO getCurrentTime let depositUTxO = realWorldModelUTxO utxoToDeposit - amount <- liftIO $ randomBetween 1_000_000 (unCoin $ totalLovelace depositUTxO) + amount <- liftIO $ randomBetween 1_000_000 (unCoin $ UTxO.totalLovelace depositUTxO) let blueprint = CommitBlueprintTx{blueprintTx = txSpendingUTxO depositUTxO, lookupUTxO = depositUTxO} pure $ Right $ diff --git a/hydra-node/test/Hydra/Chain/Direct/WalletSpec.hs b/hydra-node/test/Hydra/Chain/Direct/WalletSpec.hs index 321e687a856..e763f04f3f7 100644 --- a/hydra-node/test/Hydra/Chain/Direct/WalletSpec.hs +++ b/hydra-node/test/Hydra/Chain/Direct/WalletSpec.hs @@ -30,11 +30,10 @@ import Hydra.Cardano.Api ( VerificationKey, fromLedgerTx, fromLedgerTxOut, - fromLedgerUTxO, genTxIn, selectLovelace, + shelleyBasedEra, toLedgerTxIn, - toLedgerUTxO, txOutValue, verificationKeyHash, ) @@ -115,7 +114,7 @@ setupQuery vk = do where queryFn queryPointMVar point _addr = do putMVar queryPointMVar point - walletUTxO <- Ledger.unUTxO . toLedgerUTxO <$> generate (genOneUTxOFor vk) + walletUTxO <- Ledger.unUTxO . UTxO.toShelleyUTxO shelleyBasedEra <$> generate (genOneUTxOFor vk) tip <- generate arbitrary pure $ WalletInfoOnChain @@ -132,7 +131,7 @@ mockChainQuery :: VerificationKey PaymentKey -> ChainQuery IO mockChainQuery vk _point addr = do let Api.ShelleyAddress _ cred _ = addr fromShelleyPaymentCredential cred `shouldBe` PaymentCredentialByKey (verificationKeyHash vk) - walletUTxO <- Ledger.unUTxO . toLedgerUTxO <$> generate (genOneUTxOFor vk) + walletUTxO <- Ledger.unUTxO . UTxO.toShelleyUTxO shelleyBasedEra <$> generate (genOneUTxOFor vk) tip <- generate arbitrary pure $ WalletInfoOnChain @@ -293,7 +292,7 @@ prop_picksLargestUTxOToPayTheFees = & counterexample ("No utxo found: " <> decodeUtf8 (encodePretty combinedUTxO)) Just (_, txout) -> do let foundLovelace = selectLovelace $ txOutValue (fromLedgerTxOut txout) - mapToLovelace = fmap (selectLovelace . txOutValue) . UTxO.txOutputs . fromLedgerUTxO . Ledger.UTxO + mapToLovelace = fmap (selectLovelace . txOutValue) . UTxO.txOutputs . UTxO.fromShelleyUTxO shelleyBasedEra . Ledger.UTxO property $ all (foundLovelace >=) (mapToLovelace utxo1) && all (foundLovelace >=) (mapToLovelace utxo2) diff --git a/hydra-node/test/Hydra/Ledger/CardanoSpec.hs b/hydra-node/test/Hydra/Ledger/CardanoSpec.hs index 09fc5d95118..83e89261b27 100644 --- a/hydra-node/test/Hydra/Ledger/CardanoSpec.hs +++ b/hydra-node/test/Hydra/Ledger/CardanoSpec.hs @@ -20,6 +20,7 @@ import Hydra.Ledger (applyTransactions) import Hydra.Ledger.Cardano (cardanoLedger, genSequenceOfSimplePaymentTransactions) import Test.Aeson.GenericSpecs (roundtripAndGoldenSpecs) import Test.Cardano.Ledger.Babbage.Arbitrary () +import Test.Gen.Cardano.Api.Typed (genChainPoint) import Test.Hydra.Node.Fixture (defaultGlobals, defaultLedgerEnv, defaultPParams) import Test.Hydra.Tx.Gen (genOneUTxOFor, genOutput, genTxOut, genUTxOFor, genValue) import Test.QuickCheck ( @@ -33,6 +34,7 @@ import Test.QuickCheck ( property, (===), ) +import Test.QuickCheck.Hedgehog (hedgehog) import Test.Util (propCollisionResistant) spec :: Spec @@ -89,7 +91,7 @@ spec = describe "genChainPoint" $ prop "generates only some genesis points" $ checkCoverage $ - forAll genChainPoint $ \cp -> + forAll (hedgehog genChainPoint) $ \cp -> cover 80 (cp /= ChainPointAtGenesis) "not at genesis" $ property True shouldParseJSONAs :: forall a. (HasCallStack, FromJSON a) => LByteString -> Expectation diff --git a/hydra-node/test/Hydra/Model.hs b/hydra-node/test/Hydra/Model.hs index 707bfff4f99..02ecd992888 100644 --- a/hydra-node/test/Hydra/Model.hs +++ b/hydra-node/test/Hydra/Model.hs @@ -47,7 +47,6 @@ import Hydra.BehaviorSpec ( shortLabel, waitUntilMatch, ) -import Hydra.Cardano.Api.Prelude (fromShelleyPaymentCredential) import Hydra.Chain (maximumNumberOfParties) import Hydra.Chain.Direct.State (initialChainState) import Hydra.HeadLogic (Committed (), NodeState (headState)) diff --git a/hydra-node/test/Hydra/Model/MockChain.hs b/hydra-node/test/Hydra/Model/MockChain.hs index d47350c469b..711006937ba 100644 --- a/hydra-node/test/Hydra/Model/MockChain.hs +++ b/hydra-node/test/Hydra/Model/MockChain.hs @@ -78,9 +78,11 @@ import Hydra.Tx.Party (Party (..), deriveParty, getParty) import Hydra.Tx.ScriptRegistry (registryUTxO) import Hydra.Tx.Snapshot (ConfirmedSnapshot (..)) import Hydra.Tx.Utils (verificationKeyToOnChainId) +import Test.Gen.Cardano.Api.Typed (genBlockHeaderAt) import Test.Hydra.Tx.Fixture (defaultPParams, testNetworkId) import Test.Hydra.Tx.Gen (genScriptRegistry, genTxOutAdaOnly) import Test.QuickCheck (getPositive) +import Test.QuickCheck.Hedgehog (hedgehog) -- | Create a mocked chain which connects nodes through 'ChainSyncHandler' and -- 'Chain' interfaces. It calls connected chain sync handlers 'onRollForward' on @@ -214,7 +216,7 @@ mockChainAndNetwork tr seedKeys commits = do (MockHydraNode{node = HydraNode{oc = Chain{submitTx, draftDepositTx}}} : _) -> draftDepositTx headId defaultPParams (mkSimpleBlueprintTx utxoToDeposit) deadline Nothing Nothing >>= \case Left e -> throwIO e - Right tx -> submitTx tx $> txId tx + Right tx -> submitTx tx $> Hydra.Tx.txId tx -- REVIEW: Is this still needed now as we have TxTraceSpec? closeWithInitialSnapshot :: TVar m [MockHydraNode m] -> (Party, UTxO) -> m () @@ -313,7 +315,7 @@ mockChainAndNetwork tr seedKeys commits = do modifyTVar chain $ \(slotNum, position, blocks, utxo) -> do -- NOTE: Assumes 1 slot = 1 second let newSlot = slotNum + ChainSlot (truncate blockTime) - header = genBlockHeaderAt (fromChainSlot newSlot) `generateWith` 42 + header = hedgehog (genBlockHeaderAt (fromChainSlot newSlot)) `generateWith` 42 -- NOTE: Transactions that do not apply to the current state (eg. -- UTxO) are silently dropped which emulates the chain behaviour that -- only the client is potentially witnessing the failure, and no diff --git a/hydra-node/test/Hydra/Model/MockChainSpec.hs b/hydra-node/test/Hydra/Model/MockChainSpec.hs index 8c1f7dab8cf..c1f55f5fc99 100644 --- a/hydra-node/test/Hydra/Model/MockChainSpec.hs +++ b/hydra-node/test/Hydra/Model/MockChainSpec.hs @@ -2,8 +2,8 @@ module Hydra.Model.MockChainSpec where import Cardano.Api.UTxO qualified as UTxO import Data.Text (unpack) -import Hydra.Cardano.Api (Tx, TxIn (TxIn), UTxO, prettyPrintJSON, renderUTxO) -import Hydra.Cardano.Api.Pretty (renderTx) +import Hydra.Cardano.Api (Tx, TxIn (TxIn), UTxO, prettyPrintJSON) +import Hydra.Cardano.Api.Pretty (renderTx, renderUTxO) import Hydra.Chain.ChainState (ChainSlot (ChainSlot)) import Hydra.Ledger (Ledger (applyTransactions)) import Hydra.Ledger.Cardano (genSequenceOfSimplePaymentTransactions) @@ -38,7 +38,7 @@ isOutputOfLastTransaction txs utxo = txId tx === txid (Just _, _) -> property False - & counterexample ("Resulting Utxo: " <> renderUTxO utxo) + & counterexample ("Resulting Utxo: " <> unpack (foldMap renderUTxO (UTxO.toList utxo))) & counterexample ("Txs: " <> show (txId <$> txs)) (Nothing, _) -> property True diff --git a/hydra-node/test/Hydra/OptionsSpec.hs b/hydra-node/test/Hydra/OptionsSpec.hs index 92707892b12..8b06c2f6b24 100644 --- a/hydra-node/test/Hydra/OptionsSpec.hs +++ b/hydra-node/test/Hydra/OptionsSpec.hs @@ -12,6 +12,7 @@ import Hydra.Cardano.Api ( NetworkId (..), NetworkMagic (..), TxId, + deserialiseFromRawBytesThrow, serialiseToRawBytesHexText, ) import Hydra.Chain (maximumNumberOfParties) @@ -316,6 +317,7 @@ spec = parallel $ } it "parses --start-chain-from as a pair of slot number and block header hash" $ do + x <- deserialiseFromRawBytesThrow "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" ["--start-chain-from", "1000.0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"] `shouldParse` Run defaultRunOptions @@ -324,8 +326,7 @@ spec = parallel $ defaultCardanoChainConfig { startChainFrom = Just $ - ChainPoint 1000 $ - fromString "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" + ChainPoint 1000 x } } diff --git a/hydra-tui/hydra-tui.cabal b/hydra-tui/hydra-tui.cabal index c482495ead8..bb1e2da915d 100644 --- a/hydra-tui/hydra-tui.cabal +++ b/hydra-tui/hydra-tui.cabal @@ -58,6 +58,7 @@ library , async , base , brick >=1.10 + , cardano-api , containers , hydra-cardano-api , hydra-node diff --git a/hydra-tui/src/Hydra/Client.hs b/hydra-tui/src/Hydra/Client.hs index a75535b1d91..17d23d746e5 100644 --- a/hydra-tui/src/Hydra/Client.hs +++ b/hydra-tui/src/Hydra/Client.hs @@ -4,7 +4,6 @@ module Hydra.Client where import Hydra.Prelude -import Cardano.Api.UTxO qualified as UTxO import Control.Concurrent.Async (link) import Control.Concurrent.Class.MonadSTM (readTBQueue, writeTBQueue) import Control.Exception (Handler (Handler), IOException, catches) @@ -12,7 +11,7 @@ import Data.Aeson (eitherDecodeStrict, encode) import Hydra.API.ClientInput (ClientInput) import Hydra.API.HTTPServer (DraftCommitTxRequest (..), DraftCommitTxResponse (..)) import Hydra.API.ServerOutput (ClientMessage, Greetings, InvalidInput, TimedServerOutput) -import Hydra.Cardano.Api (TxId) +import Hydra.Cardano.Api (TxId, UTxO) import Hydra.Cardano.Api.Prelude ( PaymentKey, SigningKey, @@ -58,7 +57,7 @@ data Client tx m = Client { sendInput :: ClientInput tx -> m () -- ^ Send some input to the server. , sk :: SigningKey PaymentKey - , externalCommit :: UTxO.UTxO -> m () + , externalCommit :: UTxO -> m () , recoverCommit :: TxId -> m () } diff --git a/hydra-tui/src/Hydra/TUI/Drawing.hs b/hydra-tui/src/Hydra/TUI/Drawing.hs index eb55ef9fe1b..c8cbd252e26 100644 --- a/hydra-tui/src/Hydra/TUI/Drawing.hs +++ b/hydra-tui/src/Hydra/TUI/Drawing.hs @@ -21,6 +21,7 @@ import Data.Text (chunksOf) import Data.Time (defaultTimeLocale, formatTime) import Data.Time.Format (FormatTime) import Data.Version (Version, showVersion) +import Hydra.Cardano.Api.Pretty (renderUTxO) import Hydra.Chain.CardanoClient (CardanoClient (..)) import Hydra.Chain.Direct.State () import Hydra.Client (Client (..)) @@ -370,7 +371,7 @@ drawUTxO f utxo = [ padTop (Pad 1) $ vBox [ f addr - , padLeft (Pad 2) $ vBox (str . toString . UTxO.render <$> u) + , padLeft (Pad 2) $ vBox (str . toString . renderUTxO <$> u) ] | (addr, u) <- Map.toList byAddress ] diff --git a/hydra-tui/src/Hydra/TUI/Forms.hs b/hydra-tui/src/Hydra/TUI/Forms.hs index bc0170a0879..bbb39a2a689 100644 --- a/hydra-tui/src/Hydra/TUI/Forms.hs +++ b/hydra-tui/src/Hydra/TUI/Forms.hs @@ -8,6 +8,7 @@ module Hydra.TUI.Forms where import Hydra.Prelude hiding (Down, State) import Hydra.Cardano.Api +import Hydra.Cardano.Api.Pretty (renderUTxO) import Brick (BrickEvent (..), vBox, withDefAttr) import Brick.Forms ( @@ -40,7 +41,7 @@ utxoCheckboxField u = let items = Map.map (,False) u in newForm [ checkboxGroupField '[' 'X' ']' id $ - [ ((k, v, b), show k, UTxO.render (k, v)) + [ ((k, v, b), show k, renderUTxO (k, v)) | (k, (v, b)) <- Map.toList items ] ] @@ -57,7 +58,7 @@ utxoRadioField u = newForm [ radioField id - [ (i, show i, UTxO.render i) + [ (i, show i, renderUTxO i) | i <- Map.toList u ] ] @@ -74,7 +75,7 @@ depositIdRadioField txIdUTxO = newForm [ radioField id - [ ((txid, i, o), show txid, UTxO.render (i, o)) + [ ((txid, i, o), show txid, renderUTxO (i, o)) | (txid, i, o) <- flattened txIdUTxO ] ] @@ -83,7 +84,7 @@ depositIdRadioField txIdUTxO = flattened :: [(TxId, UTxO)] -> [(TxId, TxIn, TxOut CtxUTxO)] flattened = concatMap - (\(txId, u) -> (\(i, o) -> (txId, i, o)) <$> Map.toList (UTxO.toMap u)) + (\(a, u) -> (\(i, o) -> (a, i, o)) <$> Map.toList (UTxO.toMap u)) confirmRadioField :: forall s e n. diff --git a/hydra-tui/src/Hydra/TUI/Handlers.hs b/hydra-tui/src/Hydra/TUI/Handlers.hs index c3d63cdc8aa..f0ee4097098 100644 --- a/hydra-tui/src/Hydra/TUI/Handlers.hs +++ b/hydra-tui/src/Hydra/TUI/Handlers.hs @@ -24,6 +24,7 @@ import Hydra.API.ServerOutput (NetworkInfo (..), TimedServerOutput (..)) import Hydra.API.ServerOutput qualified as API import Hydra.Cardano.Api hiding (Active) import Hydra.Cardano.Api.Prelude () +import Hydra.Cardano.Api.Pretty (renderUTxO) import Hydra.Chain (PostTxError (InternalWalletError, NotEnoughFuel), reason) import Hydra.Chain.CardanoClient (CardanoClient (..)) import Hydra.Chain.Direct.State () @@ -234,13 +235,13 @@ handleHydraEventsInfo = \case Update (ApiTimedServerOutput TimedServerOutput{time, output = API.TxValid{transactionId}}) -> report Success time ("Transaction " <> show transactionId <> " submitted successfully") Update (ApiTimedServerOutput TimedServerOutput{time, output = API.TxInvalid{transaction, validationError}}) -> - warn time ("Transaction " <> show (txId transaction) <> " is not applicable: " <> show validationError) + warn time ("Transaction " <> show (Hydra.Tx.txId transaction) <> " is not applicable: " <> show validationError) Update (ApiTimedServerOutput TimedServerOutput{time, output = API.DecommitApproved{decommitTxId, utxoToDecommit}}) -> report Success time $ "Decommit approved and submitted to Cardano " <> show decommitTxId <> " " - <> foldMap UTxO.render (UTxO.toList utxoToDecommit) + <> foldMap renderUTxO (UTxO.toList utxoToDecommit) Update (ApiTimedServerOutput TimedServerOutput{time, output = API.DecommitFinalized{distributedUTxO}}) -> report Success time $ "Decommit finalized " @@ -248,7 +249,7 @@ handleHydraEventsInfo = \case Update (ApiTimedServerOutput TimedServerOutput{time, output = API.DecommitInvalid{decommitTx, decommitInvalidReason}}) -> warn time $ "Decommit Transaction with id " - <> show (txId decommitTx) + <> show (Hydra.Tx.txId decommitTx) <> " is not applicable: " <> show decommitInvalidReason Update (ApiTimedServerOutput TimedServerOutput{time, output = API.CommitRecorded{utxoToCommit, pendingDeposit}}) -> @@ -257,17 +258,17 @@ handleHydraEventsInfo = \case <> " deposit tx id " <> show pendingDeposit <> "and pending for approval " - <> foldMap UTxO.render (UTxO.toList utxoToCommit) + <> foldMap renderUTxO (UTxO.toList utxoToCommit) Update (ApiTimedServerOutput TimedServerOutput{time, output = API.CommitApproved{utxoToCommit}}) -> report Success time $ "Commit approved and submitted to Cardano " - <> foldMap UTxO.render (UTxO.toList utxoToCommit) + <> foldMap renderUTxO (UTxO.toList utxoToCommit) Update (ApiTimedServerOutput TimedServerOutput{time, output = API.CommitRecovered{recoveredTxId, recoveredUTxO}}) -> report Success time $ "Commit recovered " <> show recoveredTxId <> " " - <> foldMap UTxO.render (UTxO.toList recoveredUTxO) + <> foldMap renderUTxO (UTxO.toList recoveredUTxO) Update (ApiTimedServerOutput TimedServerOutput{time, output = API.CommitFinalized{depositTxId}}) -> report Success time $ "Commit finalized " diff --git a/hydra-tx/exe/Main.hs b/hydra-tx/exe/Main.hs index cc06b5575ec..cf3ddcbebe5 100644 --- a/hydra-tx/exe/Main.hs +++ b/hydra-tx/exe/Main.hs @@ -2,10 +2,9 @@ module Main where import Hydra.Prelude -import Cardano.Api.UTxO (UTxO) import Cardano.Api.UTxO qualified as UTxO import Data.Aeson (eitherDecodeFileStrict) -import Hydra.Cardano.Api (TxIx (..), textEnvelopeToJSON, toShelleyNetwork, pattern TxIn) +import Hydra.Cardano.Api (TxIx (..), UTxO, textEnvelopeToJSON, toShelleyNetwork, pattern TxIn) import Hydra.Tx.BlueprintTx (mkSimpleBlueprintTx) import Hydra.Tx.Deposit (depositTx, observeDepositTxOut) import Hydra.Tx.Recover (recoverTx) diff --git a/hydra-tx/hydra-tx.cabal b/hydra-tx/hydra-tx.cabal index ca07ddfb5ce..3298d05089f 100644 --- a/hydra-tx/hydra-tx.cabal +++ b/hydra-tx/hydra-tx.cabal @@ -77,6 +77,7 @@ library , base , base16-bytestring , bytestring + , cardano-api , cardano-crypto-class , cardano-ledger-alonzo , cardano-ledger-api @@ -122,6 +123,7 @@ library testlib build-depends: , base , bytestring + , cardano-api , cardano-crypto-class , cardano-ledger-alonzo , cardano-ledger-api @@ -182,6 +184,7 @@ test-suite tests , aeson , base , base16-bytestring + , cardano-api , cardano-binary , cardano-crypto-class , cardano-ledger-alonzo @@ -219,6 +222,7 @@ executable hydra-tx , attoparsec , base , bytestring + , cardano-api , hydra-cardano-api , hydra-prelude , hydra-tx diff --git a/hydra-tx/src/Hydra/Ledger/Cardano/Evaluate.hs b/hydra-tx/src/Hydra/Ledger/Cardano/Evaluate.hs index 2fb670a5e28..59d55b9a42e 100644 --- a/hydra-tx/src/Hydra/Ledger/Cardano/Evaluate.hs +++ b/hydra-tx/src/Hydra/Ledger/Cardano/Evaluate.hs @@ -16,7 +16,6 @@ module Hydra.Ledger.Cardano.Evaluate where import Hydra.Prelude hiding (label) -import Cardano.Api.UTxO qualified as UTxO import Cardano.Ledger.Alonzo.Scripts (CostModel, Prices (..), mkCostModel, mkCostModels, txscriptfee) import Cardano.Ledger.Api (CoinPerByte (..), ppCoinsPerUTxOByteL, ppCostModelsL, ppMaxBlockExUnitsL, ppMaxTxExUnitsL, ppMaxValSizeL, ppMinFeeAL, ppMinFeeBL, ppPricesL, ppProtocolVersionL) import Cardano.Ledger.BaseTypes (BoundedRational (boundRational), ProtVer (..), natVersion) @@ -112,7 +111,7 @@ evaluateTx' maxUnits tx utxo = do systemStart (LedgerEpochInfo epochInfo) pparams' - (UTxO.toApi utxo) + utxo (getTxBody tx) -- | Check the budget used by provided 'EvaluationReport' does not exceed given diff --git a/hydra-tx/src/Hydra/Tx/Close.hs b/hydra-tx/src/Hydra/Tx/Close.hs index e299fd7f8e1..5b6819b0302 100644 --- a/hydra-tx/src/Hydra/Tx/Close.hs +++ b/hydra-tx/src/Hydra/Tx/Close.hs @@ -2,7 +2,43 @@ module Hydra.Tx.Close where -import Hydra.Cardano.Api +import Hydra.Cardano.Api ( + BuildTxWith (..), + CtxUTxO, + PaymentKey, + ScriptDatum (..), + SlotNo, + Tx, + TxIn, + TxOut, + UTxO, + VerificationKey, + addTxExtraKeyWits, + addTxIns, + addTxInsReference, + addTxOuts, + defaultTxBodyContent, + findRedeemerSpending, + findTxOutByScript, + fromCtxUTxOTxOut, + fromScriptData, + mkScriptReference, + mkTxOutDatumInline, + modifyTxOutDatum, + resolveInputsUTxO, + scriptWitnessInCtx, + setTxMetadata, + setTxValidityLowerBound, + setTxValidityUpperBound, + toScriptData, + txOutScriptData, + utxoFromTx, + verificationKeyHash, + pattern ScriptWitness, + pattern TxMetadataInEra, + pattern TxValidityLowerBound, + pattern TxValidityUpperBound, + ) import Hydra.Prelude import Hydra.Contract.Head qualified as Head diff --git a/hydra-tx/src/Hydra/Tx/Commit.hs b/hydra-tx/src/Hydra/Tx/Commit.hs index c1f74cd837b..84b17f0dd11 100644 --- a/hydra-tx/src/Hydra/Tx/Commit.hs +++ b/hydra-tx/src/Hydra/Tx/Commit.hs @@ -1,6 +1,37 @@ module Hydra.Tx.Commit where -import Hydra.Cardano.Api +import Hydra.Cardano.Api ( + CtxUTxO, + Hash, + LedgerEra, + NetworkId (..), + PaymentKey, + Tx, + TxIn, + TxOut, + UTxO, + findTxOutByAddress, + fromLedgerTx, + fromPlutusCurrencySymbol, + fromScriptData, + mkScriptAddress, + mkTxOutDatumInline, + resolveInputsUTxO, + toLedgerData, + toLedgerKeyHash, + toLedgerTx, + toLedgerTxIn, + toLedgerTxOut, + toPlutusTxOutRef, + toScriptData, + toShelleyNetwork, + txIns', + txOutAddress, + txOutScriptData, + txOutValue, + pattern ReferenceScriptNone, + pattern TxOut, + ) import Hydra.Prelude import Cardano.Api.UTxO qualified as UTxO diff --git a/hydra-tx/src/Hydra/Tx/Crypto.hs b/hydra-tx/src/Hydra/Tx/Crypto.hs index 22bbf27731c..be182e3efec 100644 --- a/hydra-tx/src/Hydra/Tx/Crypto.hs +++ b/hydra-tx/src/Hydra/Tx/Crypto.hs @@ -100,7 +100,7 @@ instance Key HydraKey where newtype VerificationKey HydraKey = HydraVerificationKey (VerKeyDSIGN Ed25519DSIGN) deriving stock (Eq, Ord) - deriving (Show, IsString) via UsingRawBytesHex (VerificationKey HydraKey) + deriving (Show) via UsingRawBytesHex (VerificationKey HydraKey) deriving newtype (ToCBOR, FromCBOR) deriving anyclass (SerialiseAsCBOR) @@ -109,7 +109,7 @@ instance Key HydraKey where newtype SigningKey HydraKey = HydraSigningKey (SignKeyDSIGN Ed25519DSIGN) deriving stock (Eq, Ord) - deriving (Show, IsString) via UsingRawBytesHex (SigningKey HydraKey) + deriving (Show) via UsingRawBytesHex (SigningKey HydraKey) deriving newtype (ToCBOR, FromCBOR) deriving anyclass (SerialiseAsCBOR) diff --git a/hydra-tx/src/Hydra/Tx/Deposit.hs b/hydra-tx/src/Hydra/Tx/Deposit.hs index c027b596d98..d1bc5e697d9 100644 --- a/hydra-tx/src/Hydra/Tx/Deposit.hs +++ b/hydra-tx/src/Hydra/Tx/Deposit.hs @@ -1,6 +1,59 @@ module Hydra.Tx.Deposit where -import Hydra.Cardano.Api +import Hydra.Cardano.Api ( + AddressInEra, + AssetName (..), + BuildTxWith (..), + Coin, + CtxUTxO, + Network, + NetworkId, + PolicyAssets (..), + PolicyId (..), + Quantity (..), + ShelleyBasedEra (..), + SlotNo, + Tx, + TxId, + TxIn (..), + TxOut, + UTxO, + Value, + containsValue, + fromLedgerTx, + fromLedgerValue, + fromScriptData, + getTxBody, + getTxBodyContent, + lovelaceToValue, + mkAdaValue, + mkScriptAddress, + mkTxOutDatumInline, + policyAssetsToValue, + selectLovelace, + toCtxUTxOTxOut, + toLedgerTx, + toLedgerTxIn, + toLedgerTxOut, + toShelleyNetwork, + txIns', + txOutAddress, + txOutDatum, + txOutValue, + txOuts', + txValidityUpperBound, + upperBound, + valueToPolicyAssets, + pattern KeyWitness, + pattern KeyWitnessForSpending, + pattern ReferenceScriptNone, + pattern TxOut, + pattern TxOutDatumInline, + pattern TxOutDatumNone, + pattern TxValidityNoUpperBound, + pattern TxValidityUpperBound, + pattern UTxO, + ) import Hydra.Prelude hiding (toList) import Cardano.Api.UTxO qualified as UTxO @@ -213,7 +266,7 @@ depositAddress networkId = mkScriptAddress networkId depositValidatorScript -- -- If no tokens are specified, it returns two empty maps. Otherwise, it returns the partitioned maps, ensuring -- that if there are no invalid tokens, the second map is empty. -splitTokens :: UTxO.UTxO -> Map PolicyId PolicyAssets -> (Map PolicyId PolicyAssets, Map PolicyId PolicyAssets) +splitTokens :: UTxO -> Map PolicyId PolicyAssets -> (Map PolicyId PolicyAssets, Map PolicyId PolicyAssets) splitTokens userUTxO specifiedTokens | Map.null specifiedTokens = (mempty, mempty) -- Trivial case: no tokens specified | otherwise = diff --git a/hydra-tx/src/Hydra/Tx/IsTx.hs b/hydra-tx/src/Hydra/Tx/IsTx.hs index d85c6f775de..c736b76137d 100644 --- a/hydra-tx/src/Hydra/Tx/IsTx.hs +++ b/hydra-tx/src/Hydra/Tx/IsTx.hs @@ -14,7 +14,7 @@ import Cardano.Ledger.Binary (decCBOR, decodeFullAnnotator) import Cardano.Ledger.Shelley.UTxO qualified as Ledger import Codec.CBOR.Decoding qualified as CBOR import Codec.CBOR.Encoding qualified as CBOR -import Data.Aeson (FromJSONKey, ToJSONKey, (.:), (.:?)) +import Data.Aeson ((.:), (.:?)) import Data.Aeson qualified as Aeson import Data.Aeson.KeyMap qualified as KeyMap import Data.Aeson.Types (withObject) @@ -131,7 +131,7 @@ instance FromJSON Tx where -- NOTE: Check txId equivalence only if present. (o .:? "txId") >>= \case Just txid' - | txid' /= txId tx -> fail "txId not matching" + | txid' /= Hydra.Tx.IsTx.txId tx -> fail "txId not matching" _ -> pure tx -- XXX: Double CBOR encoding? @@ -148,11 +148,11 @@ instance FromCBOR Tx where (pure . fromLedgerTx) instance ToCBOR UTxO where - toCBOR = toCBOR . toLedgerUTxO + toCBOR = toCBOR . UTxO.toShelleyUTxO shelleyBasedEra encodedSizeExpr sz _ = encodedSizeExpr sz (Proxy @(Ledger.UTxO LedgerEra)) instance FromCBOR UTxO where - fromCBOR = fromLedgerUTxO <$> fromCBOR + fromCBOR = UTxO.fromShelleyUTxO shelleyBasedEra <$> fromCBOR label _ = label (Proxy @(Ledger.UTxO LedgerEra)) instance IsTx Tx where diff --git a/hydra-tx/src/Hydra/Tx/ScriptRegistry.hs b/hydra-tx/src/Hydra/Tx/ScriptRegistry.hs index d698f7d360c..4063f7baeac 100644 --- a/hydra-tx/src/Hydra/Tx/ScriptRegistry.hs +++ b/hydra-tx/src/Hydra/Tx/ScriptRegistry.hs @@ -4,7 +4,6 @@ module Hydra.Tx.ScriptRegistry where import Hydra.Prelude -import Cardano.Api.UTxO (UTxO) import Cardano.Api.UTxO qualified as UTxO import Data.Map qualified as Map import Hydra.Cardano.Api ( @@ -12,6 +11,7 @@ import Hydra.Cardano.Api ( ScriptHash, TxIn (..), TxOut, + UTxO, hashScriptInAnyLang, txOutReferenceScript, pattern ReferenceScript, diff --git a/hydra-tx/src/Hydra/Tx/Utils.hs b/hydra-tx/src/Hydra/Tx/Utils.hs index e799dbb9798..5578f63a753 100644 --- a/hydra-tx/src/Hydra/Tx/Utils.hs +++ b/hydra-tx/src/Hydra/Tx/Utils.hs @@ -21,7 +21,7 @@ import Ouroboros.Consensus.Shelley.Eras qualified as Ledger import PlutusLedgerApi.V3 (fromBuiltin, getPubKeyHash) hydraHeadV1AssetName :: AssetName -hydraHeadV1AssetName = AssetName (fromBuiltin hydraHeadV1) +hydraHeadV1AssetName = UnsafeAssetName (fromBuiltin hydraHeadV1) -- | The metadata label used for identifying Hydra protocol transactions. As -- suggested by a friendly large language model: The number most commonly @@ -39,10 +39,10 @@ mkHydraHeadV1TxName name = TxMetadata $ Map.fromList [(hydraMetadataLabel, TxMetaText $ "HydraV1/" <> name)] assetNameToOnChainId :: AssetName -> OnChainId -assetNameToOnChainId (AssetName bs) = UnsafeOnChainId bs +assetNameToOnChainId (UnsafeAssetName bs) = UnsafeOnChainId bs onChainIdToAssetName :: OnChainId -> AssetName -onChainIdToAssetName = AssetName . serialiseToRawBytes +onChainIdToAssetName = UnsafeAssetName . serialiseToRawBytes -- | Find first occurrence including a transformation. findFirst :: Foldable t => (a -> Maybe b) -> t a -> Maybe b diff --git a/hydra-tx/test/Hydra/Tx/Contract/Close/CloseInitial.hs b/hydra-tx/test/Hydra/Tx/Contract/Close/CloseInitial.hs index e0b527b90e6..f78cd9f1a65 100644 --- a/hydra-tx/test/Hydra/Tx/Contract/Close/CloseInitial.hs +++ b/hydra-tx/test/Hydra/Tx/Contract/Close/CloseInitial.hs @@ -6,7 +6,7 @@ module Hydra.Tx.Contract.Close.CloseInitial where import Hydra.Cardano.Api import Hydra.Prelude hiding (label) -import Cardano.Api.UTxO as UTxO +import Cardano.Api.UTxO qualified as UTxO import Data.Maybe (fromJust) import Hydra.Contract.Error (ToErrorCode (..)) import Hydra.Contract.HeadError (HeadError (..)) @@ -77,7 +77,7 @@ healthyCloseInitialTx = initialDatum :: TxOutDatum CtxUTxO initialDatum = mkTxOutDatumInline healthyInitialOpenDatum - lookupUTxO :: UTxO' (TxOut CtxUTxO) + lookupUTxO :: UTxO lookupUTxO = UTxO.singleton healthyOpenHeadTxIn (healthyOpenHeadTxOut initialDatum) <> registryUTxO scriptRegistry diff --git a/hydra-tx/test/Hydra/Tx/Contract/Close/CloseUsed.hs b/hydra-tx/test/Hydra/Tx/Contract/Close/CloseUsed.hs index 77a3c31d278..48290079688 100644 --- a/hydra-tx/test/Hydra/Tx/Contract/Close/CloseUsed.hs +++ b/hydra-tx/test/Hydra/Tx/Contract/Close/CloseUsed.hs @@ -6,7 +6,7 @@ module Hydra.Tx.Contract.Close.CloseUsed where import Hydra.Cardano.Api import Hydra.Prelude hiding (label) -import Cardano.Api.UTxO as UTxO +import Cardano.Api.UTxO qualified as UTxO import Data.Maybe (fromJust) import Hydra.Contract.Error (toErrorCode) import Hydra.Contract.HeadError (HeadError (..)) @@ -134,7 +134,7 @@ healthyCloseOutdatedTx = fromMaybe NoThing $ setIncrementalActionMaybe (utxoToCommit $ getSnapshot closeUsedSnapshot) (utxoToDecommit $ getSnapshot closeUsedSnapshot) - lookupUTxO :: UTxO' (TxOut CtxUTxO) + lookupUTxO :: UTxO lookupUTxO = UTxO.singleton healthyOpenHeadTxIn (healthyOpenHeadTxOut datum) <> registryUTxO scriptRegistry diff --git a/hydra-tx/test/Hydra/Tx/Contract/Commit.hs b/hydra-tx/test/Hydra/Tx/Contract/Commit.hs index ac20c4b28fe..d74a704a07c 100644 --- a/hydra-tx/test/Hydra/Tx/Contract/Commit.hs +++ b/hydra-tx/test/Hydra/Tx/Contract/Commit.hs @@ -193,6 +193,6 @@ genMintedOrBurnedValue = do [ headPolicyId <$> arbitrary , pure Fixtures.testPolicyId ] - tokenName <- oneof [arbitrary, pure (AssetName $ fromBuiltin hydraHeadV1)] + tokenName <- oneof [arbitrary, pure (UnsafeAssetName $ fromBuiltin hydraHeadV1)] quantity <- arbitrary `suchThat` (/= 0) pure $ fromList [(AssetId policyId tokenName, Quantity quantity)] diff --git a/hydra-tx/test/Hydra/Tx/Contract/Contest/Healthy.hs b/hydra-tx/test/Hydra/Tx/Contract/Contest/Healthy.hs index 7835dbd0425..ecc49fe15e8 100644 --- a/hydra-tx/test/Hydra/Tx/Contract/Contest/Healthy.hs +++ b/hydra-tx/test/Hydra/Tx/Contract/Contest/Healthy.hs @@ -5,7 +5,7 @@ module Hydra.Tx.Contract.Contest.Healthy where import Hydra.Cardano.Api import Hydra.Prelude hiding (label) -import Cardano.Api.UTxO as UTxO +import Cardano.Api.UTxO qualified as UTxO import Hydra.Contract.HeadState qualified as Head import Hydra.Data.ContestationPeriod qualified as OnChain import Hydra.Data.Party qualified as OnChain diff --git a/hydra-tx/test/Hydra/Tx/Contract/FanOut.hs b/hydra-tx/test/Hydra/Tx/Contract/FanOut.hs index 88366be23ad..cd4a27c2e86 100644 --- a/hydra-tx/test/Hydra/Tx/Contract/FanOut.hs +++ b/hydra-tx/test/Hydra/Tx/Contract/FanOut.hs @@ -62,7 +62,7 @@ healthyFanoutTx = fromList $ map ( \party -> - (AssetId testPolicyId (AssetName . serialiseToRawBytes . verificationKeyHash . vkey $ party), 1) + (AssetId testPolicyId (UnsafeAssetName . serialiseToRawBytes . verificationKeyHash . vkey $ party), 1) ) healthyParties diff --git a/hydra-tx/test/Hydra/Tx/IsTxSpec.hs b/hydra-tx/test/Hydra/Tx/IsTxSpec.hs index e9af25f475e..295649210ee 100644 --- a/hydra-tx/test/Hydra/Tx/IsTxSpec.hs +++ b/hydra-tx/test/Hydra/Tx/IsTxSpec.hs @@ -6,7 +6,6 @@ import Test.Hydra.Prelude -- NOTE: Arbitrary UTxO and Tx instances import Test.Hydra.Tx.Gen () -import Cardano.Api.UTxO (fromApi, toApi) import Cardano.Binary (decodeFull', serialize') import Cardano.Binary qualified as CB import Cardano.Ledger.Api (bodyTxL, certsTxBodyL, inputsTxBodyL, updateTxBodyL) @@ -14,7 +13,7 @@ import Cardano.Ledger.Api qualified as Ledger import Control.Lens ((.~), (^.)) import Data.Aeson qualified as Aeson import Data.ByteString.Base16 qualified as Base16 -import Hydra.Cardano.Api (Tx, UTxO, fromLedgerTx, getTxId, toLedgerTx, pattern Tx) +import Hydra.Cardano.Api (Tx, fromLedgerTx, getTxId, toLedgerTx, pattern Tx) import Hydra.Tx.IsTx (txId) import Test.Aeson.GenericSpecs (roundtripAndGoldenSpecs) import Test.QuickCheck (Property, counterexample, forAll, property, (.&&.), (===)) @@ -22,10 +21,6 @@ import Test.QuickCheck (Property, counterexample, forAll, property, (.&&.), (=== spec :: Spec spec = parallel $ do - describe "UTxO" $ do - roundtripAndGoldenSpecs (Proxy @UTxO) - prop "Roundtrip to and from Api" roundtripFromAndToApi - describe "Tx" $ do roundtripAndGoldenSpecs (Proxy @(ReasonablySized Tx)) prop "Same TxId before/after JSON encoding" roundtripTxId @@ -65,10 +60,6 @@ genConwayCompatibleBabbageTx = do & bodyTxL . certsTxBodyL .~ mempty & bodyTxL . updateTxBodyL .~ empty -roundtripFromAndToApi :: UTxO -> Property -roundtripFromAndToApi utxo = - fromApi (toApi utxo) === utxo - roundtripTxId :: Tx -> Property roundtripTxId tx@(Tx body _) = case Aeson.decode (Aeson.encode tx) of diff --git a/hydra-tx/testlib/Test/Hydra/Tx/Gen.hs b/hydra-tx/testlib/Test/Hydra/Tx/Gen.hs index b00936a0caf..3437b45271d 100644 --- a/hydra-tx/testlib/Test/Hydra/Tx/Gen.hs +++ b/hydra-tx/testlib/Test/Hydra/Tx/Gen.hs @@ -232,7 +232,7 @@ genUTxOWithSimplifiedAddresses = -- * Others instance Arbitrary AssetName where - arbitrary = AssetName . BS.take 32 <$> arbitrary + arbitrary = UnsafeAssetName . BS.take 32 <$> arbitrary instance Arbitrary PolicyAssets where arbitrary = PolicyAssets <$> arbitrary diff --git a/hydra-tx/testlib/Test/Hydra/Tx/Mutation.hs b/hydra-tx/testlib/Test/Hydra/Tx/Mutation.hs index 7fdb25064a6..4676450dea9 100644 --- a/hydra-tx/testlib/Test/Hydra/Tx/Mutation.hs +++ b/hydra-tx/testlib/Test/Hydra/Tx/Mutation.hs @@ -128,7 +128,73 @@ -- In the case of a failure we get a detailed report on the context of the failure. module Test.Hydra.Tx.Mutation where -import Hydra.Cardano.Api +import Hydra.Cardano.Api ( + AssetId (..), + CtxTx, + CtxUTxO, + DebugPlutusFailure (..), + FromScriptData, + Hash, + HashableScriptData, + LedgerEra, + PaymentKey, + PlutusScript, + PolicyId, + Quantity, + ScriptExecutionError (..), + ToScriptData, + Tx, + TxBodyScriptData, + TxIn, + TxOut, + TxOutDatum, + TxValidityLowerBound, + TxValidityUpperBound, + UTxO, + Value, + VerificationKey, + fromLedgerData, + fromLedgerMultiAsset, + fromLedgerTxIn, + fromLedgerTxOut, + fromLedgerValidityInterval, + fromScriptData, + getTxBodyContent, + mkScriptAddress, + mkTxOutDatumInline, + modifyTxOutValue, + scriptPolicyId, + toCtxUTxOTxOut, + toLedgerData, + toLedgerKeyHash, + toLedgerPolicyID, + toLedgerScript, + toLedgerTxIn, + toLedgerTxOut, + toLedgerValidityInterval, + toLedgerValue, + txBody, + txMintValue, + txMintValueToValue, + txOutAddress, + txOutDatum, + txOutValue, + pattern ByronAddress, + pattern ByronAddressInEra, + pattern PlutusScript, + pattern ShelleyAddress, + pattern ShelleyAddressInEra, + pattern ShelleyTxBody, + pattern Tx, + pattern TxBodyNoScriptData, + pattern TxBodyScriptData, + pattern TxOut, + pattern TxOutDatumHash, + pattern TxOutDatumInline, + pattern TxOutDatumNone, + pattern TxOutSupplementalDatum, + pattern UTxO, + ) import Cardano.Api.UTxO qualified as UTxO import Cardano.Ledger.Alonzo.Scripts qualified as Ledger diff --git a/hydraw/hydraw.cabal b/hydraw/hydraw.cabal index 43f134071d8..3508e2bfefb 100644 --- a/hydraw/hydraw.cabal +++ b/hydraw/hydraw.cabal @@ -32,6 +32,7 @@ library build-depends: , aeson , base + , cardano-api , http-conduit , hydra-cardano-api , hydra-node