11{-# LANGUAGE DataKinds #-}
2+ {-# LANGUAGE FlexibleContexts #-}
23
34module Test.Gen.Cardano.Api.Experimental
45 ( genAnyScript
@@ -11,6 +12,8 @@ module Test.Gen.Cardano.Api.Experimental
1112 , genSimpleScriptInEra
1213 , genUnsignedSubTx
1314 , genSignedSubTx
15+ , genUnsignedSubTxWithGovernance
16+ , genGovernanceActionProposals
1417 )
1518where
1619
@@ -21,7 +24,15 @@ import Cardano.Api.Experimental.AnyScriptWitness
2124import Cardano.Api.Experimental.Tx
2225import Cardano.Api.Ledger qualified as L
2326
27+ import Cardano.Ledger.Core qualified as L
28+ import Cardano.Ledger.Dijkstra.Tx qualified as Dijkstra
29+ import Cardano.Ledger.Dijkstra.TxBody qualified as Dijkstra
30+
31+ import Control.Monad (forM , zipWithM )
2432import Data.Map.Ordered.Strict qualified as OMap
33+ import Data.Map.Strict qualified as Map
34+ import Data.OSet.Strict qualified as OSet
35+ import Data.Set qualified as Set
2536import Data.Typeable
2637
2738import Test.Gen.Cardano.Api.Typed
@@ -32,11 +43,13 @@ import Test.Gen.Cardano.Api.Typed
3243 , genTxIn
3344 )
3445
46+ import Test.Cardano.Ledger.Conway.Arbitrary qualified as Conway
3547import Test.Cardano.Ledger.Dijkstra.Arbitrary ()
3648
3749import Hedgehog (Gen )
3850import Hedgehog.Gen qualified as Gen
3951import Hedgehog.Gen.QuickCheck qualified as Q
52+ import Test.QuickCheck qualified as QC
4053
4154genAnyWitness :: Gen (AnyWitness era )
4255genAnyWitness =
@@ -153,9 +166,127 @@ genScriptWitnesssedTxVotingProcedures = return $ TxVotingProcedures (L.VotingPro
153166genScriptWitnessedTxProposals :: Gen (TxProposalProcedures era )
154167genScriptWitnessedTxProposals = return $ TxProposalProcedures OMap. empty
155168
156- -- | An arbitrary Dijkstra sub-transaction. May contain key witnesses.
169+ -- | A Dijkstra sub-transaction with shared governance size budgets . May contain key witnesses.
157170genUnsignedSubTx :: Gen UnsignedSubTx
158- genUnsignedSubTx = UnsignedSubTx <$> Q. arbitrary
171+ genUnsignedSubTx = UnsignedSubTx <$> Q. quickcheck genBudgetedSubTx
159172
160173genSignedSubTx :: Gen SignedSubTx
161- genSignedSubTx = SignedSubTx <$> Q. arbitrary
174+ genSignedSubTx = SignedSubTx <$> Q. quickcheck genBudgetedSubTx
175+
176+ -- | Generate exact governance cardinalities for serialisation boundary cases.
177+ genUnsignedSubTxWithGovernance
178+ :: Int
179+ -- ^ Number of voters.
180+ -> Int
181+ -- ^ Voting entries per voter.
182+ -> Int
183+ -- ^ Number of proposals.
184+ -> Gen UnsignedSubTx
185+ genUnsignedSubTxWithGovernance voterCount voteCount proposalCount =
186+ UnsignedSubTx
187+ <$> Q. quickcheck
188+ ( genSubTxWithGovernance
189+ (L. VotingProcedures <$> genDistinctMap voterCount (genDistinctMap voteCount QC. arbitrary))
190+ ( QC. suchThat
191+ (OSet. fromFoldable <$> QC. vectorOf proposalCount QC. arbitrary)
192+ ((== proposalCount) . length )
193+ )
194+ )
195+
196+ -- | Include every governance action family and distinct treasury coin values.
197+ genGovernanceActionProposals
198+ :: (L. EraPParams era , QC. Arbitrary (L. PParamsHKD L. StrictMaybe era ))
199+ => [L. Coin ]
200+ -- ^ Proposal deposits and treasury withdrawal values.
201+ -> Gen (OSet. OSet (L. ProposalProcedure era ))
202+ genGovernanceActionProposals coins = Q. quickcheck $ do
203+ actions <-
204+ sequence
205+ [ Conway. genParameterChange
206+ , Conway. genHardForkInitiation
207+ , do
208+ recipients <- genDistinctMap (length coins) $ pure ()
209+ L. TreasuryWithdrawals (Map. fromList $ zip (Map. keys recipients) coins) <$> QC. arbitrary
210+ , Conway. genNoConfidence
211+ , Conway. genUpdateCommittee
212+ , Conway. genNewConstitution
213+ , pure L. InfoAction
214+ ]
215+ OSet. fromFoldable
216+ <$> zipWithM
217+ (\ coin action -> L. ProposalProcedure coin <$> QC. arbitrary <*> pure action <*> QC. arbitrary)
218+ coins
219+ actions
220+
221+ type TestEra = DijkstraEra
222+
223+ genBudgetedSubTx :: QC. Gen (L. Tx L. SubTx (LedgerEra TestEra ))
224+ genBudgetedSubTx = genSubTxWithGovernance genBudgetedVotingProcedures genBudgetedProposals
225+
226+ genSubTxWithGovernance
227+ :: QC. Gen (L. VotingProcedures (LedgerEra TestEra ))
228+ -> QC. Gen (OSet. OSet (L. ProposalProcedure (LedgerEra TestEra )))
229+ -> QC. Gen (L. Tx L. SubTx (LedgerEra TestEra ))
230+ genSubTxWithGovernance doVotes doProposals = do
231+ body <-
232+ Dijkstra. DijkstraSubTxBody
233+ <$> QC. arbitrary
234+ <*> QC. arbitrary
235+ <*> QC. arbitrary
236+ <*> QC. arbitrary
237+ <*> QC. arbitrary
238+ <*> QC. scale (`div` 15 ) QC. arbitrary
239+ <*> QC. arbitrary
240+ <*> QC. scale (`div` 15 ) QC. arbitrary
241+ <*> QC. arbitrary
242+ <*> QC. arbitrary
243+ <*> QC. arbitrary
244+ <*> doVotes
245+ <*> doProposals
246+ <*> QC. arbitrary
247+ <*> QC. arbitrary
248+ <*> QC. arbitrary
249+ <*> QC. arbitrary
250+ <*> QC. arbitrary
251+ Dijkstra. MkDijkstraTx <$> (Dijkstra. DijkstraSubTx body <$> QC. arbitrary <*> QC. arbitrary)
252+
253+ genBudgetedVotingProcedures :: L. Era era => QC. Gen (L. VotingProcedures era )
254+ genBudgetedVotingProcedures = QC. sized $ \ budget -> do
255+ voterCount <- QC. chooseInt (0 , budget)
256+ -- Every voter has a nonempty map, with at most the outer size in total entries.
257+ let entryBudget = budget `div` max 1 voterCount
258+ L. VotingProcedures
259+ <$> genDistinctMap
260+ voterCount
261+ ( do
262+ entryCount <- QC. chooseInt (1 , entryBudget)
263+ genDistinctMap entryCount QC. arbitrary
264+ )
265+
266+ genBudgetedProposals
267+ :: (L. EraPParams era , QC. Arbitrary (L. PParamsHKD L. StrictMaybe era ))
268+ => QC. Gen (OSet. OSet (L. ProposalProcedure era ))
269+ genBudgetedProposals = QC. sized $ \ budget -> do
270+ -- Fixed-cost cost models make proposal counts grow more slowly than payload sizes.
271+ let countBudget = length $ takeWhile (\ count -> count <= budget `div` count) [1 .. budget]
272+ proposalCount <- QC. chooseInt (0 , countBudget)
273+ -- Divide the QuickCheck size among actions before generating their nested payloads.
274+ let payloadBudget = budget `div` max 1 proposalCount
275+ OSet. fromFoldable
276+ <$> QC. vectorOf
277+ proposalCount
278+ ( L. ProposalProcedure
279+ <$> QC. arbitrary
280+ <*> QC. arbitrary
281+ <*> QC. resize payloadBudget QC. arbitrary
282+ <*> QC. arbitrary
283+ )
284+
285+ genDistinctMap :: (Ord k , QC. Arbitrary k ) => Int -> QC. Gen v -> QC. Gen (Map. Map k v )
286+ genDistinctMap entryCount doValue = do
287+ keys <-
288+ QC. suchThat
289+ (QC. vectorOf entryCount QC. arbitrary)
290+ ((== entryCount) . Set. size . Set. fromList)
291+ entries <- forM keys $ \ key -> (,) key <$> doValue
292+ pure $ Map. fromList entries
0 commit comments