Skip to content

Commit

Permalink
Make testnet topology configurable
Browse files Browse the repository at this point in the history
  • Loading branch information
carbolymer committed Oct 10, 2024
1 parent 3136bde commit 0918299
Show file tree
Hide file tree
Showing 39 changed files with 649 additions and 508 deletions.
1 change: 1 addition & 0 deletions cardano-testnet/cardano-testnet.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ library
, hedgehog-extras ^>= 0.6.4
, lens-aeson
, microlens
, mono-traversable
, mtl
, network
, network-mux
Expand Down
8 changes: 4 additions & 4 deletions cardano-testnet/src/Parsers/Cardano.hs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module Parsers.Cardano
( cmdCardano
) where

import Cardano.Api (EraInEon (..), bounded, AnyShelleyBasedEra (AnyShelleyBasedEra))
import Cardano.Api (AnyShelleyBasedEra (AnyShelleyBasedEra), EraInEon (..), bounded)

import Cardano.CLI.Environment
import Cardano.CLI.EraBased.Options.Common hiding (pNetworkId)
Expand Down Expand Up @@ -65,7 +65,7 @@ pCardanoTestnetCliOptions envCli = CardanoTestnetOptions
pNumSpoNodes :: Parser [TestnetNodeOptions]
pNumSpoNodes =
OA.option
((`L.replicate` SpoTestnetNodeOptions Nothing []) <$> auto)
((`L.replicate` TestnetNodeOptions TestnetNodeRoleSpo Nothing []) <$> auto)
( OA.long "num-pool-nodes"
<> OA.help "Number of pool nodes. Note this uses a default node configuration for all nodes."
<> OA.metavar "COUNT"
Expand All @@ -75,8 +75,8 @@ pNumSpoNodes =

_pSpo :: Parser TestnetNodeOptions
_pSpo =
SpoTestnetNodeOptions . Just
<$> parseNodeConfigFile
TestnetNodeOptions TestnetNodeRoleSpo -- TODO add parser for node roles
. Just <$> parseNodeConfigFile
<*> pure [] -- TODO: Consider adding support for extra args

parseNodeConfigFile :: Parser NodeConfigurationYaml
Expand Down
30 changes: 8 additions & 22 deletions cardano-testnet/src/Testnet/Components/Configuration.hs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
Expand All @@ -13,11 +13,6 @@ module Testnet.Components.Configuration
, getByronGenesisHash
, getShelleyGenesisHash

, NumPools(..)
, numPools
, NumDReps
, numDReps

, anyEraToString
, eraToString
) where
Expand Down Expand Up @@ -61,7 +56,8 @@ import System.FilePath.Posix (takeDirectory, (</>))
import Testnet.Defaults
import Testnet.Filepath
import Testnet.Process.Run (execCli_)
import Testnet.Start.Types (CardanoTestnetOptions (..), anyEraToString, anyShelleyBasedEraToString, eraToString)
import Testnet.Start.Types (NumDReps (..), NumPools (..), anyEraToString,
anyShelleyBasedEraToString, eraToString)

import Hedgehog
import qualified Hedgehog as H
Expand Down Expand Up @@ -118,16 +114,6 @@ getShelleyGenesisHash path key = do
numSeededUTxOKeys :: Int
numSeededUTxOKeys = 3

newtype NumPools = NumPools Int

numPools :: CardanoTestnetOptions -> NumPools
numPools CardanoTestnetOptions { cardanoNodes } = NumPools $ length cardanoNodes

newtype NumDReps = NumDReps Int

numDReps :: CardanoTestnetOptions -> NumDReps
numDReps CardanoTestnetOptions { cardanoNumDReps } = NumDReps cardanoNumDReps

