Skip to content

Commit

Permalink
cardano-testnet: allow to pass genesis files
Browse files Browse the repository at this point in the history
  • Loading branch information
smelc committed Jan 25, 2024
1 parent 03fb7f7 commit 731e6d9
Show file tree
Hide file tree
Showing 16 changed files with 100 additions and 48 deletions.
2 changes: 1 addition & 1 deletion cardano-node-chairman/test/Spec/Chairman/Cardano.hs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@ hprop_chairman :: H.Property
hprop_chairman = H.integrationRetryWorkspace 2 "cardano-chairman" $ \tempAbsPath' -> do
conf <- H.mkConf tempAbsPath'

allNodes <- fmap H.nodeName . H.allNodes <$> H.cardanoTestnet H.cardanoDefaultTestnetOptions conf
allNodes <- fmap H.nodeName . H.allNodes <$> H.cardanoTestnetDefault H.cardanoDefaultTestnetOptions conf

chairmanOver 120 50 conf allNodes
1 change: 1 addition & 0 deletions cardano-testnet/src/Cardano/Testnet.hs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ module Cardano.Testnet (

-- ** Start a testnet
cardanoTestnet,
cardanoTestnetDefault,

-- ** Testnet options
CardanoTestnetOptions(..),
Expand Down
2 changes: 1 addition & 1 deletion cardano-testnet/src/Parsers/Run.hs
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,4 @@ runTestnetCmd = \case

runCardanoOptions :: CardanoTestnetOptions -> IO ()
runCardanoOptions options =
runTestnet $ cardanoTestnet options
runTestnet $ cardanoTestnetDefault options
30 changes: 14 additions & 16 deletions cardano-testnet/src/Testnet/Components/Configuration.hs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ module Testnet.Components.Configuration
, createSPOGenesisAndFiles
, mkTopologyConfig
, numSeededUTxOKeys
, NumPools(..)
) where

import Cardano.Api.Shelley hiding (cardanoEra)
Expand All @@ -28,7 +29,6 @@ import qualified Data.Aeson as Aeson
import qualified Data.ByteString.Lazy as LBS
import qualified Data.List as List
import Data.String
import Data.Time
import GHC.Stack (HasCallStack)
import qualified GHC.Stack as GHC
import System.FilePath.Posix (takeDirectory, (</>))
Expand All @@ -42,11 +42,12 @@ import qualified Hedgehog.Extras.Test.File as H
import qualified Data.Aeson.Lens as L
import Lens.Micro

import Cardano.Api.Ledger (StandardCrypto)
import Data.Word (Word32)
import Testnet.Defaults
import Testnet.Filepath
import Testnet.Process.Run (execCli_)
import Testnet.Property.Utils
import Testnet.Start.Types


