Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
### Added

- Added new flag `--tx-generator-config` to specify a partial base configuration for `tx-generator`.
43 changes: 29 additions & 14 deletions cardano-testnet/src/Parsers/Cardano.hs
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,17 @@ import Testnet.Start.Cardano
import Testnet.Start.Types
import Testnet.Types (readNodeLoggingFormat)


optsTestnet :: Parser CardanoTestnetCliOptions
optsTestnet = CardanoTestnetCliOptions
<$> pCardanoTestnetCliOptions
<$> pCardanoTestnetCliOptions RunTestnet
<*> pGenesisOptions
<*> pNodeEnvironment
<*> pUpdateTimestamps

optsCreateTestnet :: Parser CardanoTestnetCreateEnvOptions
optsCreateTestnet = CardanoTestnetCreateEnvOptions
<$> pCardanoTestnetCliOptions
<$> pCardanoTestnetCliOptions ConfigOnly
<*> pGenesisOptions
<*> pEnvOutputDir
<*> pCreateEnvOptions
Expand All @@ -47,8 +48,8 @@ pCreateEnvOptions :: Parser CreateEnvOptions
pCreateEnvOptions = CreateEnvOptions
<$> pOnChainParams

pCardanoTestnetCliOptions :: Parser CardanoTestnetOptions
pCardanoTestnetCliOptions = CardanoTestnetOptions
pCardanoTestnetCliOptions :: TestnetMode -> Parser CardanoTestnetOptions
pCardanoTestnetCliOptions mode = CardanoTestnetOptions
<$> pTestnetNodeOptions
<*> pure (AnyShelleyBasedEra defaultEra)
<*> pMaxLovelaceSupply
Expand All @@ -71,16 +72,30 @@ pCardanoTestnetCliOptions = CardanoTestnetOptions
<> OA.help "Enable new epoch state logging to logs/ledger-epoch-state.log"
<> OA.showDefault
)
<*> ( OA.flag' GenerateTemplateConfigForTxGenerator
( OA.long "generate-tx-generator-config"
<> OA.help "Generate a template configuration file for tx-generator."
)
<|> OA.flag' GenerateAndRunTxGenerator
( OA.long "run-tx-generator"
<> OA.help "Generate a configuration file for tx-generator and run it."
)
<|> pure NoTxGeneratorSupport
)
<*> case mode of
RunTestnet ->
TxGeneratorSupport <$>
( TxGeneratorOptions
<$> (OA.flag' GenerateTemplateConfig
( OA.long "generate-tx-generator-config"
<> OA.help "Generate a template configuration file for tx-generator."
)
<|> OA.flag' GenerateAndRun
( OA.long "run-tx-generator"
<> OA.help "Generate a configuration file for tx-generator and run it."
))
<*> optional (OA.strOption
( OA.long "tx-generator-config"
<> OA.help ("A partial configuration file for tx-generator. " ++
"Missing but required fields will be filled with defaults. " ++
"And the following testnet-specific fields will be overridden to match the generated testnet: " ++
"\"nodeConfigFile\", \"sigKey\", \"localNodeSocketPath\", and \"targetNodes\"")
<> OA.metavar "FILEPATH"
)
)
)
<|> pure NoTxGeneratorSupport
ConfigOnly -> pure NoTxGeneratorSupport
<*> (maybe NoUserProvidedEnv UserProvidedEnv <$> optional (OA.strOption
( OA.long "output-dir"
<> OA.help "Directory where to store files, sockets, and so on. It is created if it doesn't exist. If unset, a temporary directory is used."
Expand Down
95 changes: 64 additions & 31 deletions cardano-testnet/src/Testnet/Start/Cardano.hs
Original file line number Diff line number Diff line change
Expand Up @@ -397,15 +397,16 @@ cardanoTestnet

case cardanoEnableTxGenerator testnetOptions of
NoTxGeneratorSupport -> pure ()
GenerateTemplateConfigForTxGenerator ->
void $ generateTxGenConfig tmpAbsPath nodeConfigFile utxoSigningKeyFile node1SocketPath nodeDescriptions
GenerateAndRunTxGenerator -> do
configFile <- generateTxGenConfig tmpAbsPath nodeConfigFile utxoSigningKeyFile node1SocketPath nodeDescriptions
hProcess <- runRIO () $ startTxGenRuntime (TmpAbsolutePath tmpAbsPath)
[ "json_highlevel"
, configFile
]
liftIOAnnotated $ interruptNodesOnSigINT (hProcess : map nodeProcessHandle testnetNodes')
TxGeneratorSupport (TxGeneratorOptions { txGeneratorCmd, txGeneratorConfig }) -> do
configFile <- generateTxGenConfig tmpAbsPath nodeConfigFile utxoSigningKeyFile node1SocketPath nodeDescriptions txGeneratorConfig
case txGeneratorCmd of
GenerateTemplateConfig -> pure ()
GenerateAndRun -> do
hProcess <- runRIO () $ startTxGenRuntime (TmpAbsolutePath tmpAbsPath)
[ "json_highlevel"
, configFile
]
liftIOAnnotated $ interruptNodesOnSigINT (hProcess : map nodeProcessHandle testnetNodes')

pure runtime

Expand All @@ -416,33 +417,66 @@ cardanoTestnet
-- TODO: This should come from the configuration!
makePathsAbsolute :: (Element a ~ FilePath, MonoFunctor a) => a -> a
makePathsAbsolute = omap (tmpAbsPath </>)

mkTestnetNodeKeyPaths :: Int -> SpoNodeKeys
mkTestnetNodeKeyPaths n = makePathsAbsolute $ Defaults.defaultSpoKeys n

generateTxGenConfig :: MonadUnliftIO m => FilePath -> FilePath -> SigningKeyFile 'In -> String -> NonEmpty NodeDescription -> m FilePath
generateTxGenConfig basePath nodeConfigFilePath utxoSigningKeyFile localNodeSocketPath nodeTopology = do
generateTxGenConfig :: MonadUnliftIO m => FilePath -> FilePath -> SigningKeyFile 'In -> String -> NonEmpty NodeDescription -> Maybe FilePath -> m FilePath
generateTxGenConfig basePath nodeConfigFilePath utxoSigningKeyFile localNodeSocketPath nodeTopology mUserConfig = do
nixServiceOptions <- case mUserConfig of
Nothing -> pure defaultTxGenConfig
Just userConfigFile -> setTxGenTestnetConfig <$> readPartialTxGenConfig userConfigFile
let file = basePath </> "tx-generator-config.json"
nixServiceOptions = NixServiceOptions {
_nix_debugMode = False
, _nix_tx_count = 100
, _nix_tps = 10
, _nix_inputs_per_tx = 2
, _nix_outputs_per_tx = 2
, _nix_tx_fee = 212_345
, _nix_min_utxo_value = 1_000_000
, _nix_add_tx_size = 39
, _nix_init_cooldown = 50
, _nix_era = AnyCardanoEra ConwayEra
, _nix_plutus = Nothing
, _nix_keepalive = Just 30
, _nix_nodeConfigFile = Just nodeConfigFilePath
, _nix_cardanoTracerSocket = Nothing
, _nix_sigKey = utxoSigningKeyFile
, _nix_localNodeSocketPath = localNodeSocketPath
, _nix_targetNodes = nodeTopology
}
liftIOAnnotated . LBS.writeFile file $ A.encodePretty nixServiceOptions
pure file
where
-- | Read a partial tx-generator config from a JSON file, merging it
-- on top of the defaults. This allows users to specify only the options they want to change.
readPartialTxGenConfig :: MonadUnliftIO m => FilePath -> m NixServiceOptions
readPartialTxGenConfig userConfigFile = do
eObject <- eitherDecode <$> liftIOAnnotated (LBS.readFile userConfigFile)
userObj <- case eObject of
Right (Object obj) -> pure obj
Right _ -> throwString $ "Expected a JSON Object in tx-generator config file: " <> userConfigFile
Left err -> throwString $ "Could not parse tx-generator config file: " <> userConfigFile <> " Error: " <> err
defaultObj <- case toJSON defaultTxGenConfig of
Object obj -> return obj
_ -> throwString "Internal error: NixServiceOptions didn't serialize to an Object"
case fromJSON (Object (userObj <> defaultObj)) of
Success opts -> pure opts
Error err -> throwString $ "Could not decode tx-generator config: " <> userConfigFile <> " Error: " <> err

setTxGenTestnetConfig :: NixServiceOptions -> NixServiceOptions
setTxGenTestnetConfig opts =
opts { _nix_nodeConfigFile = Just nodeConfigFilePath
, _nix_sigKey = utxoSigningKeyFile
, _nix_localNodeSocketPath = localNodeSocketPath
, _nix_targetNodes = nodeTopology
}

defaultTxGenConfig :: NixServiceOptions
defaultTxGenConfig =
setTxGenTestnetConfig
NixServiceOptions
{ _nix_debugMode = False
, _nix_tx_count = 100
, _nix_tps = 10
, _nix_inputs_per_tx = 2
, _nix_outputs_per_tx = 2
, _nix_tx_fee = 212_345
, _nix_min_utxo_value = 1_000_000
, _nix_add_tx_size = 39
, _nix_init_cooldown = 50
, _nix_era = AnyCardanoEra ConwayEra
, _nix_plutus = Nothing
, _nix_keepalive = Just 30
, _nix_cardanoTracerSocket = Nothing
-- Placeholders for testnet-specific fields (overwritten by setTxGenTestnetConfig)
, _nix_nodeConfigFile = Nothing
, _nix_sigKey = File ""
, _nix_localNodeSocketPath = ""
, _nix_targetNodes = nodeTopology
}

-- wait for new blocks or throw an exception if there are none in the timeout period
waitForBlockThrow :: MonadUnliftIO m
Expand Down Expand Up @@ -474,7 +508,6 @@ cardanoTestnet
_ ->
throwString $ nodeName <> " was unable to produce any blocks for " <> show timeoutSeconds <> "s"


-- | A convenience wrapper around `createTestnetEnv` and `cardanoTestnet`
createAndRunTestnet :: ()
=> HasCallStack
Expand Down
23 changes: 21 additions & 2 deletions cardano-testnet/src/Testnet/Start/Types.hs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ module Testnet.Start.Types
, NumDReps(..)
, NumPools(..)
, NumRelays(..)
, TestnetMode(..)
, TxGeneratorCmd(..)
, TxGeneratorOptions(..)
, TxGeneratorSupport(..)
, cardanoNumPools
, cardanoNumRelays
Expand Down Expand Up @@ -167,10 +170,26 @@ data CardanoTestnetCreateEnvOptions = CardanoTestnetCreateEnvOptions
, createEnvCreateEnvOptions :: CreateEnvOptions
} deriving (Eq, Show)

-- | Whether we should only generate the configuration
-- or also run the testnet.
data TestnetMode
= ConfigOnly -- ^ Only generate configuration
| RunTestnet -- ^ Generate configuration and run the testnet
deriving (Eq, Show)

data TxGeneratorCmd
= GenerateTemplateConfig
| GenerateAndRun
deriving (Eq, Show)

data TxGeneratorOptions = TxGeneratorOptions
{ txGeneratorCmd :: TxGeneratorCmd
, txGeneratorConfig :: Maybe FilePath
} deriving (Eq, Show)

data TxGeneratorSupport
= NoTxGeneratorSupport
| GenerateTemplateConfigForTxGenerator
| GenerateAndRunTxGenerator
| TxGeneratorSupport TxGeneratorOptions
deriving (Eq, Show)

-- | Options which, contrary to 'GenesisOptions' are not implemented
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ Usage: cardano-testnet cardano [--num-pool-nodes COUNT]
[--nodeLoggingFormat LOGGING_FORMAT]
[--num-dreps NUMBER]
[--enable-new-epoch-state-logging]
[--generate-tx-generator-config | --run-tx-generator]
[(--generate-tx-generator-config | --run-tx-generator)
[--tx-generator-config FILEPATH]]
[--output-dir DIRECTORY]
[--testnet-magic INT]
[--epoch-length SLOTS]
Expand All @@ -21,7 +22,6 @@ Usage: cardano-testnet create-env [--num-pool-nodes COUNT]
[--nodeLoggingFormat LOGGING_FORMAT]
[--num-dreps NUMBER]
[--enable-new-epoch-state-logging]
[--generate-tx-generator-config | --run-tx-generator]
[--output-dir DIRECTORY]
[--testnet-magic INT]
[--epoch-length SLOTS]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ Usage: cardano-testnet cardano [--num-pool-nodes COUNT]
[--nodeLoggingFormat LOGGING_FORMAT]
[--num-dreps NUMBER]
[--enable-new-epoch-state-logging]
[--generate-tx-generator-config | --run-tx-generator]
[(--generate-tx-generator-config | --run-tx-generator)
[--tx-generator-config FILEPATH]]
[--output-dir DIRECTORY]
[--testnet-magic INT]
[--epoch-length SLOTS]
Expand Down Expand Up @@ -35,6 +36,13 @@ Available options:
tx-generator.
--run-tx-generator Generate a configuration file for tx-generator and
run it.
--tx-generator-config FILEPATH
A partial configuration file for tx-generator.
Missing but required fields will be filled with
defaults. And the following testnet-specific fields
will be overridden to match the generated testnet:
"nodeConfigFile", "sigKey", "localNodeSocketPath",
and "targetNodes"
--output-dir DIRECTORY Directory where to store files, sockets, and so on.
It is created if it doesn't exist. If unset, a
temporary directory is used.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ Usage: cardano-testnet create-env [--num-pool-nodes COUNT]
[--nodeLoggingFormat LOGGING_FORMAT]
[--num-dreps NUMBER]
[--enable-new-epoch-state-logging]
[--generate-tx-generator-config | --run-tx-generator]
[--output-dir DIRECTORY]
[--testnet-magic INT]
[--epoch-length SLOTS]
Expand All @@ -30,11 +29,6 @@ Available options:
--enable-new-epoch-state-logging
Enable new epoch state logging to
logs/ledger-epoch-state.log
--generate-tx-generator-config
Generate a template configuration file for
tx-generator.
--run-tx-generator Generate a configuration file for tx-generator and
run it.
--output-dir DIRECTORY Directory where to store files, sockets, and so on.
It is created if it doesn't exist. If unset, a
temporary directory is used.
Expand Down
Loading