Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generalize UTxO identifiers and addresses in coin selection Gen modules. #3174

Merged
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/core/cardano-wallet-core.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ library
-- The following modules define QC generators and shrinkers that can
-- be used by both `cardano-wallet-core` and `cardano-wallet`:
--
Cardano.Wallet.CoinSelection.Gen
Cardano.Wallet.CoinSelection.Internal.Balance.Gen
Cardano.Wallet.Primitive.Types.Address.Gen
Cardano.Wallet.Primitive.Types.Coin.Gen
Expand Down
49 changes: 49 additions & 0 deletions lib/core/src/Cardano/Wallet/CoinSelection/Gen.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
module Cardano.Wallet.CoinSelection.Gen
( coarbitraryWalletUTxO
, genWalletUTxO
, genWalletUTxOFunction
, genWalletUTxOLargeRange
, shrinkWalletUTxO
)
where

import Prelude

import Cardano.Wallet.CoinSelection
( WalletUTxO (..) )
import Cardano.Wallet.Primitive.Types.Address.Gen
( genAddress, shrinkAddress )
import Cardano.Wallet.Primitive.Types.Tx.Gen
( genTxIn, genTxInLargeRange, shrinkTxIn )
import Generics.SOP
( NP (..) )
import Test.QuickCheck
( Gen, coarbitrary )
import Test.QuickCheck.Extra
( genFunction, genSized2, genericRoundRobinShrink, (<:>), (<@>) )

--------------------------------------------------------------------------------
-- Wallet UTxO identifiers chosen according to the size parameter
--------------------------------------------------------------------------------

coarbitraryWalletUTxO :: WalletUTxO -> Gen a -> Gen a
coarbitraryWalletUTxO = coarbitrary . show

genWalletUTxO :: Gen WalletUTxO
genWalletUTxO = uncurry WalletUTxO <$> genSized2 genTxIn genAddress

shrinkWalletUTxO :: WalletUTxO -> [WalletUTxO]
shrinkWalletUTxO = genericRoundRobinShrink
<@> shrinkTxIn
<:> shrinkAddress
<:> Nil

genWalletUTxOFunction :: Gen a -> Gen (WalletUTxO -> a)
genWalletUTxOFunction = genFunction coarbitraryWalletUTxO

--------------------------------------------------------------------------------
-- Wallet UTxO identifiers chosen from a large range
--------------------------------------------------------------------------------

genWalletUTxOLargeRange :: Gen WalletUTxO
genWalletUTxOLargeRange = WalletUTxO <$> genTxInLargeRange <*> genAddress
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,14 @@ module Cardano.Wallet.CoinSelection.Internal.Balance.Gen

import Prelude

import Cardano.Wallet.CoinSelection
( WalletSelectionContext )
import Cardano.Wallet.CoinSelection.Internal.Balance
( SelectionLimit
, SelectionLimitOf (..)
, SelectionSkeleton (..)
, SelectionStrategy (..)
)
import Cardano.Wallet.Primitive.Types.Address.Gen
( genAddress, shrinkAddress )
import Cardano.Wallet.CoinSelection.Internal.Context
( SelectionContext (..) )
import Cardano.Wallet.Primitive.Types.Coin
( Coin (..) )
import Cardano.Wallet.Primitive.Types.TokenBundle
Expand Down Expand Up @@ -72,8 +70,8 @@ shrinkSelectionLimit = \case
-- Selection skeletons
--------------------------------------------------------------------------------

genSelectionSkeleton :: Gen (SelectionSkeleton WalletSelectionContext)
genSelectionSkeleton = SelectionSkeleton
genSelectionSkeleton :: Gen (Address ctx) -> Gen (SelectionSkeleton ctx)
genSelectionSkeleton genAddress = SelectionSkeleton
<$> genSkeletonInputCount
<*> genSkeletonOutputs
<*> genSkeletonChange
Expand All @@ -89,9 +87,9 @@ genSelectionSkeleton = SelectionSkeleton
listOf (Set.fromList <$> listOf genAssetId)