createConfigYaml
Expand Down Expand Up @@ -78,35 +79,32 @@ createConfigYaml (TmpAbsolutePath tempAbsPath') anyCardanoEra' = GHC.withFrozenC
numSeededUTxOKeys :: Int
numSeededUTxOKeys = 3

newtype NumPools = NumPools { unNumPools :: Int }

createSPOGenesisAndFiles
:: (MonadTest m, MonadCatch m, MonadIO m, HasCallStack)
=> CardanoTestnetOptions
-> UTCTime -- ^ Start time
=> NumPools
-> AnyCardanoEra -- ^ The era to use
-> ShelleyGenesis StandardCrypto -- ^ The shelley genesis to use.
-> TmpAbsolutePath
-> m FilePath -- ^ Shelley genesis directory
createSPOGenesisAndFiles testnetOptions startTime (TmpAbsolutePath tempAbsPath') = do
createSPOGenesisAndFiles NumPools {unNumPools = numPoolNodes} era shelleyGenesis (TmpAbsolutePath tempAbsPath') = do
let genesisShelleyFpAbs = tempAbsPath' </> defaultShelleyGenesisFp
genesisShelleyDirAbs = takeDirectory genesisShelleyFpAbs
genesisShelleyDir <- H.createDirectoryIfMissing genesisShelleyDirAbs
let testnetMagic = cardanoTestnetMagic testnetOptions
numPoolNodes = length $ cardanoNodes testnetOptions
let testnetMagic = sgNetworkMagic shelleyGenesis
numStakeDelegators = 3
era = cardanoNodeEra testnetOptions
-- TODO: Even this is cumbersome. You need to know where to put the initial
-- shelley genesis for create-testnet-data to use.
startTime = sgSystemStart shelleyGenesis

-- TODO: We need to read the genesis files into Haskell and modify them
-- based on cardano-testnet's cli parameters

-- We create the initial genesis file to avoid having to re-write the genesis file later
-- with the parameters we want. The user must provide genesis files or we will use a default.
-- We should *never* be modifying the genesis file after cardano-testnet is run because this
-- We should *never* be modifying the genesis file after @cardanoTestnet@ is run because this
-- is sure to be a source of confusion if users provide genesis files and we are mutating them
-- without their knowledge.
let shelleyGenesis :: LBS.ByteString
shelleyGenesis = encode $ defaultShelleyGenesis startTime testnetOptions

H.evalIO $ LBS.writeFile genesisShelleyFpAbs shelleyGenesis
H.evalIO $ LBS.writeFile genesisShelleyFpAbs $ encode shelleyGenesis

-- TODO: Remove this rewrite.
-- 50 second epochs
Expand All @@ -128,7 +126,7 @@ createSPOGenesisAndFiles testnetOptions startTime (TmpAbsolutePath tempAbsPath')
execCli_
[ convertToEraString era, "genesis", "create-testnet-data"
, "--spec-shelley", genesisShelleyFpAbs
, "--testnet-magic", show @Int testnetMagic
, "--testnet-magic", show @Word32 testnetMagic
, "--pools", show @Int numPoolNodes
, "--supply", "1000000000000"
, "--supply-delegated", "1000000000000"
Expand Down
89 changes: 71 additions & 18 deletions cardano-testnet/src/Testnet/Start/Cardano.hs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ module Testnet.Start.Cardano
, PaymentKeyPair(..)

, cardanoTestnet
, cardanoTestnetDefault
) where

import Prelude hiding (lines)
Expand All @@ -41,16 +42,25 @@ import qualified Hedgehog.Extras.Stock.OS as OS
import qualified Hedgehog.Extras.Test.Base as H
import qualified Hedgehog.Extras.Test.File as H

import qualified Testnet.Defaults as Defaults

import Cardano.Api
import Cardano.Api.Ledger (StandardCrypto)
import Cardano.Ledger.Alonzo.Genesis (AlonzoGenesis)
import Cardano.Ledger.Conway.Genesis (ConwayGenesis)
import qualified Control.Monad.Class.MonadTimer.SI as MT
import Control.Monad.IO.Class
import qualified Data.Aeson as Aeson
import Data.Bifunctor (first)
import Data.Time (UTCTime)
import Data.Word (Word32)
import Testnet.Components.Configuration
import Testnet.Defaults
import Testnet.Filepath
import qualified Testnet.Process.Run as H
import Testnet.Process.Run
import qualified Testnet.Process.Run as H
import qualified Testnet.Property.Assert as H
import Testnet.Property.Checks
import Testnet.Runtime as TR
import Testnet.Runtime as TR hiding (shelleyGenesis)
import qualified Testnet.Start.Byron as Byron
import Testnet.Start.Types

Expand All @@ -63,10 +73,11 @@ import Testnet.Start.Types
-- a valid node cluster.
testnetMinimumConfigurationRequirements :: CardanoTestnetOptions -> H.Integration ()
testnetMinimumConfigurationRequirements cTestnetOpts = do
when (length (cardanoNodes cTestnetOpts) < 2) $ do
H.noteShow_ ("Need at least two nodes to run a cluster" :: String)
let actualLength = length (cardanoNodes cTestnetOpts)
when (actualLength < 2) $ do
H.noteShow_ ("Need at least two nodes to run a cluster, but got: " <> show actualLength)
H.noteShow_ cTestnetOpts
H.assert False
H.failure

data ForkPoint
= AtVersion Int
Expand All @@ -79,6 +90,19 @@ data ForkPoint
startTimeOffsetSeconds :: DTC.NominalDiffTime
startTimeOffsetSeconds = if OS.isWin32 then 90 else 15

-- | Like 'cardanoTestnet', but using defaults for all configuration files.
-- See 'cardanoTestnet' for additional documentation.
cardanoTestnetDefault :: ()
=> CardanoTestnetOptions
-> Conf
-> H.Integration TestnetRuntime
cardanoTestnetDefault opts conf = do
alonzoGenesis <- H.evalEither $ first prettyError Defaults.defaultAlonzoGenesis
currentTime <- H.noteShowIO DTC.getCurrentTime
startTime <- H.noteShow $ DTC.addUTCTime startTimeOffsetSeconds currentTime
cardanoTestnet
opts conf startTime
(Defaults.defaultShelleyGenesis startTime opts) alonzoGenesis Defaults.defaultConwayGenesis

-- | Setup a number of credentials and pools, like this:
--
Expand Down Expand Up @@ -122,14 +146,38 @@ startTimeOffsetSeconds = if OS.isWin32 then 90 else 15
-- > │   └── node-spo{1,2,3}
-- > └── utxo-keys
-- >    └── utxo{1,2,3}.{addr,skey,vkey}
cardanoTestnet :: CardanoTestnetOptions -> Conf -> H.Integration TestnetRuntime
cardanoTestnet testnetOptions Conf {tempAbsPath} = do
testnetMinimumConfigurationRequirements testnetOptions
void $ H.note OS.os
currentTime <- H.noteShowIO DTC.getCurrentTime
let tempAbsPath' = unTmpAbsPath tempAbsPath
cardanoTestnet :: ()
=> CardanoTestnetOptions -- ^ The options to use. Must be consistent with the genesis files.
-> Conf
-> UTCTime -- ^ The starting time. Must be the same as the one in the shelley genesis.
-> ShelleyGenesis StandardCrypto -- ^ The shelley genesis to use, for example 'Defaults.defaultShelleyGenesis'.
-- Some fields are overridden by the accompanying 'CardanoTestnetOptions'.
-> AlonzoGenesis -- ^ The alonzo genesis to use, for example 'Defaults.defaultAlonzoGenesis'.
-> ConwayGenesis StandardCrypto -- ^ The conway genesis to use, for example 'Defaults.defaultConwayGenesis'.
-> H.Integration TestnetRuntime
cardanoTestnet
testnetOptions Conf {tempAbsPath} startTime
shelleyGenesis alonzoGenesis conwayGenesis = do
let shelleyStartTime = sgSystemStart shelleyGenesis
shelleyTestnetMagic = sgNetworkMagic shelleyGenesis
optionsMagic :: Word32 = fromIntegral $ cardanoTestnetMagic testnetOptions
tempAbsPath' = unTmpAbsPath tempAbsPath
testnetMagic = cardanoTestnetMagic testnetOptions
numPoolNodes = length $ cardanoNodes testnetOptions
numPools = NumPools $ length $ cardanoNodes testnetOptions
era = cardanoNodeEra testnetOptions

-- Sanity checks
testnetMinimumConfigurationRequirements testnetOptions
when (shelleyStartTime /= startTime) $ do
H.note_ $ "Expected same system start in shelley genesis and parameter, but got " <> show shelleyStartTime <> " and " <> show startTime
H.failure
when (shelleyTestnetMagic /= optionsMagic) $ do
H.note_ $ "Expected same network magic in shelley genesis and parameter, but got " <> show shelleyTestnetMagic <> " and " <> show optionsMagic
H.failure
-- Done with sanity checks

H.note_ OS.os

if all isJust [mconfig | SpoTestnetNodeOptions mconfig _ <- cardanoNodes testnetOptions]
then
Expand All @@ -139,10 +187,8 @@ cardanoTestnet testnetOptions Conf {tempAbsPath} = do
-- See all of the ad hoc file creation/renaming/dir creation etc below.
H.failMessage GHC.callStack "Specifying node configuration files per node not supported yet."
else do
startTime <- H.noteShow $ DTC.addUTCTime startTimeOffsetSeconds currentTime

H.lbsWriteFile (tempAbsPath' </> "byron.genesis.spec.json")
. J.encode $ defaultByronProtocolParamsJsonValue
. J.encode $ Defaults.defaultByronProtocolParamsJsonValue

-- Because in Conway the overlay schedule and decentralization parameter
-- are deprecated, we must use the "create-staked" cli command to create
Expand All @@ -154,10 +200,17 @@ cardanoTestnet testnetOptions Conf {tempAbsPath} = do
(tempAbsPath' </> "byron.genesis.spec.json")
(tempAbsPath' </> "byron-gen-command")

_ <- createSPOGenesisAndFiles testnetOptions startTime (TmpAbsolutePath tempAbsPath')
-- Write Alonzo genesis file
alonzoGenesisJsonFile <- H.noteShow $ tempAbsPath' </> "genesis.alonzo.spec.json"
H.evalIO $ LBS.writeFile alonzoGenesisJsonFile $ Aeson.encode alonzoGenesis

-- Write Conway genesis file
conwayGenesisJsonFile <- H.noteShow $ tempAbsPath' </> "genesis.conway.spec.json"
H.evalIO $ LBS.writeFile conwayGenesisJsonFile $ Aeson.encode conwayGenesis

configurationFile <- H.noteShow $ tempAbsPath' </> "configuration.yaml"

_ <- createSPOGenesisAndFiles numPools era shelleyGenesis (TmpAbsolutePath tempAbsPath')

poolKeys <- H.noteShow $ flip fmap [1..numPoolNodes] $ \n ->
PoolNodeKeys
Expand Down Expand Up @@ -215,7 +268,7 @@ cardanoTestnet testnetOptions Conf {tempAbsPath} = do


-- Add Byron, Shelley and Alonzo genesis hashes to node configuration
finalYamlConfig <- createConfigYaml tempAbsPath $ cardanoNodeEra testnetOptions
finalYamlConfig <- createConfigYaml tempAbsPath era

H.evalIO $ LBS.writeFile configurationFile finalYamlConfig

Expand Down Expand Up @@ -340,7 +393,7 @@ cardanoTestnet testnetOptions Conf {tempAbsPath} = do

let runtime = TestnetRuntime
{ configurationFile
, shelleyGenesisFile = tempAbsPath' </> defaultShelleyGenesisFp
, shelleyGenesisFile = tempAbsPath' </> Defaults.defaultShelleyGenesisFp
, testnetMagic
, poolNodes
, wallets = wallets
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ hprop_leadershipSchedule = H.integrationRetryWorkspace 2 "babbage-leadership-sch
tr@TestnetRuntime
{ testnetMagic
, wallets
} <- cardanoTestnet cTestnetOptions conf
} <- cardanoTestnetDefault cTestnetOptions conf

execConfig <- H.headM (poolSprockets tr) >>= H.mkExecConfig tempBaseAbsPath

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ hprop_stakeSnapshot = H.integrationRetryWorkspace 2 "babbage-stake-snapshot" $ \
TestnetRuntime
{ testnetMagic
, poolNodes
} <- cardanoTestnet options conf
} <- cardanoTestnetDefault options conf

poolNode1 <- H.headM poolNodes

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ hprop_transaction = H.integrationRetryWorkspace 0 "babbage-transaction" $ \tempA
{ testnetMagic
, poolNodes
, wallets
} <- cardanoTestnet options conf
} <- cardanoTestnetDefault options conf

poolNode1 <- H.headM poolNodes

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ hprop_stakeSnapshot = H.integrationRetryWorkspace 2 "conway-stake-snapshot" $ \t
TestnetRuntime
{ testnetMagic
, poolNodes
} <- cardanoTestnet options conf
} <- cardanoTestnetDefault options conf

poolNode1 <- H.headM poolNodes

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ hprop_kes_period_info = H.integrationRetryWorkspace 2 "kes-period-info" $ \tempA
, cardanoNodeEra = AnyCardanoEra era -- TODO: We should only support the latest era and the upcoming era
}

runTime@TestnetRuntime { testnetMagic, wallets } <- cardanoTestnet cTestnetOptions conf
runTime@TestnetRuntime { testnetMagic, wallets } <- cardanoTestnetDefault cTestnetOptions conf
execConfig <- H.headM (poolSprockets runTime) >>= H.mkExecConfig tempBaseAbsPath

-- First we note all the relevant files
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ hprop_querySlotNumber = H.integrationRetryWorkspace 2 "query-slot-number" $ \tem
tr@TestnetRuntime
{ testnetMagic
, poolNodes
} <- cardanoTestnet options conf
} <- cardanoTestnetDefault options conf
ShelleyGenesis{sgSlotLength, sgEpochLength} <- H.noteShowM $ shelleyGenesis tr
startTime <- H.noteShowM $ getStartTime tempAbsBasePath' tr

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ prop_foldBlocks = H.integrationRetryWorkspace 2 "foldblocks" $ \tempAbsBasePath'
, cardanoNodeEra = AnyCardanoEra era -- TODO: We should only support the latest era and the upcoming era
}

runtime <- cardanoTestnet options conf
runtime <- cardanoTestnetDefault options conf

-- Get socketPath
socketPathAbs <- do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ hprop_ledger_events_propose_new_constitution = H.integrationWorkspace "propose-n
, poolNodes
, wallets
}
<- cardanoTestnet fastTestnetOptions conf
<- cardanoTestnetDefault fastTestnetOptions conf

poolNode1 <- H.headM poolNodes

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ hprop_ledger_events_sanity_check = H.integrationWorkspace "ledger-events-sanity-
}

!testnetRuntime
<- cardanoTestnet fastTestnetOptions conf
<- cardanoTestnetDefault fastTestnetOptions conf
NodeRuntime{nodeSprocket} <- H.headM $ poolRuntime <$> poolNodes testnetRuntime
let socketName' = IO.sprocketName nodeSprocket
socketBase = IO.sprocketBase nodeSprocket -- /tmp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ hprop_shutdownOnSlotSynced = H.integrationRetryWorkspace 2 "shutdown-on-slot-syn
, SpoTestnetNodeOptions Nothing []
]
}
testnetRuntime <- cardanoTestnet fastTestnetOptions conf
testnetRuntime <- cardanoTestnetDefault fastTestnetOptions conf
let allNodes' = poolNodes testnetRuntime
H.note_ $ "All nodes: " <> show (map (nodeName . poolRuntime) allNodes')

Expand Down Expand Up @@ -238,7 +238,7 @@ hprop_shutdownOnSigint = H.integrationRetryWorkspace 2 "shutdown-on-sigint" $ \t
, cardanoSlotLength = 0.01
}
testnetRuntime
<- cardanoTestnet fastTestnetOptions conf
<- cardanoTestnetDefault fastTestnetOptions conf
node@NodeRuntime{nodeProcessHandle} <- H.headM $ poolRuntime <$> poolNodes testnetRuntime

-- send SIGINT
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ hprop_transaction = H.integrationRetryWorkspace 0 "submit-api-babbage-transactio
, testnetMagic
, poolNodes
, wallets
} <- cardanoTestnet options conf
} <- cardanoTestnetDefault options conf

poolNode1 <- H.headM poolNodes

Expand Down

0 comments on commit 731e6d9

Please sign in to comment.