createSPOGenesisAndFiles
:: (MonadTest m, MonadCatch m, MonadIO m, HasCallStack)
=> NumPools -- ^ The number of pools to make
Expand All @@ -139,7 +125,7 @@ createSPOGenesisAndFiles
-> ConwayGenesis StandardCrypto -- ^ The conway genesis to use, for example 'Defaults.defaultConwayGenesis'.
-> TmpAbsolutePath
-> m FilePath -- ^ Shelley genesis directory
createSPOGenesisAndFiles (NumPools numPoolNodes) (NumDReps numDelReps) maxSupply sbe shelleyGenesis
createSPOGenesisAndFiles numTestnetNodes numDelReps maxSupply sbe shelleyGenesis
alonzoGenesis conwayGenesis (TmpAbsolutePath tempAbsPath) = GHC.withFrozenCallStack $ do
let inputGenesisShelleyFp = tempAbsPath </> genesisInputFilepath ShelleyEra
inputGenesisAlonzoFp = tempAbsPath </> genesisInputFilepath AlonzoEra
Expand All @@ -158,7 +144,7 @@ createSPOGenesisAndFiles (NumPools numPoolNodes) (NumDReps numDelReps) maxSupply
let testnetMagic = sgNetworkMagic shelleyGenesis
-- At least there should be a delegator per DRep
-- otherwise some won't be representing anybody
numStakeDelegators = max 3 numDelReps :: Int
numStakeDelegators = max 3 (fromIntegral numDelReps) :: Int
startTime = sgSystemStart shelleyGenesis

-- TODO: Remove this rewrite.
Expand All @@ -171,8 +157,8 @@ createSPOGenesisAndFiles (NumPools numPoolNodes) (NumDReps numDelReps) maxSupply
-- TODO: create-testnet-data should have arguments for
-- Alonzo and Conway genesis that are optional and if not
-- supplised the users get a default
H.note_ $ "Number of pools: " <> show numPoolNodes
H.note_ $ "Number of stake delegators: " <> show numPoolNodes
H.note_ $ "Number of pools: " <> show numTestnetNodes
H.note_ $ "Number of stake delegators: " <> show numTestnetNodes
H.note_ $ "Number of seeded UTxO keys: " <> show numSeededUTxOKeys

execCli_
Expand All @@ -181,7 +167,7 @@ createSPOGenesisAndFiles (NumPools numPoolNodes) (NumDReps numDelReps) maxSupply
, "--spec-alonzo", inputGenesisAlonzoFp
, "--spec-conway", inputGenesisConwayFp
, "--testnet-magic", show testnetMagic
, "--pools", show numPoolNodes
, "--pools", show numTestnetNodes
, "--total-supply", show maxSupply -- Half of this will be delegated, see https://github.com/IntersectMBO/cardano-cli/pull/874
, "--stake-delegators", show numStakeDelegators
, "--utxo-keys", show numSeededUTxOKeys
Expand Down
63 changes: 46 additions & 17 deletions cardano-testnet/src/Testnet/Defaults.hs
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,24 @@ module Testnet.Defaults
, defaultDRepSkeyFp
, defaultDRepKeyPair
, defaultDelegatorStakeKeyPair
, defaultNodeName
, defaultNodeDataDir
, defaultSpoColdKeyPair
, defaultSPOColdVKeyFp
, defaultSPOColdSKeyFp
, defaultSpoColdVKeyFp
, defaultSpoColdSKeyFp
, defaultSpoKeys
, defaultSpoKeysDir
, defaultSpoName
, defaultShelleyGenesis
, defaultGenesisFilepath
, defaultYamlHardforkViaConfig
, defaultMainnetTopology
, defaultUtxoKeys
, plutusV3Script
) where

import Cardano.Api (CardanoEra (..), File (..), pshow, ShelleyBasedEra (..),
toCardanoEra, unsafeBoundedRational, AnyShelleyBasedEra (..))
import Cardano.Api (AnyShelleyBasedEra (..), CardanoEra (..), File (..),
ShelleyBasedEra (..), pshow, toCardanoEra, unsafeBoundedRational)
import qualified Cardano.Api.Shelley as Api

