From ea52eab066109ba8a48c1455b98e61647284ee8b Mon Sep 17 00:00:00 2001 From: Florent C Date: Fri, 3 Feb 2023 16:58:34 +0100 Subject: [PATCH 01/11] Requalify imports in `Cooked.Wallet` --- cooked-validators/src/Cooked/Wallet.hs | 80 +++++++++++++------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/cooked-validators/src/Cooked/Wallet.hs b/cooked-validators/src/Cooked/Wallet.hs index 00beafc5c..42bc0e0b7 100644 --- a/cooked-validators/src/Cooked/Wallet.hs +++ b/cooked-validators/src/Cooked/Wallet.hs @@ -6,22 +6,22 @@ module Cooked.Wallet where -import qualified Cardano.Api as Api -import qualified Cardano.Api.Shelley as Api -import qualified Cardano.Crypto.Wallet as CWCrypto +import qualified Cardano.Api as Cardano +import qualified Cardano.Api.Shelley as Cardano +import qualified Cardano.Crypto.Wallet as Cardano import Control.Arrow import Data.Default import Data.Function (on) -import qualified Data.Map.Strict as M -import Data.Maybe +import Data.Map.Strict (Map) +import qualified Data.Map.Strict as Map +import Data.Maybe (fromMaybe) import qualified Ledger as Pl import qualified Ledger.Ada as Pl -import qualified Ledger.CardanoWallet as CW +import qualified Ledger.CardanoWallet as Pl import qualified Ledger.Credential as Pl -import qualified Ledger.Crypto as Crypto import qualified Ledger.Tx.CardanoAPI.Internal as Pl import qualified Ledger.Value as Pl -import qualified Plutus.V2.Ledger.Tx as Pl (OutputDatum (..)) +import qualified Plutus.V2.Ledger.Tx as Pl2 (OutputDatum (..)) import qualified PlutusTx as Pl import Unsafe.Coerce @@ -33,40 +33,40 @@ import Unsafe.Coerce -- provide our own wrapper on top of them to make sure that we can easily deal -- changes from Plutus. -type Wallet = CW.MockWallet +type Wallet = Pl.MockWallet -type PrivateKey = CWCrypto.XPrv +type PrivateKey = Cardano.XPrv instance Eq Wallet where - (==) = (==) `on` CW.mwWalletId + (==) = (==) `on` Pl.mwWalletId instance Ord Wallet where - compare = compare `on` CW.mwWalletId + compare = compare `on` Pl.mwWalletId knownWallets :: [Wallet] -knownWallets = CW.knownMockWallets +knownWallets = Pl.knownMockWallets wallet :: Int -> Wallet wallet j | j > 0 && j <= 10 = let i = j - 1 in knownWallets !! i - | otherwise = CW.fromWalletNumber (CW.WalletNumber $ fromIntegral j) + | otherwise = Pl.fromWalletNumber (Pl.WalletNumber $ fromIntegral j) walletPKHashToId :: Pl.PubKeyHash -> Maybe Int -walletPKHashToId = flip M.lookup walletPKHashToIdMap +walletPKHashToId = flip Map.lookup walletPKHashToIdMap where - walletPKHashToIdMap = M.fromList . flip zip [1 ..] . map walletPKHash $ knownWallets + walletPKHashToIdMap = Map.fromList . flip zip [1 ..] . map walletPKHash $ knownWallets walletPK :: Wallet -> Pl.PubKey -walletPK = Pl.unPaymentPubKey . CW.paymentPubKey +walletPK = Pl.unPaymentPubKey . Pl.paymentPubKey walletStakingPK :: Wallet -> Maybe Pl.PubKey -walletStakingPK = fmap Crypto.toPublicKey . walletStakingSK +walletStakingPK = fmap Pl.toPublicKey . walletStakingSK walletPKHash :: Wallet -> Pl.PubKeyHash walletPKHash = Pl.pubKeyHash . walletPK walletStakingPKHash :: Wallet -> Maybe Pl.PubKeyHash -walletStakingPKHash = fmap Crypto.pubKeyHash . walletStakingPK +walletStakingPKHash = fmap Pl.pubKeyHash . walletStakingPK walletAddress :: Wallet -> Pl.Address walletAddress w = @@ -74,28 +74,28 @@ walletAddress w = (Pl.PubKeyCredential $ walletPKHash w) (Pl.StakingHash . Pl.PubKeyCredential <$> walletStakingPKHash w) -walletSK :: CW.MockWallet -> PrivateKey -walletSK = Pl.unPaymentPrivateKey . CW.paymentPrivateKey +walletSK :: Pl.MockWallet -> PrivateKey +walletSK = Pl.unPaymentPrivateKey . Pl.paymentPrivateKey -- Massive hack to be able to open a MockPrivateKey; this is needed because -- the constructor and accessor to MockPrivateKey are not exported. Hence, -- we make an isomorphic datatype, unsafeCoerce to this datatype then extract -- whatever we need from it. -newtype HACK = HACK {please :: CWCrypto.XPrv} +newtype HACK = HACK {please :: Cardano.XPrv} -- | Don't use this; its a hack and will be deprecated once we have time -- to make a PR into plutus exporting the things we need. If you use this anyway, -- make sure that you only apply it to @MockPrivateKey@; the function is polymorphic -- because @MockPrivateKey@ is not exported either; having a dedicated function makes -- it easy to test that this works: check the @Cooked.WalletSpec@ test module. -hackUnMockPrivateKey :: a -> CWCrypto.XPrv +hackUnMockPrivateKey :: a -> Cardano.XPrv hackUnMockPrivateKey = please . unsafeCoerce walletStakingSK :: Wallet -> Maybe PrivateKey -walletStakingSK = fmap hackUnMockPrivateKey . CW.mwStakeKey +walletStakingSK = fmap hackUnMockPrivateKey . Pl.mwStakeKey -toPKHMap :: [Wallet] -> M.Map Pl.PubKeyHash Wallet -toPKHMap ws = M.fromList [(walletPKHash w, w) | w <- ws] +toPKHMap :: [Wallet] -> Map Pl.PubKeyHash Wallet +toPKHMap ws = Map.fromList [(walletPKHash w, w) | w <- ws] -- * Signs a transaction @@ -132,13 +132,13 @@ txAddSignature w = Pl.addSignature' (walletSK w) -- and permanent values. (Remember: 1 Ada = 1000000 Lovelace) -- -- Check the corresponding @Default InitialDistribution@ instance for the default value. -newtype InitialDistribution = InitialDistribution {distribution :: M.Map Wallet [Pl.Value]} +newtype InitialDistribution = InitialDistribution {distribution :: Map Wallet [Pl.Value]} deriving (Eq, Show) -- | An initial distribution is valid if all utxos being created contain at least -- a minimum amount of Ada: 'minAda'. validInitialDistribution :: InitialDistribution -> Bool -validInitialDistribution = all (all hasMinAda . snd) . M.toList . distribution +validInitialDistribution = all (all hasMinAda . snd) . Map.toList . distribution where hasMinAda vl = minAda `Pl.leq` vl @@ -152,19 +152,19 @@ ensureHasMinAda val = val <> Pl.toValue missingAda missingAda = max 0 $ Pl.minAdaTxOut - Pl.fromValue val instance Semigroup InitialDistribution where - (InitialDistribution i) <> (InitialDistribution j) = InitialDistribution $ M.unionWith (<>) i j + (InitialDistribution i) <> (InitialDistribution j) = InitialDistribution $ Map.unionWith (<>) i j instance Monoid InitialDistribution where - mempty = InitialDistribution M.empty + mempty = InitialDistribution Map.empty instance Default InitialDistribution where - def = InitialDistribution $ M.fromList $ zip knownWallets (repeat $ replicate 10 defLovelace) + def = InitialDistribution $ Map.fromList $ zip knownWallets (repeat $ replicate 10 defLovelace) where defLovelace = Pl.lovelaceValueOf 100_000_000 -- | Ensures the distribution is valid by adding any missing Ada to all utxos. distributionFromList :: [(Wallet, [Pl.Value])] -> InitialDistribution -distributionFromList = InitialDistribution . M.fromList . fmap (second $ fmap ensureHasMinAda) +distributionFromList = InitialDistribution . Map.fromList . fmap (second $ fmap ensureHasMinAda) -- | Extension of the default initial distribution with additional value in -- some wallets. @@ -184,18 +184,18 @@ initialTxFor initDist -- initUtxosFor w v = Pl.TxOut $ Api.TxOut addr val Api.TxOutDatumNone Api.ReferenceScriptNone initUtxosFor w v = toPlTxOut @() (walletAddress w) v Nothing - initDist' = M.toList $ distribution initDist + initDist' = Map.toList $ distribution initDist toPlTxOut :: Pl.ToData a => Pl.Address -> Pl.Value -> Maybe a -> Pl.TxOut toPlTxOut addr value datum = toPlTxOut' addr value datum' where - datum' = maybe Pl.NoOutputDatum (Pl.OutputDatumHash . Pl.datumHash . Pl.Datum . Pl.toBuiltinData) datum + datum' = maybe Pl2.NoOutputDatum (Pl2.OutputDatumHash . Pl.datumHash . Pl.Datum . Pl.toBuiltinData) datum - toPlTxOut' :: Pl.Address -> Pl.Value -> Pl.OutputDatum -> Pl.TxOut + toPlTxOut' :: Pl.Address -> Pl.Value -> Pl2.OutputDatum -> Pl.TxOut toPlTxOut' addr value datum = Pl.TxOut $ toCardanoTxOut' addr value datum - toCardanoTxOut' :: Pl.Address -> Pl.Value -> Pl.OutputDatum -> Api.TxOut Api.CtxTx Api.BabbageEra - toCardanoTxOut' addr value datum = Api.TxOut cAddr cValue cDatum Api.ReferenceScriptNone + toCardanoTxOut' :: Pl.Address -> Pl.Value -> Pl2.OutputDatum -> Cardano.TxOut Cardano.CtxTx Cardano.BabbageEra + toCardanoTxOut' addr value datum = Cardano.TxOut cAddr cValue cDatum Cardano.ReferenceScriptNone where fromRight' x = case x of Left err -> error $ show err @@ -204,8 +204,8 @@ initialTxFor initDist cValue = fromRight' $ Pl.toCardanoTxOutValue value cDatum = fromRight' $ Pl.toCardanoTxOutDatum datum - theNetworkId :: Api.NetworkId - theNetworkId = Api.Testnet $ Api.NetworkMagic 42 -- TODO PORT what's magic? + theNetworkId :: Cardano.NetworkId + theNetworkId = Cardano.Testnet $ Cardano.NetworkMagic 42 -- TODO PORT what's magic? valuesForWallet :: InitialDistribution -> Wallet -> [Pl.Value] -valuesForWallet d w = fromMaybe [] $ w `M.lookup` distribution d +valuesForWallet d w = fromMaybe [] $ w `Map.lookup` distribution d From 4c70840e83a150491992561026093dd7a224adf1 Mon Sep 17 00:00:00 2001 From: Florent C Date: Mon, 6 Feb 2023 11:18:47 +0100 Subject: [PATCH 02/11] Reduce pollution of hack to retrieve private keys --- cooked-validators/src/Cooked/Wallet.hs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/cooked-validators/src/Cooked/Wallet.hs b/cooked-validators/src/Cooked/Wallet.hs index 42bc0e0b7..15942317f 100644 --- a/cooked-validators/src/Cooked/Wallet.hs +++ b/cooked-validators/src/Cooked/Wallet.hs @@ -81,18 +81,18 @@ walletSK = Pl.unPaymentPrivateKey . Pl.paymentPrivateKey -- the constructor and accessor to MockPrivateKey are not exported. Hence, -- we make an isomorphic datatype, unsafeCoerce to this datatype then extract -- whatever we need from it. -newtype HACK = HACK {please :: Cardano.XPrv} - --- | Don't use this; its a hack and will be deprecated once we have time --- to make a PR into plutus exporting the things we need. If you use this anyway, --- make sure that you only apply it to @MockPrivateKey@; the function is polymorphic --- because @MockPrivateKey@ is not exported either; having a dedicated function makes --- it easy to test that this works: check the @Cooked.WalletSpec@ test module. -hackUnMockPrivateKey :: a -> Cardano.XPrv -hackUnMockPrivateKey = please . unsafeCoerce +newtype HACK = HACK Cardano.XPrv walletStakingSK :: Wallet -> Maybe PrivateKey walletStakingSK = fmap hackUnMockPrivateKey . Pl.mwStakeKey + where + -- Don't use this; its a hack and will be deprecated once we have time + -- to make a PR into plutus exporting the things we need. If you use this anyway, + -- make sure that you only apply it to @MockPrivateKey@; the function is polymorphic + -- because @MockPrivateKey@ is not exported either; having a dedicated function makes + -- it easy to test that this works: check the @Cooked.WalletSpec@ test module. + hackUnMockPrivateKey :: a -> Cardano.XPrv + hackUnMockPrivateKey x = let HACK y = unsafeCoerce x in y toPKHMap :: [Wallet] -> Map Pl.PubKeyHash Wallet toPKHMap ws = Map.fromList [(walletPKHash w, w) | w <- ws] From db5996b6ad5e72c63d6924cea1fa32c4158dafd0 Mon Sep 17 00:00:00 2001 From: Florent C Date: Mon, 6 Feb 2023 11:19:15 +0100 Subject: [PATCH 03/11] Remove legacy min ada from wallet API --- cooked-validators/src/Cooked/Wallet.hs | 33 +++++--------------------- examples/tests/AuctionSpec.hs | 2 +- 2 files changed, 7 insertions(+), 28 deletions(-) diff --git a/cooked-validators/src/Cooked/Wallet.hs b/cooked-validators/src/Cooked/Wallet.hs index 15942317f..c50cfaf6f 100644 --- a/cooked-validators/src/Cooked/Wallet.hs +++ b/cooked-validators/src/Cooked/Wallet.hs @@ -9,7 +9,6 @@ module Cooked.Wallet where import qualified Cardano.Api as Cardano import qualified Cardano.Api.Shelley as Cardano import qualified Cardano.Crypto.Wallet as Cardano -import Control.Arrow import Data.Default import Data.Function (on) import Data.Map.Strict (Map) @@ -20,7 +19,6 @@ import qualified Ledger.Ada as Pl import qualified Ledger.CardanoWallet as Pl import qualified Ledger.Credential as Pl import qualified Ledger.Tx.CardanoAPI.Internal as Pl -import qualified Ledger.Value as Pl import qualified Plutus.V2.Ledger.Tx as Pl2 (OutputDatum (..)) import qualified PlutusTx as Pl import Unsafe.Coerce @@ -135,22 +133,6 @@ txAddSignature w = Pl.addSignature' (walletSK w) newtype InitialDistribution = InitialDistribution {distribution :: Map Wallet [Pl.Value]} deriving (Eq, Show) --- | An initial distribution is valid if all utxos being created contain at least --- a minimum amount of Ada: 'minAda'. -validInitialDistribution :: InitialDistribution -> Bool -validInitialDistribution = all (all hasMinAda . snd) . Map.toList . distribution - where - hasMinAda vl = minAda `Pl.leq` vl - --- | Proxy to 'Pl.minAdaTxOut' as a 'Pl.Value' -minAda :: Pl.Value -minAda = Pl.toValue Pl.minAdaTxOut - -ensureHasMinAda :: Pl.Value -> Pl.Value -ensureHasMinAda val = val <> Pl.toValue missingAda - where - missingAda = max 0 $ Pl.minAdaTxOut - Pl.fromValue val - instance Semigroup InitialDistribution where (InitialDistribution i) <> (InitialDistribution j) = InitialDistribution $ Map.unionWith (<>) i j @@ -164,7 +146,7 @@ instance Default InitialDistribution where -- | Ensures the distribution is valid by adding any missing Ada to all utxos. distributionFromList :: [(Wallet, [Pl.Value])] -> InitialDistribution -distributionFromList = InitialDistribution . Map.fromList . fmap (second $ fmap ensureHasMinAda) +distributionFromList = InitialDistribution . Map.fromList -- | Extension of the default initial distribution with additional value in -- some wallets. @@ -172,14 +154,11 @@ initialDistribution' :: [(Wallet, [Pl.Value])] -> InitialDistribution initialDistribution' = (def <>) . distributionFromList initialTxFor :: InitialDistribution -> Pl.Tx -initialTxFor initDist - | not $ validInitialDistribution initDist = - error "Not all UTxOs have at least minAda; this initial distribution is unusable" - | otherwise = - mempty - { Pl.txMint = mconcat (map (mconcat . snd) initDist'), - Pl.txOutputs = concatMap (\(w, vs) -> map (initUtxosFor w) vs) initDist' - } +initialTxFor initDist = + mempty + { Pl.txMint = mconcat (map (mconcat . snd) initDist'), + Pl.txOutputs = concatMap (\(w, vs) -> map (initUtxosFor w) vs) initDist' + } where -- initUtxosFor w v = Pl.TxOut $ Api.TxOut addr val Api.TxOutDatumNone Api.ReferenceScriptNone initUtxosFor w v = toPlTxOut @() (walletAddress w) v Nothing diff --git a/examples/tests/AuctionSpec.hs b/examples/tests/AuctionSpec.hs index 0c2b82ff2..09fcf6c0c 100644 --- a/examples/tests/AuctionSpec.hs +++ b/examples/tests/AuctionSpec.hs @@ -53,7 +53,7 @@ bananasIn v = Value.assetClassValueOf v bananaAssetClass -- | initial distribution s.t. everyone owns five bananas testInit :: InitialDistribution -testInit = initialDistribution' [(i, [minAda <> banana 5]) | i <- knownWallets] +testInit = initialDistribution' [(i, [Ada.lovelaceValueOf 2_000_000 <> banana 5]) | i <- knownWallets] -- * Successful single-trace runs From 367a615715458be3b3fe0a1c8696116e52023693 Mon Sep 17 00:00:00 2001 From: Florent C Date: Mon, 6 Feb 2023 11:12:06 +0100 Subject: [PATCH 04/11] Overhaul comments in Wallet --- cooked-validators/src/Cooked/Wallet.hs | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/cooked-validators/src/Cooked/Wallet.hs b/cooked-validators/src/Cooked/Wallet.hs index c50cfaf6f..34aa87192 100644 --- a/cooked-validators/src/Cooked/Wallet.hs +++ b/cooked-validators/src/Cooked/Wallet.hs @@ -27,7 +27,7 @@ import Unsafe.Coerce -- $mockchainwallets -- --- Because the mock wallets from the plutus-apps changes somewhat often, we will +-- Because the mock wallets from the plutus-apps changes somewhat often, we -- provide our own wrapper on top of them to make sure that we can easily deal -- changes from Plutus. @@ -41,46 +41,58 @@ instance Eq Wallet where instance Ord Wallet where compare = compare `on` Pl.mwWalletId +-- | All the wallets corresponding to known Plutus mock wallets. knownWallets :: [Wallet] knownWallets = Pl.knownMockWallets +-- | Wallet corresponding to a given wallet number (or wallet ID) wallet :: Int -> Wallet wallet j | j > 0 && j <= 10 = let i = j - 1 in knownWallets !! i | otherwise = Pl.fromWalletNumber (Pl.WalletNumber $ fromIntegral j) +-- | Retrieves the id of the known wallet that corresponds to a public key hash, if any. +-- +-- @walletPKHashToId (walletPKHash (wallet 3)) == Just 3@ walletPKHashToId :: Pl.PubKeyHash -> Maybe Int walletPKHashToId = flip Map.lookup walletPKHashToIdMap where walletPKHashToIdMap = Map.fromList . flip zip [1 ..] . map walletPKHash $ knownWallets +-- | Retrieves a wallet publik key (PK) walletPK :: Wallet -> Pl.PubKey walletPK = Pl.unPaymentPubKey . Pl.paymentPubKey +-- | Retrieves a wallet's public staking key (PK), if any walletStakingPK :: Wallet -> Maybe Pl.PubKey walletStakingPK = fmap Pl.toPublicKey . walletStakingSK +-- | Retrieves a wallet's public key hash walletPKHash :: Wallet -> Pl.PubKeyHash walletPKHash = Pl.pubKeyHash . walletPK +-- | Retrieves a wallet's public staking key hash, if any walletStakingPKHash :: Wallet -> Maybe Pl.PubKeyHash walletStakingPKHash = fmap Pl.pubKeyHash . walletStakingPK +-- | Retrieves a wallet's address walletAddress :: Wallet -> Pl.Address walletAddress w = Pl.Address (Pl.PubKeyCredential $ walletPKHash w) (Pl.StakingHash . Pl.PubKeyCredential <$> walletStakingPKHash w) +-- | Retrieves a wallet private key (secret key SK) walletSK :: Pl.MockWallet -> PrivateKey walletSK = Pl.unPaymentPrivateKey . Pl.paymentPrivateKey --- Massive hack to be able to open a MockPrivateKey; this is needed because +-- FIXME Massive hack to be able to open a MockPrivateKey; this is needed because -- the constructor and accessor to MockPrivateKey are not exported. Hence, -- we make an isomorphic datatype, unsafeCoerce to this datatype then extract -- whatever we need from it. newtype HACK = HACK Cardano.XPrv +-- | Retrieves a wallet's private staking key (secret key SK), if any walletStakingSK :: Wallet -> Maybe PrivateKey walletStakingSK = fmap hackUnMockPrivateKey . Pl.mwStakeKey where @@ -95,8 +107,7 @@ walletStakingSK = fmap hackUnMockPrivateKey . Pl.mwStakeKey toPKHMap :: [Wallet] -> Map Pl.PubKeyHash Wallet toPKHMap ws = Map.fromList [(walletPKHash w, w) | w <- ws] --- * Signs a transaction - +-- | Signs a transaction txAddSignature :: Wallet -> Pl.Tx -> Pl.Tx txAddSignature w = Pl.addSignature' (walletSK w) @@ -153,6 +164,8 @@ distributionFromList = InitialDistribution . Map.fromList initialDistribution' :: [(Wallet, [Pl.Value])] -> InitialDistribution initialDistribution' = (def <>) . distributionFromList +-- | Bootstraps an initial transaction resulting in a state where wallets +-- posess UTxOs fitting a given 'InitialDistribution' initialTxFor :: InitialDistribution -> Pl.Tx initialTxFor initDist = mempty From 60a2aabf9dbc83a4545177a8525919258abb45e4 Mon Sep 17 00:00:00 2001 From: Florent C Date: Mon, 6 Feb 2023 11:35:21 +0100 Subject: [PATCH 05/11] Remove unused functions from wallet API --- cooked-validators/src/Cooked/Wallet.hs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/cooked-validators/src/Cooked/Wallet.hs b/cooked-validators/src/Cooked/Wallet.hs index 34aa87192..1956bbf6a 100644 --- a/cooked-validators/src/Cooked/Wallet.hs +++ b/cooked-validators/src/Cooked/Wallet.hs @@ -13,7 +13,6 @@ import Data.Default import Data.Function (on) import Data.Map.Strict (Map) import qualified Data.Map.Strict as Map -import Data.Maybe (fromMaybe) import qualified Ledger as Pl import qualified Ledger.Ada as Pl import qualified Ledger.CardanoWallet as Pl @@ -104,9 +103,6 @@ walletStakingSK = fmap hackUnMockPrivateKey . Pl.mwStakeKey hackUnMockPrivateKey :: a -> Cardano.XPrv hackUnMockPrivateKey x = let HACK y = unsafeCoerce x in y -toPKHMap :: [Wallet] -> Map Pl.PubKeyHash Wallet -toPKHMap ws = Map.fromList [(walletPKHash w, w) | w <- ws] - -- | Signs a transaction txAddSignature :: Wallet -> Pl.Tx -> Pl.Tx txAddSignature w = Pl.addSignature' (walletSK w) @@ -198,6 +194,3 @@ initialTxFor initDist = theNetworkId :: Cardano.NetworkId theNetworkId = Cardano.Testnet $ Cardano.NetworkMagic 42 -- TODO PORT what's magic? - -valuesForWallet :: InitialDistribution -> Wallet -> [Pl.Value] -valuesForWallet d w = fromMaybe [] $ w `Map.lookup` distribution d From 81f4d7955ea8e00db9c3bacfc5da6c8daacbbe92 Mon Sep 17 00:00:00 2001 From: Florent C Date: Mon, 6 Feb 2023 11:37:54 +0100 Subject: [PATCH 06/11] Rename smart constructor to `initialDistribution` --- cooked-validators/src/Cooked/Wallet.hs | 4 ++-- examples/tests/AuctionSpec.hs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cooked-validators/src/Cooked/Wallet.hs b/cooked-validators/src/Cooked/Wallet.hs index 1956bbf6a..a20a191ba 100644 --- a/cooked-validators/src/Cooked/Wallet.hs +++ b/cooked-validators/src/Cooked/Wallet.hs @@ -157,8 +157,8 @@ distributionFromList = InitialDistribution . Map.fromList -- | Extension of the default initial distribution with additional value in -- some wallets. -initialDistribution' :: [(Wallet, [Pl.Value])] -> InitialDistribution -initialDistribution' = (def <>) . distributionFromList +initialDistribution :: [(Wallet, [Pl.Value])] -> InitialDistribution +initialDistribution = (def <>) . distributionFromList -- | Bootstraps an initial transaction resulting in a state where wallets -- posess UTxOs fitting a given 'InitialDistribution' diff --git a/examples/tests/AuctionSpec.hs b/examples/tests/AuctionSpec.hs index 09fcf6c0c..821584352 100644 --- a/examples/tests/AuctionSpec.hs +++ b/examples/tests/AuctionSpec.hs @@ -53,7 +53,7 @@ bananasIn v = Value.assetClassValueOf v bananaAssetClass -- | initial distribution s.t. everyone owns five bananas testInit :: InitialDistribution -testInit = initialDistribution' [(i, [Ada.lovelaceValueOf 2_000_000 <> banana 5]) | i <- knownWallets] +testInit = initialDistribution [(i, [Ada.lovelaceValueOf 2_000_000 <> banana 5]) | i <- knownWallets] -- * Successful single-trace runs From 4c518b2d13d5492b4700f3322f27c47f47548633 Mon Sep 17 00:00:00 2001 From: Florent C Date: Mon, 6 Feb 2023 11:40:23 +0100 Subject: [PATCH 07/11] Rename InitialDistribution field to fit convention --- cooked-validators/src/Cooked/Wallet.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cooked-validators/src/Cooked/Wallet.hs b/cooked-validators/src/Cooked/Wallet.hs index a20a191ba..eab3dc20e 100644 --- a/cooked-validators/src/Cooked/Wallet.hs +++ b/cooked-validators/src/Cooked/Wallet.hs @@ -137,7 +137,7 @@ txAddSignature w = Pl.addSignature' (walletSK w) -- and permanent values. (Remember: 1 Ada = 1000000 Lovelace) -- -- Check the corresponding @Default InitialDistribution@ instance for the default value. -newtype InitialDistribution = InitialDistribution {distribution :: Map Wallet [Pl.Value]} +newtype InitialDistribution = InitialDistribution {unInitialDistribution :: Map Wallet [Pl.Value]} deriving (Eq, Show) instance Semigroup InitialDistribution where @@ -172,7 +172,7 @@ initialTxFor initDist = -- initUtxosFor w v = Pl.TxOut $ Api.TxOut addr val Api.TxOutDatumNone Api.ReferenceScriptNone initUtxosFor w v = toPlTxOut @() (walletAddress w) v Nothing - initDist' = Map.toList $ distribution initDist + initDist' = Map.toList $ unInitialDistribution initDist toPlTxOut :: Pl.ToData a => Pl.Address -> Pl.Value -> Maybe a -> Pl.TxOut toPlTxOut addr value datum = toPlTxOut' addr value datum' From a06129f268c92bb84f1d15432f246eb40f26a7bb Mon Sep 17 00:00:00 2001 From: Florent C Date: Mon, 6 Feb 2023 11:44:07 +0100 Subject: [PATCH 08/11] Apply 80 cols limit to Wallet (with reason) --- cooked-validators/src/Cooked/Wallet.hs | 72 ++++++++++++++++---------- 1 file changed, 46 insertions(+), 26 deletions(-) diff --git a/cooked-validators/src/Cooked/Wallet.hs b/cooked-validators/src/Cooked/Wallet.hs index eab3dc20e..a4b0c4b88 100644 --- a/cooked-validators/src/Cooked/Wallet.hs +++ b/cooked-validators/src/Cooked/Wallet.hs @@ -50,13 +50,15 @@ wallet j | j > 0 && j <= 10 = let i = j - 1 in knownWallets !! i | otherwise = Pl.fromWalletNumber (Pl.WalletNumber $ fromIntegral j) --- | Retrieves the id of the known wallet that corresponds to a public key hash, if any. +-- | Retrieves the id of the known wallet that corresponds to a public key +-- hash, if any. -- -- @walletPKHashToId (walletPKHash (wallet 3)) == Just 3@ walletPKHashToId :: Pl.PubKeyHash -> Maybe Int walletPKHashToId = flip Map.lookup walletPKHashToIdMap where - walletPKHashToIdMap = Map.fromList . flip zip [1 ..] . map walletPKHash $ knownWallets + walletPKHashToIdMap = + Map.fromList . flip zip [1 ..] . map walletPKHash $ knownWallets -- | Retrieves a wallet publik key (PK) walletPK :: Wallet -> Pl.PubKey @@ -85,21 +87,22 @@ walletAddress w = walletSK :: Pl.MockWallet -> PrivateKey walletSK = Pl.unPaymentPrivateKey . Pl.paymentPrivateKey --- FIXME Massive hack to be able to open a MockPrivateKey; this is needed because --- the constructor and accessor to MockPrivateKey are not exported. Hence, --- we make an isomorphic datatype, unsafeCoerce to this datatype then extract --- whatever we need from it. +-- FIXME Massive hack to be able to open a MockPrivateKey; this is needed +-- because the constructor and accessor to MockPrivateKey are not exported. +-- Hence, we make an isomorphic datatype, unsafeCoerce to this datatype then +-- extract whatever we need from it. newtype HACK = HACK Cardano.XPrv -- | Retrieves a wallet's private staking key (secret key SK), if any walletStakingSK :: Wallet -> Maybe PrivateKey walletStakingSK = fmap hackUnMockPrivateKey . Pl.mwStakeKey where - -- Don't use this; its a hack and will be deprecated once we have time - -- to make a PR into plutus exporting the things we need. If you use this anyway, - -- make sure that you only apply it to @MockPrivateKey@; the function is polymorphic - -- because @MockPrivateKey@ is not exported either; having a dedicated function makes - -- it easy to test that this works: check the @Cooked.WalletSpec@ test module. + -- Don't use this; its a hack and will be deprecated once we have time to + -- make a PR into plutus exporting the things we need. If you use this + -- anyway, make sure that you only apply it to @MockPrivateKey@; the + -- function is polymorphic because @MockPrivateKey@ is not exported either; + -- having a dedicated function makes it easy to test that this works: check + -- the @Cooked.WalletSpec@ test module. hackUnMockPrivateKey :: a -> Cardano.XPrv hackUnMockPrivateKey x = let HACK y = unsafeCoerce x in y @@ -115,11 +118,11 @@ txAddSignature w = Pl.addSignature' (walletSK w) -- the underlying plutus definitions to make it easer when we have -- to plug our own, if we ever have the need --- | Describes the initial distribution of /UTxOs/ per wallet. This is important since --- transaction validation must specify a /collateral/, hence, wallets must posses more --- than one UTxO to begin with in order to execute a transaction and have some collateral --- option. The @txCollateral@ is transfered to the node operator in case the transaction --- fails to validate. +-- | Describes the initial distribution of /UTxOs/ per wallet. This is +-- important since transaction validation must specify a /collateral/, hence, +-- wallets must posses more than one UTxO to begin with in order to execute a +-- transaction and have some collateral option. The @txCollateral@ is +-- transfered to the node operator in case the transaction fails to validate. -- -- An initial distribution defined by: -- @@ -131,23 +134,31 @@ txAddSignature w = Pl.addSignature' (walletSK w) -- > , (wallet 3 , [Pl.lovelaceValueOf 10000000 <> permanentValue "XYZ" 10]) -- > ] -- --- Specifies a starting state where @wallet 1@ contains two /UTxOs/, one with 42 Ada --- and one with 2 Ada and one "TOK" token; @wallet 2@ contains a single /UTxO/ with 10 Ada and --- @wallet 3@ has 10 Ada and a permanent value. Check #quickvalues for more on quick --- and permanent values. (Remember: 1 Ada = 1000000 Lovelace) +-- Specifies a starting state where @wallet 1@ contains two /UTxOs/, one with +-- 42 Ada and one with 2 Ada and one "TOK" token; @wallet 2@ contains a single +-- /UTxO/ with 10 Ada and @wallet 3@ has 10 Ada and a permanent value. Check +-- #quickvalues for more on quick and permanent values. (Remember: 1 Ada = +-- 1000000 Lovelace) -- --- Check the corresponding @Default InitialDistribution@ instance for the default value. -newtype InitialDistribution = InitialDistribution {unInitialDistribution :: Map Wallet [Pl.Value]} +-- Check the corresponding @Default InitialDistribution@ instance for the +-- default value. +newtype InitialDistribution = InitialDistribution + { unInitialDistribution :: Map Wallet [Pl.Value] + } deriving (Eq, Show) instance Semigroup InitialDistribution where - (InitialDistribution i) <> (InitialDistribution j) = InitialDistribution $ Map.unionWith (<>) i j + (InitialDistribution i) <> (InitialDistribution j) = + InitialDistribution $ Map.unionWith (<>) i j instance Monoid InitialDistribution where mempty = InitialDistribution Map.empty instance Default InitialDistribution where - def = InitialDistribution $ Map.fromList $ zip knownWallets (repeat $ replicate 10 defLovelace) + def = + InitialDistribution $ + Map.fromList $ + zip knownWallets (repeat $ replicate 10 defLovelace) where defLovelace = Pl.lovelaceValueOf 100_000_000 @@ -177,13 +188,22 @@ initialTxFor initDist = toPlTxOut :: Pl.ToData a => Pl.Address -> Pl.Value -> Maybe a -> Pl.TxOut toPlTxOut addr value datum = toPlTxOut' addr value datum' where - datum' = maybe Pl2.NoOutputDatum (Pl2.OutputDatumHash . Pl.datumHash . Pl.Datum . Pl.toBuiltinData) datum + datum' = + maybe + Pl2.NoOutputDatum + ( Pl2.OutputDatumHash + . Pl.datumHash + . Pl.Datum + . Pl.toBuiltinData + ) + datum toPlTxOut' :: Pl.Address -> Pl.Value -> Pl2.OutputDatum -> Pl.TxOut toPlTxOut' addr value datum = Pl.TxOut $ toCardanoTxOut' addr value datum toCardanoTxOut' :: Pl.Address -> Pl.Value -> Pl2.OutputDatum -> Cardano.TxOut Cardano.CtxTx Cardano.BabbageEra - toCardanoTxOut' addr value datum = Cardano.TxOut cAddr cValue cDatum Cardano.ReferenceScriptNone + toCardanoTxOut' addr value datum = + Cardano.TxOut cAddr cValue cDatum Cardano.ReferenceScriptNone where fromRight' x = case x of Left err -> error $ show err From 3b871d33f10ad6ec4f5ca0a004450b0eddab2523 Mon Sep 17 00:00:00 2001 From: Florent C Date: Mon, 6 Feb 2023 11:51:59 +0100 Subject: [PATCH 09/11] Add heading documentation comment to Wallet module --- cooked-validators/src/Cooked/Wallet.hs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cooked-validators/src/Cooked/Wallet.hs b/cooked-validators/src/Cooked/Wallet.hs index a4b0c4b88..5e751d50b 100644 --- a/cooked-validators/src/Cooked/Wallet.hs +++ b/cooked-validators/src/Cooked/Wallet.hs @@ -4,6 +4,12 @@ {-# LANGUAGE TypeSynonymInstances #-} {-# OPTIONS_GHC -Wno-orphans #-} +-- | This module defines convenient wrappers for mock chain wallets (around +-- Plutus mock wallets) and initial distributions (that is the initial state +-- associating a list of UTxOs with some initial values to each known wallet). +-- It also exposes a convenient API to construct wallets and distributions, +-- manipulate them, and fetch information (such as public/private keys and +-- staking keys). module Cooked.Wallet where import qualified Cardano.Api as Cardano From ccc037b44ee61a1339a4e9334ea53d168a3cffc1 Mon Sep 17 00:00:00 2001 From: Florent C Date: Thu, 9 Feb 2023 16:01:42 +0100 Subject: [PATCH 10/11] Apply suggestions from code review Co-authored-by: carlhammann <102371507+carlhammann@users.noreply.github.com> --- cooked-validators/src/Cooked/Wallet.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cooked-validators/src/Cooked/Wallet.hs b/cooked-validators/src/Cooked/Wallet.hs index 5e751d50b..78f798d0f 100644 --- a/cooked-validators/src/Cooked/Wallet.hs +++ b/cooked-validators/src/Cooked/Wallet.hs @@ -32,7 +32,7 @@ import Unsafe.Coerce -- $mockchainwallets -- --- Because the mock wallets from the plutus-apps changes somewhat often, we +-- Because the mock wallets from the plutus-apps change somewhat often, we -- provide our own wrapper on top of them to make sure that we can easily deal -- changes from Plutus. @@ -103,7 +103,7 @@ newtype HACK = HACK Cardano.XPrv walletStakingSK :: Wallet -> Maybe PrivateKey walletStakingSK = fmap hackUnMockPrivateKey . Pl.mwStakeKey where - -- Don't use this; its a hack and will be deprecated once we have time to + -- Don't move this function to outside the where clause; its a hack and will be deprecated once we have time to -- make a PR into plutus exporting the things we need. If you use this -- anyway, make sure that you only apply it to @MockPrivateKey@; the -- function is polymorphic because @MockPrivateKey@ is not exported either; From 6a3a5ccf92ff6e79680a342002e73150b51b2949 Mon Sep 17 00:00:00 2001 From: Florent C Date: Thu, 9 Feb 2023 16:04:48 +0100 Subject: [PATCH 11/11] Remove unreliable comment about a Wallet test --- cooked-validators/src/Cooked/Wallet.hs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/cooked-validators/src/Cooked/Wallet.hs b/cooked-validators/src/Cooked/Wallet.hs index 78f798d0f..85341cbdb 100644 --- a/cooked-validators/src/Cooked/Wallet.hs +++ b/cooked-validators/src/Cooked/Wallet.hs @@ -103,12 +103,11 @@ newtype HACK = HACK Cardano.XPrv walletStakingSK :: Wallet -> Maybe PrivateKey walletStakingSK = fmap hackUnMockPrivateKey . Pl.mwStakeKey where - -- Don't move this function to outside the where clause; its a hack and will be deprecated once we have time to - -- make a PR into plutus exporting the things we need. If you use this - -- anyway, make sure that you only apply it to @MockPrivateKey@; the - -- function is polymorphic because @MockPrivateKey@ is not exported either; - -- having a dedicated function makes it easy to test that this works: check - -- the @Cooked.WalletSpec@ test module. + -- Don't move this function to outside the where clause; its a hack and + -- will be deprecated once we have time to make a PR into plutus exporting + -- the things we need. If you use this anyway, make sure that you only + -- apply it to @MockPrivateKey@; the function is polymorphic because + -- @MockPrivateKey@ is not exported either hackUnMockPrivateKey :: a -> Cardano.XPrv hackUnMockPrivateKey x = let HACK y = unsafeCoerce x in y