diff --git a/hydra-node/bench/tx-cost/TxCost.hs b/hydra-node/bench/tx-cost/TxCost.hs index b1afbb8e432..b40aacf60af 100644 --- a/hydra-node/bench/tx-cost/TxCost.hs +++ b/hydra-node/bench/tx-cost/TxCost.hs @@ -59,10 +59,10 @@ import Hydra.Ledger.Cardano.Evaluate ( ) import Hydra.Ledger.Cardano.Time (slotNoFromUTCTime) import Hydra.Plutus.Orphans () +import Hydra.Tx.Snapshot (genConfirmedSnapshot) import PlutusLedgerApi.V2 (toBuiltinData) import PlutusTx.Builtins (lengthOfByteString, serialiseData) import Test.Hydra.Tx.Gen (genOutput, genUTxOAdaOnlyOfSize) -import Test.Hydra.Tx.Snapshot (genConfirmedSnapshot) import Test.QuickCheck (generate) computeInitCost :: IO [(NumParties, TxSize, MemUnit, CpuUnit, Coin)] diff --git a/hydra-node/src/Hydra/Chain.hs b/hydra-node/src/Hydra/Chain.hs index 34b79492509..e96e67be7a8 100644 --- a/hydra-node/src/Hydra/Chain.hs +++ b/hydra-node/src/Hydra/Chain.hs @@ -34,7 +34,6 @@ import Hydra.Tx ( ) import Hydra.Tx.OnChainId (OnChainId) import Test.Cardano.Ledger.Core.Arbitrary () -import Test.Hydra.Tx () import Test.Hydra.Tx.Gen (ArbitraryIsTx) import Test.QuickCheck.Instances.Semigroup () import Test.QuickCheck.Instances.Time () diff --git a/hydra-node/src/Hydra/Chain/Direct/State.hs b/hydra-node/src/Hydra/Chain/Direct/State.hs index d657e7c9544..0650a77931f 100644 --- a/hydra-node/src/Hydra/Chain/Direct/State.hs +++ b/hydra-node/src/Hydra/Chain/Direct/State.hs @@ -107,6 +107,7 @@ import Hydra.Tx.Decrement (decrementTx) import Hydra.Tx.Fanout (fanoutTx) import Hydra.Tx.Init (initTx) import Hydra.Tx.OnChainId (OnChainId) +import Hydra.Tx.Snapshot (genConfirmedSnapshot) import Hydra.Tx.Utils (splitUTxO, verificationKeyToOnChainId) import Test.Hydra.Tx.Gen ( genOneUTxOFor, @@ -116,7 +117,6 @@ import Test.Hydra.Tx.Gen ( genUTxOAdaOnlyOfSize, genVerificationKey, ) -import Test.Hydra.Tx.Snapshot (genConfirmedSnapshot) import Test.QuickCheck (choose, frequency, oneof, suchThat, vector) import Test.QuickCheck.Gen (elements) import Test.QuickCheck.Modifiers (Positive (Positive)) diff --git a/hydra-node/src/Hydra/Chain/Direct/Tx.hs b/hydra-node/src/Hydra/Chain/Direct/Tx.hs index 5518e075f18..029a289e8f1 100644 --- a/hydra-node/src/Hydra/Chain/Direct/Tx.hs +++ b/hydra-node/src/Hydra/Chain/Direct/Tx.hs @@ -46,7 +46,6 @@ import Hydra.Tx.OnChainId (OnChainId (..)) import Hydra.Tx.Utils (assetNameToOnChainId, findFirst, hydraHeadV1AssetName, hydraMetadataLabel) import PlutusLedgerApi.V2 (CurrencySymbol, fromBuiltin) import PlutusLedgerApi.V2 qualified as Plutus -import Test.Hydra.Tx () import Test.Hydra.Tx.Gen () import Test.QuickCheck (vectorOf) diff --git a/hydra-node/src/Hydra/HeadLogic/State.hs b/hydra-node/src/Hydra/HeadLogic/State.hs index 953360611bb..11dcdc9b3a3 100644 --- a/hydra-node/src/Hydra/HeadLogic/State.hs +++ b/hydra-node/src/Hydra/HeadLogic/State.hs @@ -22,7 +22,6 @@ import Hydra.Tx.Snapshot ( SnapshotNumber, SnapshotVersion, ) -import Test.Hydra.Tx () import Test.Hydra.Tx.Gen (ArbitraryIsTx) -- | The main state of the Hydra protocol state machine. It holds both, the diff --git a/hydra-node/src/Hydra/Network/Message.hs b/hydra-node/src/Hydra/Network/Message.hs index 9e79dc65f11..cabff87614d 100644 --- a/hydra-node/src/Hydra/Network/Message.hs +++ b/hydra-node/src/Hydra/Network/Message.hs @@ -16,7 +16,6 @@ import Hydra.Tx ( UTxOType, ) import Hydra.Tx.Crypto (Signature) -import Test.Hydra.Tx () import Test.Hydra.Tx.Gen (ArbitraryIsTx) data NetworkEvent msg diff --git a/hydra-tx/hydra-tx.cabal b/hydra-tx/hydra-tx.cabal index 862d6aed77f..ac2db92b027 100644 --- a/hydra-tx/hydra-tx.cabal +++ b/hydra-tx/hydra-tx.cabal @@ -114,12 +114,9 @@ library testlib hs-source-dirs: testlib visibility: public exposed-modules: - Test.Hydra.Tx Test.Hydra.Tx.Fixture Test.Hydra.Tx.Gen - Test.Hydra.Tx.HeadId Test.Hydra.Tx.Mutation - Test.Hydra.Tx.Snapshot other-modules: Paths_hydra_tx build-depends: diff --git a/hydra-tx/src/Hydra/Tx/HeadId.hs b/hydra-tx/src/Hydra/Tx/HeadId.hs index 45496f2d91d..0c594779f78 100644 --- a/hydra-tx/src/Hydra/Tx/HeadId.hs +++ b/hydra-tx/src/Hydra/Tx/HeadId.hs @@ -4,6 +4,7 @@ module Hydra.Tx.HeadId where import Hydra.Prelude +import Data.ByteString qualified as BS import Hydra.Cardano.Api ( HasTypeProxy (..), PolicyId, @@ -11,6 +12,9 @@ import Hydra.Cardano.Api ( UsingRawBytesHex (..), ) import PlutusLedgerApi.V2 (CurrencySymbol (..), toBuiltin) +import Test.QuickCheck (vectorOf) +import Test.QuickCheck.Instances.Semigroup () +import Test.QuickCheck.Instances.Time () -- | Uniquely identifies a Hydra Head. newtype HeadId = UnsafeHeadId ByteString @@ -26,6 +30,9 @@ instance HasTypeProxy HeadId where data AsType HeadId = AsHeadId proxyToAsType _ = AsHeadId +instance Arbitrary HeadId where + arbitrary = UnsafeHeadId . BS.pack <$> vectorOf 16 arbitrary + -- | Unique seed to create a 'HeadId' -- -- XXX: This might actually be the 'HeadId' to the protocol and users? Then the @@ -44,6 +51,9 @@ instance HasTypeProxy HeadSeed where data AsType HeadSeed = AsHeadSeed proxyToAsType _ = AsHeadSeed +instance Arbitrary HeadSeed where + arbitrary = UnsafeHeadSeed . BS.pack <$> vectorOf 16 arbitrary + headIdToCurrencySymbol :: HeadId -> CurrencySymbol headIdToCurrencySymbol (UnsafeHeadId headId) = CurrencySymbol (toBuiltin headId) diff --git a/hydra-tx/src/Hydra/Tx/Party.hs b/hydra-tx/src/Hydra/Tx/Party.hs index cc55b7f1b68..6884832d1e1 100644 --- a/hydra-tx/src/Hydra/Tx/Party.hs +++ b/hydra-tx/src/Hydra/Tx/Party.hs @@ -24,6 +24,7 @@ import Hydra.Tx.Crypto (AsType (AsHydraKey), HydraKey) newtype Party = Party {vkey :: VerificationKey HydraKey} deriving stock (Eq, Show, Generic) deriving anyclass (ToJSON, FromJSON) + deriving newtype (Arbitrary) instance ToJSONKey Party where toJSONKey = toJSONKeyText (serialiseToRawBytesHexText . vkey) @@ -43,9 +44,6 @@ instance Ord Party where Party{vkey = a} <= Party{vkey = b} = verificationKeyHash a <= verificationKeyHash b -instance Arbitrary Party where - arbitrary = Party <$> arbitrary - instance FromCBOR Party where fromCBOR = Party <$> fromCBOR diff --git a/hydra-tx/src/Hydra/Tx/Snapshot.hs b/hydra-tx/src/Hydra/Tx/Snapshot.hs index a6d725f8de0..30af5757954 100644 --- a/hydra-tx/src/Hydra/Tx/Snapshot.hs +++ b/hydra-tx/src/Hydra/Tx/Snapshot.hs @@ -9,18 +9,21 @@ import Cardano.Crypto.Util (SignableRepresentation (..)) import Codec.Serialise (serialise) import Data.Aeson (object, withObject, (.:), (.:?), (.=)) import Data.ByteString.Lazy qualified as LBS -import Hydra.Cardano.Api (SerialiseAsRawBytes (..)) +import Hydra.Cardano.Api (SerialiseAsRawBytes (..), SigningKey) import Hydra.Contract.HeadState qualified as Onchain -import Hydra.Tx.Crypto (MultiSignature) +import Hydra.Tx.Crypto (HydraKey, MultiSignature, aggregate, sign) import Hydra.Tx.HeadId (HeadId) import Hydra.Tx.IsTx (IsTx (..)) import PlutusLedgerApi.V2 (toBuiltin, toData) +import Test.QuickCheck (frequency, suchThat) import Test.QuickCheck.Instances.Natural () +-- * SnapshotNumber and SnapshotVersion + newtype SnapshotNumber = UnsafeSnapshotNumber Natural deriving stock (Eq, Ord, Generic) - deriving newtype (Show, ToJSON, FromJSON, ToCBOR, FromCBOR, Real, Num, Enum, Integral) + deriving newtype (Show, ToJSON, FromJSON, ToCBOR, FromCBOR, Real, Num, Enum, Integral, Arbitrary) -- NOTE: On-chain scripts ensure snapshot number does not become negative. fromChainSnapshotNumber :: Onchain.SnapshotNumber -> SnapshotNumber @@ -30,13 +33,15 @@ fromChainSnapshotNumber = newtype SnapshotVersion = UnsafeSnapshotVersion Natural deriving stock (Eq, Ord, Generic) - deriving newtype (Show, ToJSON, FromJSON, ToCBOR, FromCBOR, Real, Num, Enum, Integral) + deriving newtype (Show, ToJSON, FromJSON, ToCBOR, FromCBOR, Real, Num, Enum, Integral, Arbitrary) -- NOTE: On-chain scripts ensure snapshot version does not become negative. fromChainSnapshotVersion :: Onchain.SnapshotVersion -> SnapshotVersion fromChainSnapshotVersion = UnsafeSnapshotVersion . fromMaybe 0 . integerToNatural +-- * Snapshot + data Snapshot tx = Snapshot { headId :: HeadId , version :: SnapshotVersion @@ -54,6 +59,17 @@ data Snapshot tx = Snapshot deriving stock instance IsTx tx => Eq (Snapshot tx) deriving stock instance IsTx tx => Show (Snapshot tx) +-- | Binary representation of snapshot signatures. That is, concatenated CBOR for +-- 'headId', 'version', 'number', 'utxoHash' and 'utxoToDecommitHash' according +-- to CDDL schemata: +-- +-- headId = bytes .size 16 +-- version = uint +-- number = uint +-- utxoHash = bytes +-- utxoToDecommitHash = bytes +-- +-- where hashes are the result of applying 'hashUTxO'. instance forall tx. IsTx tx => SignableRepresentation (Snapshot tx) where getSignableRepresentation Snapshot{headId, version, number, utxo, utxoToDecommit} = LBS.toStrict $ @@ -106,6 +122,19 @@ instance (Typeable tx, FromCBOR (UTxOType tx), FromCBOR (TxIdType tx)) => FromCB <*> fromCBOR <*> fromCBOR +instance (Arbitrary (UTxOType tx), Arbitrary (TxIdType tx)) => Arbitrary (Snapshot tx) where + arbitrary = genericArbitrary + + -- NOTE: See note on 'Arbitrary (ClientInput tx)' + shrink Snapshot{headId, version, number, utxo, confirmed, utxoToDecommit} = + [ Snapshot headId version number confirmed' utxo' utxoToDecommit' + | confirmed' <- shrink confirmed + , utxo' <- shrink utxo + , utxoToDecommit' <- shrink utxoToDecommit + ] + +-- * ConfirmedSnapshot + -- | A snapshot that can be used to close a head with. Either the initial one, -- or when it was signed by all parties, i.e. it is confirmed. data ConfirmedSnapshot tx @@ -121,13 +150,13 @@ data ConfirmedSnapshot tx deriving stock (Generic, Eq, Show) deriving anyclass (ToJSON, FromJSON) +-- | Safely get a 'Snapshot' from a confirmed snapshot. +-- -- NOTE: While we could use 'snapshot' directly, this is a record-field accessor -- which may become partial (and lead to unnoticed runtime errors) if we ever -- add a new branch to the sumtype. So, we explicitely define a getter which -- will force us into thinking about changing the signature properly if this -- happens. - --- | Safely get a 'Snapshot' from a confirmed snapshot. getSnapshot :: ConfirmedSnapshot tx -> Snapshot tx getSnapshot = \case InitialSnapshot{headId, initialUTxO} -> @@ -147,3 +176,48 @@ isInitialSnapshot :: ConfirmedSnapshot tx -> Bool isInitialSnapshot = \case InitialSnapshot{} -> True ConfirmedSnapshot{} -> False + +instance (Arbitrary (UTxOType tx), Arbitrary (TxIdType tx), IsTx tx) => Arbitrary (ConfirmedSnapshot tx) where + arbitrary = do + ks <- arbitrary + utxo <- arbitrary + utxoToDecommit <- arbitrary + headId <- arbitrary + genConfirmedSnapshot headId 0 0 utxo utxoToDecommit ks + + shrink = \case + InitialSnapshot hid sn -> [InitialSnapshot hid sn' | sn' <- shrink sn] + ConfirmedSnapshot sn sigs -> ConfirmedSnapshot <$> shrink sn <*> shrink sigs + +genConfirmedSnapshot :: + IsTx tx => + HeadId -> + -- | Exact snapshot version to generate. + SnapshotVersion -> + -- | The lower bound on snapshot number to generate. + -- If this is 0, then we can generate an `InitialSnapshot` or a `ConfirmedSnapshot`. + -- Otherwise we generate only `ConfirmedSnapshot` with a number strictly superior to + -- this lower bound. + SnapshotNumber -> + UTxOType tx -> + Maybe (UTxOType tx) -> + [SigningKey HydraKey] -> + Gen (ConfirmedSnapshot tx) +genConfirmedSnapshot headId version minSn utxo utxoToDecommit sks + | minSn > 0 = confirmedSnapshot + | otherwise = + frequency + [ (1, initialSnapshot) + , (9, confirmedSnapshot) + ] + where + initialSnapshot = + InitialSnapshot <$> arbitrary <*> pure utxo + + confirmedSnapshot = do + -- FIXME: This is another nail in the coffin to our current modeling of + -- snapshots + number <- arbitrary `suchThat` (> minSn) + let snapshot = Snapshot{headId, version, number, confirmed = [], utxo, utxoToDecommit} + let signatures = aggregate $ fmap (`sign` snapshot) sks + pure $ ConfirmedSnapshot{snapshot, signatures} diff --git a/hydra-tx/src/Hydra/Tx/Utils.hs b/hydra-tx/src/Hydra/Tx/Utils.hs index db76aef1610..b3f69e0bda5 100644 --- a/hydra-tx/src/Hydra/Tx/Utils.hs +++ b/hydra-tx/src/Hydra/Tx/Utils.hs @@ -1,5 +1,3 @@ -{-# OPTIONS_GHC -Wno-orphans #-} - module Hydra.Tx.Utils where import Hydra.Cardano.Api diff --git a/hydra-tx/test/Hydra/Tx/Contract/Close/CloseUnused.hs b/hydra-tx/test/Hydra/Tx/Contract/Close/CloseUnused.hs index 1791dd86931..63b20706238 100644 --- a/hydra-tx/test/Hydra/Tx/Contract/Close/CloseUnused.hs +++ b/hydra-tx/test/Hydra/Tx/Contract/Close/CloseUnused.hs @@ -61,7 +61,6 @@ import Test.Hydra.Tx.Mutation ( replaceSnapshotVersion, replaceUTxOHash, ) -import Test.Hydra.Tx.Snapshot () import Test.QuickCheck (arbitrarySizedNatural, choose, elements, listOf1, oneof, resize, suchThat) import Test.QuickCheck.Instances () diff --git a/hydra-tx/test/Hydra/Tx/Contract/Close/CloseUsed.hs b/hydra-tx/test/Hydra/Tx/Contract/Close/CloseUsed.hs index 53c1895538e..759269c1ad6 100644 --- a/hydra-tx/test/Hydra/Tx/Contract/Close/CloseUsed.hs +++ b/hydra-tx/test/Hydra/Tx/Contract/Close/CloseUsed.hs @@ -44,7 +44,6 @@ import Hydra.Tx.Contract.Close.Healthy ( somePartyCardanoVerificationKey, ) import Hydra.Tx.Crypto (MultiSignature (..), toPlutusSignatures) -import Hydra.Tx.Snapshot () import PlutusLedgerApi.V1.Time (DiffMilliSeconds (..), fromMilliSeconds) import PlutusLedgerApi.V2 (POSIXTime, PubKeyHash (PubKeyHash), toBuiltin) import Test.Hydra.Tx.Fixture qualified as Fixture @@ -71,7 +70,6 @@ import Test.Hydra.Tx.Mutation ( replaceSnapshotVersion, replaceUTxOHash, ) -import Test.Hydra.Tx.Snapshot () import Test.QuickCheck (arbitrarySizedNatural, choose, elements, listOf1, oneof, suchThat) import Test.QuickCheck.Instances () diff --git a/hydra-tx/test/Hydra/Tx/Contract/Contest/ContestCurrent.hs b/hydra-tx/test/Hydra/Tx/Contract/Contest/ContestCurrent.hs index ad339f1e7cf..8e872d34ec7 100644 --- a/hydra-tx/test/Hydra/Tx/Contract/Contest/ContestCurrent.hs +++ b/hydra-tx/test/Hydra/Tx/Contract/Contest/ContestCurrent.hs @@ -34,7 +34,6 @@ import Hydra.Tx.Utils ( ) import PlutusLedgerApi.V2 (BuiltinByteString, toBuiltin) import PlutusLedgerApi.V2 qualified as Plutus -import Test.Hydra.Tx () import Test.Hydra.Tx.Fixture (aliceSk, bobSk, carolSk, slotLength, systemStart, testNetworkId, testPolicyId) import Test.Hydra.Tx.Fixture qualified as Fixture import Test.Hydra.Tx.Gen ( diff --git a/hydra-tx/test/Hydra/Tx/Contract/Decrement.hs b/hydra-tx/test/Hydra/Tx/Contract/Decrement.hs index 29666969fbc..9102a30bb00 100644 --- a/hydra-tx/test/Hydra/Tx/Contract/Decrement.hs +++ b/hydra-tx/test/Hydra/Tx/Contract/Decrement.hs @@ -37,7 +37,6 @@ import Hydra.Tx.Utils (adaOnly, splitUTxO) import PlutusTx.Builtins (toBuiltin) import Test.Hydra.Tx.Fixture (aliceSk, bobSk, carolSk, testNetworkId, testPolicyId) import Test.Hydra.Tx.Gen (genForParty, genScriptRegistry, genUTxOSized, genValue, genVerificationKey) -import Test.Hydra.Tx.Snapshot () import Test.QuickCheck (arbitrarySizedNatural, choose, elements, oneof) import Test.QuickCheck.Gen (suchThat) import Test.QuickCheck.Instances () diff --git a/hydra-tx/testlib/Test/Hydra/Tx.hs b/hydra-tx/testlib/Test/Hydra/Tx.hs index 7fbfa481527..c8156619627 100644 --- a/hydra-tx/testlib/Test/Hydra/Tx.hs +++ b/hydra-tx/testlib/Test/Hydra/Tx.hs @@ -1,4 +1 @@ module Test.Hydra.Tx where - -import Test.Hydra.Tx.HeadId () -import Test.Hydra.Tx.Snapshot () diff --git a/hydra-tx/testlib/Test/Hydra/Tx/Fixture.hs b/hydra-tx/testlib/Test/Hydra/Tx/Fixture.hs index 32bc0f3530d..f49454b030f 100644 --- a/hydra-tx/testlib/Test/Hydra/Tx/Fixture.hs +++ b/hydra-tx/testlib/Test/Hydra/Tx/Fixture.hs @@ -1,5 +1,4 @@ {-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-} -{-# OPTIONS_GHC -Wno-orphans #-} -- | Generic Cardano constants for use in testing. module Test.Hydra.Tx.Fixture ( diff --git a/hydra-tx/testlib/Test/Hydra/Tx/HeadId.hs b/hydra-tx/testlib/Test/Hydra/Tx/HeadId.hs deleted file mode 100644 index 3d66e4a87a8..00000000000 --- a/hydra-tx/testlib/Test/Hydra/Tx/HeadId.hs +++ /dev/null @@ -1,18 +0,0 @@ -{-# LANGUAGE DerivingVia #-} -{-# OPTIONS_GHC -fno-warn-orphans #-} - -module Test.Hydra.Tx.HeadId where - -import Hydra.Prelude - -import Data.ByteString qualified as BS -import Hydra.Tx.HeadId (HeadId (..), HeadSeed (..)) -import Test.QuickCheck (vectorOf) -import Test.QuickCheck.Instances.Semigroup () -import Test.QuickCheck.Instances.Time () - -instance Arbitrary HeadId where - arbitrary = UnsafeHeadId . BS.pack <$> vectorOf 16 arbitrary - -instance Arbitrary HeadSeed where - arbitrary = UnsafeHeadSeed . BS.pack <$> vectorOf 16 arbitrary diff --git a/hydra-tx/testlib/Test/Hydra/Tx/Snapshot.hs b/hydra-tx/testlib/Test/Hydra/Tx/Snapshot.hs deleted file mode 100644 index a143beda136..00000000000 --- a/hydra-tx/testlib/Test/Hydra/Tx/Snapshot.hs +++ /dev/null @@ -1,89 +0,0 @@ -{-# LANGUAGE DuplicateRecordFields #-} -{-# LANGUAGE UndecidableInstances #-} -{-# OPTIONS_GHC -fno-warn-orphans #-} - -module Test.Hydra.Tx.Snapshot where - -import Hydra.Prelude - -import Hydra.Cardano.Api (SigningKey) -import Hydra.Tx.Crypto (HydraKey, aggregate, sign) -import Hydra.Tx.HeadId (HeadId) -import Hydra.Tx.IsTx (IsTx (..)) -import Hydra.Tx.Snapshot (ConfirmedSnapshot (..), Snapshot (..), SnapshotNumber (..), SnapshotVersion (..)) -import Test.Hydra.Tx.HeadId () -import Test.QuickCheck (frequency, suchThat) -import Test.QuickCheck.Instances.Natural () - -instance Arbitrary SnapshotNumber where - arbitrary = UnsafeSnapshotNumber <$> arbitrary - -instance Arbitrary SnapshotVersion where - arbitrary = UnsafeSnapshotVersion <$> arbitrary - -instance (Arbitrary (UTxOType tx), Arbitrary (TxIdType tx)) => Arbitrary (Snapshot tx) where - arbitrary = genericArbitrary - - -- NOTE: See note on 'Arbitrary (ClientInput tx)' - shrink Snapshot{headId, version, number, utxo, confirmed, utxoToDecommit} = - [ Snapshot headId version number confirmed' utxo' utxoToDecommit' - | confirmed' <- shrink confirmed - , utxo' <- shrink utxo - , utxoToDecommit' <- shrink utxoToDecommit - ] - --- | Binary representation of snapshot signatures. That is, concatenated CBOR for --- 'headId', 'version', 'number', 'utxoHash' and 'utxoToDecommitHash' according --- to CDDL schemata: --- --- headId = bytes .size 16 --- version = uint --- number = uint --- utxoHash = bytes --- utxoToDecommitHash = bytes --- --- where hashes are the result of applying 'hashUTxO'. -instance (Arbitrary (UTxOType tx), Arbitrary (TxIdType tx), IsTx tx) => Arbitrary (ConfirmedSnapshot tx) where - arbitrary = do - ks <- arbitrary - utxo <- arbitrary - utxoToDecommit <- arbitrary - headId <- arbitrary - genConfirmedSnapshot headId 0 0 utxo utxoToDecommit ks - - shrink = \case - InitialSnapshot hid sn -> [InitialSnapshot hid sn' | sn' <- shrink sn] - ConfirmedSnapshot sn sigs -> ConfirmedSnapshot <$> shrink sn <*> shrink sigs - -genConfirmedSnapshot :: - IsTx tx => - HeadId -> - -- | Exact snapshot version to generate. - SnapshotVersion -> - -- | The lower bound on snapshot number to generate. - -- If this is 0, then we can generate an `InitialSnapshot` or a `ConfirmedSnapshot`. - -- Otherwise we generate only `ConfirmedSnapshot` with a number strictly superior to - -- this lower bound. - SnapshotNumber -> - UTxOType tx -> - Maybe (UTxOType tx) -> - [SigningKey HydraKey] -> - Gen (ConfirmedSnapshot tx) -genConfirmedSnapshot headId version minSn utxo utxoToDecommit sks - | minSn > 0 = confirmedSnapshot - | otherwise = - frequency - [ (1, initialSnapshot) - , (9, confirmedSnapshot) - ] - where - initialSnapshot = - InitialSnapshot <$> arbitrary <*> pure utxo - - confirmedSnapshot = do - -- FIXME: This is another nail in the coffin to our current modeling of - -- snapshots - number <- arbitrary `suchThat` (> minSn) - let snapshot = Snapshot{headId, version, number, confirmed = [], utxo, utxoToDecommit} - let signatures = aggregate $ fmap (`sign` snapshot) sks - pure $ ConfirmedSnapshot{snapshot, signatures}