import Cardano.Ledger.Alonzo.Core (PParams (..))
Expand Down Expand Up @@ -256,7 +261,7 @@ defaultYamlHardforkViaConfig sbe =
, (proxyName (Proxy @TraceTxOutbound), False)
, (proxyName (Proxy @TraceTxSubmissionProtocol), False)
]

defaultYamlConfig :: Aeson.KeyMap Aeson.Value
defaultYamlConfig =
Aeson.fromList
Expand Down Expand Up @@ -468,37 +473,53 @@ defaultCommitteeKeyPair n =
}

-- | The relative path to SPO cold verification key in directories created by cardano-testnet
defaultSPOColdVKeyFp :: Int -> FilePath
defaultSPOColdVKeyFp n = "pools-keys" </> "pool" <> show n </> "cold.vkey"
defaultSpoColdVKeyFp :: Int -> FilePath
defaultSpoColdVKeyFp n = defaultSpoKeysDir n </> "cold.vkey"

-- | The relative path to SPO cold secret key in directories created by cardano-testnet
defaultSPOColdSKeyFp :: Int -> FilePath
defaultSPOColdSKeyFp n = "pools-keys" </> "pool" <> show n </> "cold.skey"
defaultSpoColdSKeyFp :: Int -> FilePath
defaultSpoColdSKeyFp n = defaultSpoKeysDir n </> "cold.skey"

-- | The name of a SPO, used in file system operations
defaultSpoName :: Int -> String
defaultSpoName n = "pool" <> show n

