Skip to content

Commit

Permalink
Update docs.
Browse files Browse the repository at this point in the history
  • Loading branch information
zmrocze committed Sep 26, 2022
1 parent 43785cd commit 9b33876
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 50 deletions.
13 changes: 8 additions & 5 deletions docs/interactive-plutip.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,11 @@ setup = do
waitSeconds 2
pure (env, ownWallet)

addWalletWithAdas :: [Ada] -> ReaderT ClusterEnv IO BpiWallet
addWalletWithAdas = addSomeWallet . map (fromInteger . Ada.toLovelace)
addWalletWithAdas :: [Ada] -> ReaderT ClusterEnv IO (BpiWallet k)
addWalletWithAdas funds = addSomeWallet $ testWallet'
(map (fromInteger . Ada.toLovelace) funds)
Nothing
(PkhTag ())
```

> Aside: Feel free to choose the amount of ada you want to fund your wallet with. Just remember: `addSomeWallet` takes a list of _lovelace_ amounts. Here, I've actually made my custom `Ada` type as well some helper utilities (not the same as `Plutus.V1.Ledger.Ada` as that is removed in newer `plutus-ledger-api` versions).
Expand Down Expand Up @@ -89,7 +92,7 @@ Once you have that, you can simply use `runContract` from `import Test.Plutip.In
runContract ::
(ToJSON w, Monoid w, MonadIO m) =>
ClusterEnv ->
BpiWallet ->
BpiWallet k ->
Contract w s e a ->
m (ExecutionResult w e a)
```
Expand Down Expand Up @@ -179,7 +182,7 @@ import Test.Plutip.Contract.Types (TestContractConstraints)
newtype ContractRunner = ContrRunner
{ runContr ::
forall w e a.
TestContractConstraints w e a =>
TestContractConstraints w e Int a =>
Contract w EmptySchema e a ->
IO (Either (FailureReason e) a)
}
Expand All @@ -192,7 +195,7 @@ begin = do
setup = do
env <- ask
-- Gotta have all those utxos for the collaterals.
ownWallet <- addWalletWithAdas $ 300 : replicate 50 10
ownWallet <- addWalletWithAdas $ testWallet' (300 : replicate 50 10) Nothing (PkhTag 0)
-- Wait for faucet funds to be added.
waitSeconds 2
pure (env, ownWallet)
Expand Down
82 changes: 52 additions & 30 deletions docs/tasty-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ test =
withConfiguredCluster def -- 1
"Basic integration: launch, add wallet, tx from wallet to wallet" -- 2
$ [ assertExecution "Contract 1" -- 3
(initAda [100,200] <> initLovelace 10_000_000) -- 3.1
(withContract $ \[wallet2pkh] -> someContract) -- 3.2
(initAda (PkhTag (0 :: Int)) [100,200] <> initLovelace (BaseTag 1) 10_000_000) -- 3.1
(withContract $ \wl -> someContract) -- 3.2
[ shouldSucceed -- 3.3
]
]
Expand All @@ -20,8 +20,8 @@ test =
1. Will start the local network with default config (more on configuring below)
2. Description of test group that will be run on current instance of the network
3. Test scenario that will be performed on the local network with it's description. Scenario includes:
1. (3.1.) Initialization of `wallets`. In this case two addresses will be funded: first will have 2 UTxOs with 100 and 200 Ada, second - single UTxO with 10 Ada.
2. (3.2) Execution of "`someContract :: Contract w s e a`". `PaymentPubKeyHash` of *first wallet* will be accessible in `someContract` as "own PaymentPubKeyHash". e.g with `ownFirstPaymentPubKeyHash`. `PaymentPubKeyHash` of *second* initiated wallet is brought into scope by `wallet2pkh` during pattern match on list (more on that below).
1. (3.1.) Initialization of `wallets`. In this case two addresses will be funded: first - enterprise address - will have 2 UTxOs with 100 and 200 Ada, second - base address - single UTxO with 10 Ada.
2. (3.2) Execution of "`someContract :: Contract w s e a`". `PaymentPubKeyHash` of *first wallet* will be accessible in `someContract` as "own PaymentPubKeyHash". e.g with `ownFirstPaymentPubKeyHash`. `PaymentPubKeyHash` of *second* initiated wallet is accessible through `wl :: WalletLookups` (more on that below).
3. (3.3) List of checks or `predicates` which will be performed for the result of `someContract` execution.

It is possible to run several scenarios on single network instance - note that `withConfiguredCluster` accepts list of `assertExecution`'s.
Expand All @@ -33,39 +33,61 @@ It is possible to initialize arbitrary number of `wallets` in second argument of
E.g. if `wallets` initialized like

```haskell
(initAda [100] <> initAda [200] <> initAda [300])
(initAda (PkhTag (0 :: Int)) [100] <> initAda (PkhTag 1) [200] <> initAda (BaseTag 2) [300])
```

we will get 3 funded addresses represented by 3 corresponding `wallets`:

* `PaymentPubKeyHash` of wallet `initAda [100]` will be "own" `PaymentPubKeyHash` for contract executed it test case.
* `PaymentPubKeyHash` of `wallets` `initAda [200]` and `initAda [300]` will be available via lambda argument. I.e.:
* `PaymentPubKeyHash` of wallet 0 will be "own" `PaymentPubKeyHash` for contract executed it test case.
* `PaymentPubKeyHash` of `wallets` 1 and 2 will be available via lambda wallet lookups argument. I.e.:


```haskell
withContract $ \[pkh1, pkh2] -> someContract
withContract $ \wl -> do
PkhWallet pkh1 <- lookupWallet wl (PkhTag 1)
BaseWallet pkh2 spkh2 <- lookupWallet wl (BaseTag 2)
someContract
```

where
note that the lookup return type depends on a query tag. Unfortunetely the type hint is needed to avoid cryptic error message.

* `pkh1` is `PaymentPubKeyHash` of `wallet` `initAda [200]`
* `pkh2` is `PaymentPubKeyHash` of `wallet` `initAda [300]`

`PaymentPubKeyHash` of `wallet` `initAda [100]` is meant to be `pkh0` and not presented in the list.
* `pkh1` is `PaymentPubKeyHash` of `wallet` `initAda (PkhTag 1) [200]`
* `pkh2` is `PaymentPubKeyHash` of `wallet` `initAda (BaseTag 2) [300]` and `spkh2` is its `StakePubKeyHash`

`PaymentPubKeyHash` of `wallet` `initAda (PkhTag 0) [100]` is meant to be `pkh0` and not presented in the lookups.


You can execute a contract with base address as contracts address:
```haskell
(initAda (BaseTag 0) [100])
```

and witness in contract

```haskell
withContract $ \_ -> do
ourAddr :| _ <- Contract.ownAddresses
case addr of
Address (PubKeyCredential ourPkh) (Just (StakingHash (PubKeyCredential ourSpkh))) -> logInfo "This is the address we will get."
_ -> error "Nothing else matters"
```

Use `mustPayToPubKeyAddress` instead of `mustPayToPubKey` when your address has staking keys.

## Executing contracts

It is possible to run arbitrary number of contracts in 3d argument of `assertExecution` using its monadic nature. E.g.:

```haskell
assertExecution "Some description"
( initAda [100])
( initAda (PkhTag ()) [100])
( do
void $
withContract $
\pkhs -> contract1
\wl -> contract1
withContractAs 1 $
\pkhs -> contract2
\wl -> contract2
)
[shouldSucceed]
```
Expand All @@ -85,29 +107,29 @@ For example, consider the following scenario:

```haskell
assertExecution "Some description"
( initAda [100] -- walletA
<> initAda [200] -- walletB
<> initAda [300] -- walletC
( initAda (PkhTag 'a') [100] -- walletA
<> initAda (PkhTag 'b') [200] -- walletB
<> initAda (PkhTag 'c') [300] -- walletC
)
( do
void $
withContractAs 1 $ -- running contract with walletB
\[walletA_PKH, walletC_PKH] -> setupContract1
withContractAs 'b' $ -- running contract with walletB
\wl -> do
wallA <- lookupWallet wl (PkhTag 'a')
setupContract1
void $
withContractAs 2 $ -- running contract with walletC
\[walletA_PKH, walletB_PKH] -> setupContract2
withContract $
\pkhs -> theContract
withContractAs 'c' $ -- running contract with walletC
\wl -> do
wallB <- lookupWallet wl (PkhTag 'b')
setupContract2
withContract $ -- uses first wallet, walletA
\wl -> theContract
)
[shouldSucceed]
```

Under the hood, test runner builds list of wallets like this `[walletA, walletB, walletC]` and by calling `withContractAs` we can refer to an index (0 based) of specific wallet in this list. In that case, `PaymentPubKeyHash` of referenced `wallet` becomes "own" `PaymentPubKeyHash` of the contract, and `PaymentPubKeyHash`'es in argument of lambda will be rearranged. E.g. in case of `withContractAs 1`:

* `PaymentPubKeyHash` of `walletB` will become own `PaymentPubKeyHash`
* argument of lambada will contain `PaymentPubKeyHash`'es of `walletA` and `walletC`.

Actually, `withContract` is just shortcut for `withContractAs 0`.
`withContractAs` asks explicitly for the name of a wallet to be used as contract's.
Instead `withContract` uses the first wallet, first in the order of how the initializations are written.

## Assertions

Expand Down
17 changes: 10 additions & 7 deletions src/Test/Plutip/Contract.hs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@
-- > (initAda (PkhTag 0) 100 <> initAda (PkhTag 1) 101)
-- > ( do
-- > void $ -- run something prior to the contract which result will be checked
-- > withContract $ \wl ->
-- > withContract $ \wl ->
-- > PkhWallet pkh1 <- lookupWallet wl (PkhTag 1)
-- > payTo pkh1 10_000_000
-- > withContractAs 1 $ \wl -> do -- run the contract which result will be checked
Expand Down Expand Up @@ -182,19 +182,22 @@ import Test.Plutip.Contract.Types (
)
import Test.Plutip.Contract.Values (assertValues, valueAt)
import Test.Plutip.Internal.BotPlutusInterface.Lookups (WalletLookups, lookupsMap, makeWalletInfo, makeWalletLookups)
import Test.Plutip.Internal.BotPlutusInterface.Run
( runContract, runContract, runContractWithLogLvl )
import Test.Plutip.Internal.BotPlutusInterface.Run (
runContract,
runContractWithLogLvl,
)
import Test.Plutip.Internal.BotPlutusInterface.Types (
BpiWallet (bwTag),
TestWallet (twExpected, twTag),
TestWallet' (TestWallet'),
TestWallets (unTestWallets),
WalletInfo,
getTag,
ownAddress,
WalletInfo,
)
import Test.Plutip.Internal.BotPlutusInterface.Wallet
( walletPaymentPkh )
import Test.Plutip.Internal.BotPlutusInterface.Wallet (
walletPaymentPkh,
)
import Test.Plutip.Internal.Types (
ClusterEnv,
ExecutionResult (contractLogs, outcome),
Expand Down Expand Up @@ -321,7 +324,7 @@ maybeAddValuesCheck ioRes tws =
f _ _ = error "All left are This and all right are That."
in Map.unionWith f (This <$> mb) (That <$> mc)

-- | Run a contract using the first wallet as own wallet, and return `ExecutionResult`.
-- | Run a contract using the first wallet (in the order of how initializations are written) as own wallet, and return `ExecutionResult`.
-- This could be used by itself, or combined with multiple other contracts.
--
-- @since 0.2
Expand Down
11 changes: 7 additions & 4 deletions src/Test/Plutip/Internal/BotPlutusInterface/Types.hs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,9 @@ import Test.Plutip.Internal.BotPlutusInterface.Keys (KeyPair, StakeKeyPair)

-- | Name for the wallet (k) together with information on what we expect the wallet to be.
-- Used in wallet initialization specifies requested wallet's type, used in lookups specifies expected returned wallet type.
--
--
-- Don't use the same name `k` for two wallets, even with different tag constructors.
-- `t` type parameter is the type of wallet that will be accessible from WalletLookups.
data WalletTag t k where
-- | Base address wallet: has both payment and staking keys
BaseTag :: k -> WalletTag BaseWallet k
Expand Down Expand Up @@ -69,17 +70,19 @@ newtype TestWallets k = TestWallets {unTestWallets :: NonEmpty (TestWallet' k)}

data TestWallet' k = forall t. TestWallet' (TestWallet t k)

-- | Make TestWallet', takes utxo distribution, value assertions and WalletTag as arguments.
testWallet' :: [Positive] -> Maybe (ValueOrdering, Value) -> WalletTag t k -> TestWallet' k
testWallet' twInitDistribiution twExpected twTag = TestWallet' $ TestWallet twInitDistribiution twExpected twTag

data SomeTestWallet' = forall k. SomeTestWallet' (TestWallet' k)

-- | Description of wallet to initialize
data TestWallet t k = TestWallet
{ twInitDistribiution :: [Positive]
, twExpected :: Maybe (ValueOrdering, Value)
, twTag :: WalletTag t k
}

testWallet' :: [Positive] -> Maybe (ValueOrdering, Value) -> WalletTag t k -> TestWallet' k
testWallet' twInitDistribiution twExpected twTag = TestWallet' $ TestWallet twInitDistribiution twExpected twTag

data ValueOrdering = VEq | VGt | VLt | VGEq | VLEq

-- | Value doesn't have an Ord instance, so we cannot use `compare`
Expand Down
4 changes: 2 additions & 2 deletions src/Test/Plutip/LocalCluster.hs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ waitSeconds n = liftIO $ threadDelay (fromEnum n * 1_000_000)
-- > test =
-- > withCluster
-- > "Tests with local cluster"
-- > [ assertExecution "Get utxos" (initAda (PkhTag 0) 100) (withContract $ const getUtxos) [shouldSucceed]]
-- > [ assertExecution "Get utxos" (initAda (PkhTag ()) 100) (withContract $ const getUtxos) [shouldSucceed]]
-- > ...
--
-- @since 0.2
Expand All @@ -78,7 +78,7 @@ withCluster = withConfiguredCluster def
-- > let myConfig = PlutipConfig ...
-- > withConfiguredCluster myConfig
-- > "Tests with local cluster"
-- > [ assertExecution "Get utxos" (initAda (PkhTag 0) 100) (withContract $ const getUtxos) [shouldSucceed]]
-- > [ assertExecution "Get utxos" (initAda (PkhTag ()) 100) (withContract $ const getUtxos) [shouldSucceed]]
-- > ...
--
-- @since 0.2
Expand Down
3 changes: 1 addition & 2 deletions test/Spec/Integration.hs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ import Spec.TestContract.SimpleContracts (
import Spec.TestContract.ValidateTimeRange (failingTimeContract, successTimeContract)
import Test.Plutip.Contract (
ClusterTest,
ValueOrdering (VLt),
assertExecution,
assertExecutionWith,
initAda,
Expand All @@ -45,7 +44,7 @@ import Test.Plutip.Contract (
)
import Test.Plutip.Contract.Types (WalletTag (BaseTag, PkhTag))
import Test.Plutip.Internal.BotPlutusInterface.Lookups (WalletLookups (lookupWallet), lookupAddress)
import Test.Plutip.Internal.BotPlutusInterface.Types (PkhWallet (PkhWallet))
import Test.Plutip.Internal.BotPlutusInterface.Types (PkhWallet (PkhWallet), ValueOrdering (VLt))
import Test.Plutip.Internal.Types (
FailureReason (CaughtException, ContractExecutionError),
isException,
Expand Down

0 comments on commit 9b33876

Please sign in to comment.