shrinkSelectionSkeleton
:: SelectionSkeleton WalletSelectionContext
-> [SelectionSkeleton WalletSelectionContext]
shrinkSelectionSkeleton = genericRoundRobinShrink
:: (Address ctx -> [Address ctx])
-> (SelectionSkeleton ctx -> [SelectionSkeleton ctx])
shrinkSelectionSkeleton shrinkAddress = genericRoundRobinShrink
<@> shrinkSkeletonInputCount
<:> shrinkSkeletonOutputs
<:> shrinkSkeletonChange
Expand Down
51 changes: 18 additions & 33 deletions lib/core/src/Cardano/Wallet/Primitive/Types/UTxOIndex/Gen.hs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
{-# LANGUAGE ScopedTypeVariables #-}

module Cardano.Wallet.Primitive.Types.UTxOIndex.Gen
( genUTxOIndex
, genUTxOIndexLarge
Expand All @@ -7,16 +9,10 @@ module Cardano.Wallet.Primitive.Types.UTxOIndex.Gen

import Prelude

import Cardano.Wallet.CoinSelection
( WalletUTxO (..) )
import Cardano.Wallet.Primitive.Types.Address.Gen
( genAddress, shrinkAddress )
import Cardano.Wallet.Primitive.Types.TokenBundle
( TokenBundle )
import Cardano.Wallet.Primitive.Types.TokenBundle.Gen
( genTokenBundleSmallRangePositive, shrinkTokenBundleSmallRangePositive )
import Cardano.Wallet.Primitive.Types.Tx.Gen
( genTxIn, genTxInLargeRange, shrinkTxIn )
import Cardano.Wallet.Primitive.Types.UTxOIndex
( UTxOIndex )
import Control.Monad
Expand All @@ -26,51 +22,40 @@ import Generics.SOP
import Test.QuickCheck
( Gen, choose, listOf, shrinkList, shrinkMapBy )
import Test.QuickCheck.Extra
( genSized2, genericRoundRobinShrink, (<:>), (<@>) )
( genericRoundRobinShrink, (<:>), (<@>) )

import qualified Cardano.Wallet.Primitive.Types.UTxOIndex as UTxOIndex

--------------------------------------------------------------------------------
-- Indices generated according to the size parameter
--------------------------------------------------------------------------------

genUTxOIndex :: Gen (UTxOIndex WalletUTxO)
genUTxOIndex = UTxOIndex.fromSequence <$> listOf genEntry
genUTxOIndex :: forall u. Ord u => Gen u -> Gen (UTxOIndex u)
genUTxOIndex genUTxO = UTxOIndex.fromSequence <$> listOf genEntry
where
genEntry :: Gen (WalletUTxO, TokenBundle)
genEntry = (,) <$> genWalletUTxO <*> genTokenBundleSmallRangePositive

genWalletUTxO :: Gen WalletUTxO
genWalletUTxO = uncurry WalletUTxO <$> genSized2 genTxIn genAddress
genEntry :: Gen (u, TokenBundle)
genEntry = (,) <$> genUTxO <*> genTokenBundleSmallRangePositive

shrinkUTxOIndex :: UTxOIndex WalletUTxO -> [UTxOIndex WalletUTxO]
shrinkUTxOIndex =
shrinkUTxOIndex :: forall u. Ord u => (u -> [u]) -> UTxOIndex u -> [UTxOIndex u]
shrinkUTxOIndex shrinkUTxO =
shrinkMapBy UTxOIndex.fromSequence UTxOIndex.toList (shrinkList shrinkEntry)
where
shrinkEntry :: (WalletUTxO, TokenBundle) -> [(WalletUTxO, TokenBundle)]
shrinkEntry :: (u, TokenBundle) -> [(u, TokenBundle)]
shrinkEntry = genericRoundRobinShrink
<@> shrinkWalletUTxO
<@> shrinkUTxO
<:> shrinkTokenBundleSmallRangePositive
<:> Nil

shrinkWalletUTxO :: WalletUTxO -> [WalletUTxO]
shrinkWalletUTxO = genericRoundRobinShrink
<@> shrinkTxIn
<:> shrinkAddress
<:> Nil

--------------------------------------------------------------------------------
-- Large indices
--------------------------------------------------------------------------------

genUTxOIndexLarge :: Gen (UTxOIndex WalletUTxO)
genUTxOIndexLarge = genUTxOIndexLargeN =<< choose (1024, 4096)
genUTxOIndexLarge :: Ord u => Gen u -> Gen (UTxOIndex u)
genUTxOIndexLarge genUTxO =
genUTxOIndexLargeN genUTxO =<< choose (1024, 4096)

genUTxOIndexLargeN :: Int -> Gen (UTxOIndex WalletUTxO)
genUTxOIndexLargeN n = UTxOIndex.fromSequence <$> replicateM n genEntry
genUTxOIndexLargeN :: forall u. Ord u => Gen u -> Int -> Gen (UTxOIndex u)
genUTxOIndexLargeN genUTxO n = UTxOIndex.fromSequence <$> replicateM n genEntry
where
genEntry :: Gen (WalletUTxO, TokenBundle)
genEntry = (,) <$> genWalletUTxO <*> genTokenBundleSmallRangePositive

genWalletUTxO :: Gen WalletUTxO
genWalletUTxO = WalletUTxO <$> genTxInLargeRange <*> genAddress
genEntry :: Gen (u, TokenBundle)
genEntry = (,) <$> genUTxO <*> genTokenBundleSmallRangePositive
46 changes: 23 additions & 23 deletions lib/core/src/Cardano/Wallet/Primitive/Types/UTxOSelection/Gen.hs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}

module Cardano.Wallet.Primitive.Types.UTxOSelection.Gen
Expand All @@ -10,8 +11,6 @@ module Cardano.Wallet.Primitive.Types.UTxOSelection.Gen

import Prelude

import Cardano.Wallet.CoinSelection
( WalletUTxO )
import Cardano.Wallet.Primitive.Types.UTxOIndex.Gen
( genUTxOIndex, shrinkUTxOIndex )
import Cardano.Wallet.Primitive.Types.UTxOSelection
Expand All @@ -29,39 +28,40 @@ import qualified Cardano.Wallet.Primitive.Types.UTxOSelection as UTxOSelection
-- Selections that may be empty
--------------------------------------------------------------------------------

coarbitraryWalletUTxO :: WalletUTxO -> Gen a -> Gen a
coarbitraryWalletUTxO = coarbitrary . show
coarbitraryUTxO :: Show u => u -> Gen a -> Gen a
coarbitraryUTxO = coarbitrary . show

genWalletUTxOFunction :: Gen a -> Gen (WalletUTxO -> a)
genWalletUTxOFunction = genFunction coarbitraryWalletUTxO
genUTxOFunction :: Show u => Gen a -> Gen (u -> a)
genUTxOFunction = genFunction coarbitraryUTxO

genUTxOSelection :: Gen (UTxOSelection WalletUTxO)
genUTxOSelection = UTxOSelection.fromIndexFiltered
<$> genFilter
<*> genUTxOIndex
genUTxOSelection :: forall u. (Ord u, Show u) => Gen u -> Gen (UTxOSelection u)
genUTxOSelection genUTxO = UTxOSelection.fromIndexFiltered
<$> genUTxOFilter
<*> genUTxOIndex genUTxO
where
genFilter :: Gen (WalletUTxO -> Bool)
genFilter = genWalletUTxOFunction (arbitrary @Bool)
genUTxOFilter :: Gen (u -> Bool)
genUTxOFilter = genUTxOFunction (arbitrary @Bool)

shrinkUTxOSelection :: UTxOSelection WalletUTxO -> [UTxOSelection WalletUTxO]
shrinkUTxOSelection =
shrinkUTxOSelection
:: Ord u => (u -> [u]) -> (UTxOSelection u -> [UTxOSelection u])
shrinkUTxOSelection shrinkUTxO =
shrinkMapBy UTxOSelection.fromIndexPair UTxOSelection.toIndexPair $
liftShrink2
shrinkUTxOIndex
shrinkUTxOIndex
(shrinkUTxOIndex shrinkUTxO)
(shrinkUTxOIndex shrinkUTxO)

--------------------------------------------------------------------------------
-- Selections that are non-empty
--------------------------------------------------------------------------------

genUTxOSelectionNonEmpty :: Gen (UTxOSelectionNonEmpty WalletUTxO)
genUTxOSelectionNonEmpty =
genUTxOSelection `suchThatMap` UTxOSelection.toNonEmpty
genUTxOSelectionNonEmpty
:: (Ord u, Show u) => Gen u -> Gen (UTxOSelectionNonEmpty u)
genUTxOSelectionNonEmpty genUTxO =
genUTxOSelection genUTxO `suchThatMap` UTxOSelection.toNonEmpty

shrinkUTxOSelectionNonEmpty
:: UTxOSelectionNonEmpty WalletUTxO
-> [UTxOSelectionNonEmpty WalletUTxO]
shrinkUTxOSelectionNonEmpty
:: Ord u => (u -> [u]) -> (UTxOSelectionNonEmpty u -> [UTxOSelectionNonEmpty u])
shrinkUTxOSelectionNonEmpty shrinkUTxO
= mapMaybe UTxOSelection.toNonEmpty
. shrinkUTxOSelection
. shrinkUTxOSelection shrinkUTxO
. UTxOSelection.fromNonEmpty
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ import Cardano.Numeric.Util
( inAscendingPartialOrder )
import Cardano.Wallet.CoinSelection
( WalletSelectionContext, WalletUTxO (..) )
import Cardano.Wallet.CoinSelection.Gen
( genWalletUTxO
, genWalletUTxOFunction
, genWalletUTxOLargeRange
, shrinkWalletUTxO
)
import Cardano.Wallet.CoinSelection.Internal.Balance
( AssetCount (..)
, BalanceInsufficientError (..)
Expand Down Expand Up @@ -214,7 +220,6 @@ import Test.QuickCheck
, arbitraryBoundedEnum
, checkCoverage
, choose
, coarbitrary
, conjoin
, counterexample
, cover
Expand All @@ -240,7 +245,7 @@ import Test.QuickCheck
import Test.QuickCheck.Classes
( eqLaws, ordLaws )
import Test.QuickCheck.Extra
( genFunction, genericRoundRobinShrink, report, verify, (<:>), (<@>) )
( genericRoundRobinShrink, report, verify, (<:>), (<@>) )
import Test.QuickCheck.Monadic
( PropertyM (..), assert, monadicIO, monitor, run )
import Test.Utils.Laws
Expand Down Expand Up @@ -654,7 +659,7 @@ shrinkSelectionParams
-> [SelectionParams WalletSelectionContext]
shrinkSelectionParams = genericRoundRobinShrink
<@> shrinkList shrinkOutput
<:> shrinkUTxOSelection
<:> shrinkUTxOSelection shrinkWalletUTxO
<:> shrinkCoin
<:> shrinkCoin
<:> shrinkTokenMap
Expand Down Expand Up @@ -868,7 +873,7 @@ prop_performSelection_huge = ioProperty $
-- the cost of re-generating it on every pass. This will still generate
-- interesting cases, since selection within that large index is random.
property . prop_performSelection_huge_inner
<$> generate (genUTxOIndexLargeN 50000)
<$> generate (genUTxOIndexLargeN genWalletUTxOLargeRange 50000)

prop_performSelection_huge_inner
:: UTxOIndex WalletUTxO
Expand Down Expand Up @@ -4371,16 +4376,6 @@ unitTests lbl cases =
forM_ (zip [1..] cases) $ \(i, test) ->
it (lbl <> " example #" <> show @Int i) test

--------------------------------------------------------------------------------
-- Wallet UTxO identifiers
--------------------------------------------------------------------------------

coarbitraryWalletUTxO :: WalletUTxO -> Gen a -> Gen a
coarbitraryWalletUTxO = coarbitrary . show

genWalletUTxOFunction :: Gen a -> Gen (WalletUTxO -> a)
genWalletUTxOFunction = genFunction coarbitraryWalletUTxO

--------------------------------------------------------------------------------
-- Arbitrary instances
--------------------------------------------------------------------------------
Expand Down Expand Up @@ -4444,8 +4439,8 @@ instance Arbitrary TxOut where
shrink = shrinkTxOut

instance Arbitrary (UTxOSelection WalletUTxO) where
arbitrary = genUTxOSelection
shrink = shrinkUTxOSelection
arbitrary = genUTxOSelection genWalletUTxO
shrink = shrinkUTxOSelection shrinkWalletUTxO

newtype Large a = Large
{ getLarge :: a }
Expand All @@ -4458,22 +4453,22 @@ newtype Small a = Small
instance Arbitrary (Large (SelectionParams WalletSelectionContext)) where
arbitrary = Large <$> genSelectionParams
(genWalletUTxOFunction (arbitrary @Bool))
(genUTxOIndexLarge)
(genUTxOIndexLarge genWalletUTxOLargeRange)
shrink = shrinkMapBy Large getLarge shrinkSelectionParams

instance Arbitrary (Small (SelectionParams WalletSelectionContext)) where
arbitrary = Small <$> genSelectionParams
(genWalletUTxOFunction (arbitrary @Bool))
(genUTxOIndex)
(genUTxOIndex genWalletUTxO)
shrink = shrinkMapBy Small getSmall shrinkSelectionParams

instance Arbitrary (Large (UTxOIndex WalletUTxO)) where
arbitrary = Large <$> genUTxOIndexLarge
shrink = shrinkMapBy Large getLarge shrinkUTxOIndex
arbitrary = Large <$> genUTxOIndexLarge genWalletUTxOLargeRange
shrink = shrinkMapBy Large getLarge (shrinkUTxOIndex shrinkWalletUTxO)

instance Arbitrary (Small (UTxOIndex WalletUTxO)) where
arbitrary = Small <$> genUTxOIndex
shrink = shrinkMapBy Small getSmall shrinkUTxOIndex
arbitrary = Small <$> genUTxOIndex genWalletUTxO
shrink = shrinkMapBy Small getSmall (shrinkUTxOIndex shrinkWalletUTxO)

instance Arbitrary Coin where
arbitrary = genCoinPositive
Expand Down
Loading