-- | The name of a node (which doesn't have to be a SPO)
defaultNodeName :: Int -> String
defaultNodeName n = "node" <> show n

-- | The relative path of the node data dir, where the database is stored
defaultNodeDataDir :: Int -> String
defaultNodeDataDir n = "node-data" </> defaultNodeName n

-- | The relative path where the SPO keys for the node are stored
defaultSpoKeysDir :: Int -> String
defaultSpoKeysDir n = "pools-keys" </> defaultSpoName n

-- | The relative path to SPO keys in directories created by cardano-testnet
defaultSpoColdKeyPair
:: Int
-> KeyPair SpoColdKey
defaultSpoColdKeyPair n =
KeyPair
{ verificationKey = File $ "pools-keys" </> "pool" <> show n </> "cold.vkey"
, signingKey = File $ "pools-keys" </> "pool" <> show n </> "cold.skey"
{ verificationKey = File $ defaultSpoKeysDir n </> "cold.vkey"
, signingKey = File $ defaultSpoKeysDir n </> "cold.skey"
}

-- | The relative path to SPO key pairs in directories created by cardano-testnet
defaultSpoKeys :: Int -> PoolNodeKeys
defaultSpoKeys :: Int -> TestnetNodeKeys
defaultSpoKeys n =
PoolNodeKeys
TestnetNodeKeys
{ poolNodeKeysCold = defaultSpoColdKeyPair n
, poolNodeKeysVrf =
KeyPair
{ verificationKey = File $ "pools-keys" </> "pool" ++ show n </> "vrf.vkey"
, signingKey = File $ "pools-keys" </> "pool" ++ show n </> "vrf.skey"
{ verificationKey = File $ defaultSpoKeysDir n </> "vrf.vkey"
, signingKey = File $ defaultSpoKeysDir n </> "vrf.skey"
}
, poolNodeKeysStaking =
KeyPair
{ verificationKey = File $ "pools-keys" </> "pool" ++ show n </> "staking-reward.vkey"
, signingKey = File $ "pools-keys" </> "pool" ++ show n </> "staking-reward.skey"
{ verificationKey = File $ defaultSpoKeysDir n </> "staking-reward.vkey"
, signingKey = File $ defaultSpoKeysDir n </> "staking-reward.skey"
}
}

Expand All @@ -510,6 +531,14 @@ defaultDelegatorStakeKeyPair n =
, signingKey = File $ "stake-delegators" </> ("delegator" <> show n) </> "staking.skey"
}

-- | The relative path to UTXO keys
defaultUtxoKeys :: Int -> KeyPair PaymentKey
defaultUtxoKeys n =
KeyPair
{ verificationKey = File $ "utxo-keys" </> "utxo" <> show n </> "utxo.vkey"
, signingKey = File $ "utxo-keys" </> "utxo" <> show n </> "utxo.skey"
}

-- | Default plutus script that always succeeds
plutusV3Script :: Text
plutusV3Script =
Expand Down
4 changes: 2 additions & 2 deletions cardano-testnet/src/Testnet/Process/Cli/SPO.hs
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,7 @@ registerSingleSpo asbe identifier tap@(TmpAbsolutePath tempAbsPath') nodeConfigF
-- Returns a list of generated @File VoteFile In@ representing the paths to
-- the generated voting files.
-- TODO: unify with DRep.generateVoteFiles
generateVoteFiles :: (MonadTest m, MonadIO m, MonadCatch m)
generateVoteFiles :: (HasCallStack, MonadTest m, MonadIO m, MonadCatch m)
=> ConwayEraOnwards era -- ^ The conway era onwards witness for the era in which the
-- transaction will be constructed.
-> H.ExecConfig -- ^ Specifies the CLI execution configuration.
Expand All @@ -417,7 +417,7 @@ generateVoteFiles :: (MonadTest m, MonadIO m, MonadCatch m)
-- the output voting files.
-> String -- ^ Transaction ID string of the governance action.
-> Word16 -- ^ Index of the governance action.
-> [(PoolNodeKeys, [Char])] -- ^ List of tuples where each tuple contains a 'PoolNodeKeys'
-> [(TestnetNodeKeys, [Char])] -- ^ List of tuples where each tuple contains a 'TestnetNodeKeys'
-- representing the SPO keys and a 'String' representing the
-- vote type (i.e: "yes", "no", or "abstain").
-> m [File VoteFile In]
Expand Down
1 change: 0 additions & 1 deletion cardano-testnet/src/Testnet/Property/Assert.hs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ import Data.Type.Equality
import Data.Word (Word8)
import GHC.Stack as GHC

import Testnet.Components.Configuration (NumPools(..))
import Testnet.Process.Run
import Testnet.Start.Types

Expand Down
6 changes: 3 additions & 3 deletions cardano-testnet/src/Testnet/Runtime.hs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ import Testnet.Filepath
import qualified Testnet.Ping as Ping
import Testnet.Process.Run
import Testnet.Types (NodeRuntime (NodeRuntime), TestnetRuntime (configurationFile),
poolSprockets, showIpv4Address)
showIpv4Address, testnetSprockets)

import Hedgehog (MonadTest)
import qualified Hedgehog as H
Expand Down Expand Up @@ -190,7 +190,7 @@ startNode tp node ipv4 port testnetMagic nodeCmd = GHC.withFrozenCallStack $ do
NodeExecutableError . hsep $
["Socket", pretty socketAbsPath, "was not created after 120 seconds. There was no output on stderr. Exception:", prettyException ioex])
$ hoistEither eSprocketError

-- Ping node and fail on error
Ping.pingNode (fromIntegral testnetMagic) sprocket
>>= (firstExceptT (NodeExecutableError . ("Ping error:" <+>) . prettyError) . hoistEither)
Expand Down Expand Up @@ -286,7 +286,7 @@ startLedgerNewEpochStateLogging testnetRuntime tmpWorkspace = withFrozenCallStac
H.note_ $ "Epoch states logging to " <> logFile <> " is already started."
False -> do
H.evalIO $ appendFile logFile ""
socketPath <- H.noteM $ H.sprocketSystemName <$> H.headM (poolSprockets testnetRuntime)
socketPath <- H.noteM $ H.sprocketSystemName <$> H.headM (testnetSprockets testnetRuntime)

_ <- H.asyncRegister_ . runExceptT $
foldEpochState
Expand Down
Loading

0 comments on commit 0918299

Please sign in to comment.