Skip to content

Commit 26ea2fc

Browse files
authored
Merge pull request #141 from mlabs-haskell/experimental-config
Configurable slot length and epoch size
2 parents dc5c944 + a26b2c7 commit 26ea2fc

26 files changed

+2893
-228
lines changed

CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,15 @@ This format is based on [Keep A Changelog](https://keepachangelog.com/en/1.0.0).
44

55
## Unreleased
66

7+
- Wallets with Base Address support
8+
- Lookups for wallets in tasty integration
9+
10+
## [1.2.0] - 2022-10-21
11+
712
### Added
813

914
- `Plutip` configuration
15+
- Ability to set slot length and epoch size
1016
- Ability to add custom keys constant across runs, e.g. to use them as extra signers
1117
- Ability to set custom file where relay node log can be saved after tests run
1218
- Ability to set to set custom port for `chain-idex`

Makefile

+4-3
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,14 @@ requires_nix_shell:
3939
FOURMOLU_EXTENSIONS := -o -XTypeApplications -o -XTemplateHaskell -o -XImportQualifiedPost -o -XPatternSynonyms -o -fplugin=RecordDotPreprocessor
4040

4141
# Add folder locations to the list to be reformatted.
42+
excluded := src/Test/Plutip/Internal/Cluster.hs
4243
format:
4344
@ echo "> Formatting all .hs files"
44-
fourmolu $(FOURMOLU_EXTENSIONS) --mode inplace --check-idempotence $$(find src/ test/ plutip-server/ -iregex ".*.hs")
45+
fourmolu $(FOURMOLU_EXTENSIONS) --mode inplace --check-idempotence $$(find src/ test/ plutip-server/ local-cluster/ -iregex ".*.hs" -not -path "${excluded}")
4546

4647
format_check:
4748
@ echo "> Checking format of all .hs files"
48-
fourmolu $(FOURMOLU_EXTENSIONS) --mode check --check-idempotence $$(find src/ test/ plutip-server/ -iregex ".*.hs")
49+
fourmolu $(FOURMOLU_EXTENSIONS) --mode check --check-idempotence $$(find src/ test/ plutip-server/ local-cluster/ -iregex ".*.hs" -not -path "${excluded}" )
4950

5051
NIX_SOURCES := $(shell fd -enix)
5152

@@ -64,4 +65,4 @@ cabalfmt_check: requires_nix_shell
6465
cabal-fmt --check $(CABAL_SOURCES)
6566

6667
lint: requires_nix_shell
67-
hlint $$(find src/ -iregex ".*.hs") $$(find test/ -iregex ".*.hs")
68+
hlint $$(find src/ -iregex ".*.hs" -not -path "${excluded}") $$(find test/ -iregex ".*.hs")

README.md

+4
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,7 @@ NOTE: This branch launches local network in `Vasil`. It was tested with node `1.
4949

5050
* [Tweaking local network](./docs/tweaking-network.md)
5151
* [Regenerating network configs](./docs/regenerate-network-configs.md)
52+
53+
## Maintenance
54+
55+
* [Important notes on updating `cardano-wallet` dependency](./docs/cardano-wallet-update.md)

docs/cardano-wallet-update.md

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Cluster launcher update
2+
3+
`Plutip` heavily relies on local cluster testing framework from `cardano-wallet`.
4+
5+
Initially, framework was used as-is, but in order to add to Plutip ability to set slot length and epoch size, module `Cluster.hs` was copied from `cardano-wallet` to Plutip's codebase and adjusted to make this settings possible. So in case of updating `cardano-wallet` dependency be sure that original `Cluster.hs` and Plutip's one differs only in expected way.
6+
7+
At the moment all changes are related to adding `ExtraConfig` to necessary ADTs and functions in Plutip's version of `Cluster.hs` and difference with the original is pretty small.

docs/tweaking-network.md

+8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# Tweaking private network
22

3+
## Setting slot length and epoch size
4+
5+
It is possible to set slot length and epoch size while starting network from haskell via `PlutipConfig` - `extraConfig :: ExtraConfig` holds corresponding fields.
6+
7+
For setting parameters while launching `local-cluster` executable see `--slot-len` and `--epoch-size` options in [documentation](../local-cluster/README.md).
8+
9+
## Tweaking cluster config files
10+
311
It is possible to change some settings of local network that Plutip starts. By default Plutip uses node config, genesis files and etc. from `cluster-data` directory.
412

513
It is not advised to change anything in `cluster-data`. Better way will be to copy `cluster-data` to desired location, change what is needed and then point Plutip to this custom directory via `PlutipConfig.clusterDataDir` field when calling `withConfiguredCluster` or `startCluster`.

hie.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,5 @@ cradle:
66
component: "test-suite:plutip-tests"
77
- path: "./local-cluster/"
88
component: "exe:local-cluster"
9+
- path: "./plutip-server/"
10+
component: "exe:plutip-server"

local-cluster/Main.hs

+78-27
Original file line numberDiff line numberDiff line change
@@ -5,42 +5,56 @@
55

66
module Main (main) where
77

8+
import Cardano.Ledger.Slot (EpochSize (EpochSize))
89
import Control.Applicative (optional, (<**>))
910
import Control.Monad (forM_, replicateM, void)
1011
import Control.Monad.IO.Class (liftIO)
11-
import Control.Monad.Reader (ReaderT (ReaderT))
12+
import Control.Monad.Reader (ReaderT (ReaderT), ask)
1213
import Data.Default (def)
14+
import Data.Time (NominalDiffTime)
15+
import GHC.Natural (Natural)
16+
import GHC.Word (Word64)
1317
import Numeric.Positive (Positive)
1418
import Options.Applicative (Parser, helper, info)
1519
import Options.Applicative qualified as Options
16-
import Test.Plutip.Config
17-
( PlutipConfig (clusterWorkingDir),
18-
WorkingDirectory (Fixed, Temporary),
19-
)
20-
import Test.Plutip.Internal.BotPlutusInterface.Wallet (addSomeWalletDir, walletPkh)
21-
import Test.Plutip.Internal.Types (nodeSocket)
22-
import Test.Plutip.LocalCluster
23-
( mkMainnetAddress,
24-
startCluster,
25-
stopCluster,
26-
waitSeconds,
27-
)
28-
import GHC.Natural (Natural)
20+
import Test.Plutip.Config (
21+
PlutipConfig (clusterWorkingDir, extraConfig),
22+
WorkingDirectory (Fixed, Temporary),
23+
)
24+
import Test.Plutip.Internal.BotPlutusInterface.Wallet (
25+
addSomeWalletDir,
26+
cardanoMainnetAddress,
27+
walletPkh,
28+
)
29+
import Test.Plutip.Internal.Cluster.Extra.Types (
30+
ExtraConfig (ExtraConfig),
31+
)
32+
import Test.Plutip.Internal.Types (ClusterEnv, nodeSocket)
33+
import Test.Plutip.LocalCluster (
34+
BpiWallet,
35+
mkMainnetAddress,
36+
startCluster,
37+
stopCluster,
38+
)
39+
import Test.Plutip.Tools.Cluster (awaitAddressFunded)
2940

3041
main :: IO ()
3142
main = do
3243
config <- Options.execParser (info (pClusterConfig <**> helper) mempty)
3344
case totalAmount config of
3445
Left e -> error e
3546
Right amt -> do
36-
let CWalletConfig {numWallets, dirWallets, numUtxos, workDir} = config
47+
let ClusterConfig {numWallets, dirWallets, numUtxos, workDir, slotLength, epochSize} = config
3748
workingDir = maybe Temporary (`Fixed` False) workDir
38-
plutipConfig = def {clusterWorkingDir = workingDir}
49+
50+
exctraCong = ExtraConfig slotLength epochSize
51+
plutipConfig = def {clusterWorkingDir = workingDir, extraConfig = exctraCong}
3952

4053
putStrLn "Starting cluster..."
4154
(st, _) <- startCluster plutipConfig $ do
4255
ws <- initWallets numWallets numUtxos amt dirWallets
43-
waitSeconds 2 -- let wallet Tx finish, it can take more time with bigger slot length
56+
liftIO $ putStrLn "Waiting for wallets to be funded..."
57+
awaitFunds ws (ceiling slotLength)
4458

4559
separate
4660
liftIO $ forM_ (zip ws [(1 :: Int) ..]) printWallet
@@ -58,7 +72,7 @@ main = do
5872

5973
separate = liftIO $ putStrLn "\n------------\n"
6074

61-
totalAmount :: CWalletConfig -> Either String Positive
75+
totalAmount :: ClusterConfig -> Either String Positive
6276
totalAmount cwc =
6377
case toAda (adaAmount cwc) + lvlAmount cwc of
6478
0 -> Left "One of --ada or --lovelace arguments should not be 0"
@@ -74,6 +88,15 @@ main = do
7488

7589
toAda = (* 1_000_000)
7690

91+
-- waits for the last wallet to be funded
92+
awaitFunds :: [BpiWallet] -> Int -> ReaderT ClusterEnv IO ()
93+
awaitFunds ws delay = do
94+
env <- ask
95+
let lastWallet = last ws
96+
liftIO $ do
97+
putStrLn "Waiting till all wallets will be funded..."
98+
awaitAddressFunded env delay (cardanoMainnetAddress lastWallet)
99+
77100
pnumWallets :: Parser Int
78101
pnumWallets =
79102
Options.option
@@ -134,24 +157,52 @@ pWorkDir =
134157
<> Options.metavar "FILEPATH"
135158
)
136159

137-
pClusterConfig :: Parser CWalletConfig
160+
pSlotLen :: Parser NominalDiffTime
161+
pSlotLen =
162+
Options.option
163+
Options.auto
164+
( Options.long "slot-len"
165+
<> Options.short 's'
166+
<> Options.metavar "SLOT_LEN"
167+
<> Options.value 0.2
168+
)
169+
170+
pEpochSize :: Parser EpochSize
171+
pEpochSize =
172+
EpochSize <$> wordParser
173+
where
174+
wordParser :: Parser Word64
175+
wordParser =
176+
Options.option
177+
Options.auto
178+
( Options.long "epoch-size"
179+
<> Options.short 'e'
180+
<> Options.metavar "EPOCH_SIZE"
181+
<> Options.value 160
182+
)
183+
184+
pClusterConfig :: Parser ClusterConfig
138185
pClusterConfig =
139-
CWalletConfig
186+
ClusterConfig
140187
<$> pnumWallets
141188
<*> pdirWallets
142189
<*> padaAmount
143190
<*> plvlAmount
144191
<*> pnumUtxos
145192
<*> pWorkDir
193+
<*> pSlotLen
194+
<*> pEpochSize
146195

147196
-- | Basic info about the cluster, to
148197
-- be used by the command-line
149-
data CWalletConfig = CWalletConfig
150-
{ numWallets :: Int,
151-
dirWallets :: Maybe FilePath,
152-
adaAmount :: Natural,
153-
lvlAmount :: Natural,
154-
numUtxos :: Int,
155-
workDir :: Maybe FilePath
198+
data ClusterConfig = ClusterConfig
199+
{ numWallets :: Int
200+
, dirWallets :: Maybe FilePath
201+
, adaAmount :: Natural
202+
, lvlAmount :: Natural
203+
, numUtxos :: Int
204+
, workDir :: Maybe FilePath
205+
, slotLength :: NominalDiffTime
206+
, epochSize :: EpochSize
156207
}
157208
deriving stock (Show, Eq)

local-cluster/README.md

+2
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ Full | Short | Description
3838
--lovelace AMOUNT | -l AMOUNT | Puts `AMOUNT` Lovelace into each UTxO in every wallet created, in addition to the amount specified by the `--ada` argument. Note that if you don't specify the amount of ADA to add, the total amount will be 10,000 ADA + `AMOUNT` lovelace. <br /> Note that both `--ada` and `--lovelace` can not be 0 at the same time.
3939
--utxos NUM | -u NUM | Create `NUM` UTxOs in each wallet created. Note that each UTxO created has the amount of ADA determined by the `--ada` and `--lovelace` arguments.
4040
--working-dir /path/ | -w /path/ | This determines where the node database, chain-index database, and bot-plutus-interface files will be stored for a running cluster. If specified, this will store cluster data in the provided path (can be relative or absolute), the files will be deleted on cluster shutdown by default. Otherwise, the cluster data is stored in a temporary directory and will be deleted on cluster shutdown.
41+
--slot-len SECONDS | -s SECONDS | Sets slot length of created network, is seconds. E.g. `--slot-len 1s`, `-s 0.2s`. <br /> Addition of `s` is important for correct parsing of this option.
42+
--epoch-size NUM | -s NUM | Sets epoch size of created network, is slots.
4143

4244
## Making own local network launcher
4345

plutip-server/Api/Handlers.hs

+29-8
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ module Api.Handlers (
55

66
import Cardano.Api (serialiseToCBOR)
77
import Cardano.Launcher.Node (nodeSocketFile)
8-
import Cardano.Wallet.Shelley.Launch.Cluster (RunningNode (RunningNode))
8+
9+
-- import Cardano.Wallet.Shelley.Launch.Cluster (RunningNode (RunningNode))
10+
911
import Control.Concurrent.MVar (isEmptyMVar, putMVar, takeMVar)
1012
import Control.Monad (unless)
1113
import Control.Monad.Except (runExceptT, throwError)
@@ -19,12 +21,14 @@ import Data.Text.Encoding qualified as Text
1921
import Data.Traversable (for)
2022
import System.Directory (doesFileExist)
2123
import System.FilePath (replaceFileName)
22-
import Test.Plutip.Config (chainIndexPort, relayNodeLogs)
24+
import Test.Plutip.Config (PlutipConfig (extraConfig), chainIndexPort, relayNodeLogs)
2325
import Test.Plutip.Internal.BotPlutusInterface.Setup (keysDir)
24-
import Test.Plutip.Internal.BotPlutusInterface.Wallet (BpiWallet (signKey), addSomeWallet)
26+
import Test.Plutip.Internal.BotPlutusInterface.Wallet (BpiWallet (signKey), addSomeWallet, cardanoMainnetAddress)
27+
import Test.Plutip.Internal.Cluster (RunningNode (RunningNode))
28+
import Test.Plutip.Internal.Cluster.Extra.Types (ExtraConfig (ExtraConfig))
2529
import Test.Plutip.Internal.LocalCluster (startCluster, stopCluster)
2630
import Test.Plutip.Internal.Types (ClusterEnv (runningNode))
27-
import Test.Plutip.LocalCluster (waitSeconds)
31+
import Test.Plutip.Tools.Cluster (awaitAddressFunded)
2832
import Types (
2933
AppM,
3034
ClusterStartupFailureReason (
@@ -43,7 +47,12 @@ import Types (
4347
Lovelace (unLovelace),
4448
PrivateKey,
4549
ServerOptions (ServerOptions, nodeLogs),
46-
StartClusterRequest (StartClusterRequest, keysToGenerate),
50+
StartClusterRequest (
51+
StartClusterRequest,
52+
epochSize,
53+
keysToGenerate,
54+
slotLength
55+
),
4756
StartClusterResponse (
4857
ClusterStartupFailure,
4958
ClusterStartupSuccess
@@ -55,7 +64,7 @@ import Types (
5564
startClusterHandler :: ServerOptions -> StartClusterRequest -> AppM StartClusterResponse
5665
startClusterHandler
5766
ServerOptions {nodeLogs}
58-
StartClusterRequest {keysToGenerate} = interpret $ do
67+
StartClusterRequest {slotLength, epochSize, keysToGenerate} = interpret $ do
5968
-- Check that lovelace amounts are positive
6069
for_ keysToGenerate $ \lovelaceAmounts -> do
6170
for_ lovelaceAmounts $ \lovelaces -> do
@@ -64,7 +73,9 @@ startClusterHandler
6473
statusMVar <- asks status
6574
isClusterDown <- liftIO $ isEmptyMVar statusMVar
6675
unless isClusterDown $ throwError ClusterIsRunningAlready
67-
let cfg = def {relayNodeLogs = nodeLogs, chainIndexPort = Nothing}
76+
let extraConf = ExtraConfig slotLength epochSize
77+
cfg = def {relayNodeLogs = nodeLogs, chainIndexPort = Nothing, extraConfig = extraConf}
78+
6879
(statusTVar, res@(clusterEnv, _)) <- liftIO $ startCluster cfg setup
6980
liftIO $ putMVar statusMVar statusTVar
7081
let nodeConfigPath = getNodeConfigFile clusterEnv
@@ -85,7 +96,8 @@ startClusterHandler
8596
wallets <- do
8697
for keysToGenerate $ \lovelaceAmounts -> do
8798
addSomeWallet (fromInteger . unLovelace <$> lovelaceAmounts)
88-
waitSeconds 2 -- wait for transactions to submit
99+
liftIO $ putStrLn "Waiting for wallets to be funded..."
100+
awaitFunds wallets 2
89101
pure (env, wallets)
90102
getNodeSocketFile (runningNode -> RunningNode conn _ _ _) = nodeSocketFile conn
91103
getNodeConfigFile =
@@ -95,6 +107,15 @@ startClusterHandler
95107
getWalletPrivateKey = Text.decodeUtf8 . Base16.encode . serialiseToCBOR . signKey
96108
interpret = fmap (either ClusterStartupFailure id) . runExceptT
97109

110+
-- waits for the last wallet to be funded
111+
awaitFunds :: [BpiWallet] -> Int -> ReaderT ClusterEnv IO ()
112+
awaitFunds ws delay = do
113+
env <- ask
114+
let lastWallet = last ws
115+
liftIO $ do
116+
putStrLn $ "Waiting till all wallets will be funded..."
117+
awaitAddressFunded env delay (cardanoMainnetAddress lastWallet)
118+
98119
stopClusterHandler :: StopClusterRequest -> AppM StopClusterResponse
99120
stopClusterHandler StopClusterRequest = do
100121
statusMVar <- asks status

plutip-server/Types.hs

+8-9
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ module Types (
1111
PlutipServerError (PlutipServerError),
1212
PrivateKey,
1313
ServerOptions (ServerOptions, nodeLogs, port),
14-
StartClusterRequest (StartClusterRequest, keysToGenerate),
14+
StartClusterRequest (StartClusterRequest, keysToGenerate, slotLength, epochSize),
1515
StartClusterResponse (
1616
ClusterStartupSuccess,
1717
ClusterStartupFailure
@@ -27,23 +27,20 @@ module Types (
2727
StopClusterResponse (StopClusterSuccess, StopClusterFailure),
2828
) where
2929

30+
import Cardano.Ledger.Slot (EpochSize)
3031
import Control.Concurrent.MVar (MVar)
3132
import Control.Monad.Catch (Exception, MonadThrow)
3233
import Control.Monad.IO.Class (MonadIO)
3334
import Control.Monad.Reader (MonadReader, ReaderT)
3435
import Data.Aeson (FromJSON, ToJSON, parseJSON)
3536
import Data.Kind (Type)
3637
import Data.Text (Text)
38+
import Data.Time (NominalDiffTime)
3739
import GHC.Generics (Generic)
3840
import Network.Wai.Handler.Warp (Port)
3941
import Test.Plutip.Internal.BotPlutusInterface.Wallet (BpiWallet)
4042
import Test.Plutip.Internal.LocalCluster (
41-
ClusterStatus (
42-
ClusterClosed,
43-
ClusterClosing,
44-
ClusterStarted,
45-
ClusterStarting
46-
),
43+
ClusterStatus,
4744
)
4845
import Test.Plutip.Internal.Types (ClusterEnv)
4946
import UnliftIO.STM (TVar)
@@ -97,8 +94,10 @@ instance FromJSON Lovelace where
9794
then fail "Lovelace value must not be negative"
9895
else pure $ Lovelace value
9996

100-
newtype StartClusterRequest = StartClusterRequest
101-
{ -- | Lovelace amounts for each UTXO of each wallet
97+
data StartClusterRequest = StartClusterRequest
98+
{ slotLength :: NominalDiffTime
99+
, epochSize :: EpochSize
100+
, -- | Lovelace amounts for each UTXO of each wallet
102101
keysToGenerate :: [[Lovelace]]
103102
}
104103
deriving stock (Show, Eq, Generic)

0 commit comments

Comments
 (0)