Skip to content

Introduce flag in cardano-testnet create-env to update time stamps #6275

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: nb/refactor_topology
Choose a base branch
from
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
1 change: 1 addition & 0 deletions cardano-testnet/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* [Fix discrepancy in security parameter between Byron and Shelley genesis files](https://github.com/IntersectMBO/cardano-node/pull/6188)
* [Add an option to dump/load configuration sandbox](https://github.com/IntersectMBO/cardano-node/pull/6239)
* [Add flag to support P2P topology](https://github.com/IntersectMBO/cardano-node/pull/6263)
* [Add flag to update time stamps in custom environment](https://github.com/IntersectMBO/cardano-node/pull/6275)

## 10.0.0

Expand Down
3 changes: 3 additions & 0 deletions cardano-testnet/cardano-testnet.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ library
, cardano-ledger-shelley
, cardano-node
, cardano-ping ^>= 0.8
, cardano-prelude
, contra-tracer
, containers
, data-default-class
Expand Down Expand Up @@ -225,6 +226,8 @@ test-suite cardano-testnet-test
Cardano.Testnet.Test.SanityCheck
Cardano.Testnet.Test.RunTestnet
Cardano.Testnet.Test.SubmitApi.Transaction
Cardano.Testnet.Test.UpdateTimeStamps
Cardano.Testnet.Test.Utils

type: exitcode-stdio-1.0

Expand Down
12 changes: 11 additions & 1 deletion cardano-testnet/src/Parsers/Cardano.hs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,10 @@ optsCreateTestnet envCli = CardanoTestnetCreateEnvOptions
<$> pCardanoTestnetCliOptions envCli
<*> pGenesisOptions
<*> pEnvOutputDir
<*> pTopologyType
<*> ( CreateEnvOptions
<$> pTopologyType
<*> pCreateEnvUpdateTime
)

pCardanoTestnetCliOptions :: EnvCli -> Parser CardanoTestnetOptions
pCardanoTestnetCliOptions envCli = CardanoTestnetOptions
Expand Down Expand Up @@ -99,6 +102,13 @@ pTopologyType = OA.flag DirectTopology P2PTopology
<> OA.showDefault
)

pCreateEnvUpdateTime :: Parser CreateEnvUpdateTime
pCreateEnvUpdateTime = OA.flag CreateEnv UpdateTimeAndExit
( OA.long "update-time"
<> OA.help "Don't create anything, just update the time stamps in existing files"
<> OA.showDefault
)

pEnvOutputDir :: Parser FilePath
pEnvOutputDir = OA.strOption
( OA.long "output"
Expand Down
4 changes: 2 additions & 2 deletions cardano-testnet/src/Parsers/Run.hs
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,11 @@ createEnvOptions CardanoTestnetCreateEnvOptions
{ createEnvTestnetOptions=testnetOptions
, createEnvGenesisOptions=genesisOptions
, createEnvOutputDir=outputDir
, createEnvTopologyType=topologyType
, createEnvCreateEnvOptions=ceOptions
} =
testnetRoutine (UserProvidedEnv outputDir) $ \conf ->
createTestnetEnv
testnetOptions genesisOptions topologyType
testnetOptions genesisOptions ceOptions
-- The CLI does not provide a way to provide custom genesis data by design:
-- If the user wants to have custom genesis data, they should manually
-- modify the files created by this command before running the testnet.
Expand Down
102 changes: 64 additions & 38 deletions cardano-testnet/src/Testnet/Start/Cardano.hs
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,15 @@ module Testnet.Start.Cardano


import Cardano.Api
import Cardano.Api.Byron (GenesisData (..))
import qualified Cardano.Api.Byron as Byron

import Cardano.Ledger.Alonzo.Genesis (AlonzoGenesis)
import Cardano.Ledger.Conway.Genesis (ConwayGenesis)
import Cardano.Node.Configuration.Topology (RemoteAddress(..))
import qualified Cardano.Node.Configuration.Topology as Direct
import qualified Cardano.Node.Configuration.TopologyP2P as P2P
import Cardano.Prelude (canonicalEncodePretty)
import Ouroboros.Network.PeerSelection.RelayAccessPoint (RelayAccessPoint(..))

import Prelude hiding (lines)
Expand Down Expand Up @@ -86,7 +89,7 @@ createTestnetEnv :: ()
=> HasCallStack
=> CardanoTestnetOptions
-> GenesisOptions
-> TopologyType
-> CreateEnvOptions
-> UserProvidedData ShelleyGenesis
-> UserProvidedData AlonzoGenesis
-> UserProvidedData ConwayGenesis
Expand All @@ -98,47 +101,70 @@ createTestnetEnv
, cardanoNodes
}
genesisOptions
topologyType
CreateEnvOptions
{ ceoTopologyType=topologyType
, ceoUpdateTime=createEnvUpdateTime
}
mShelley mAlonzo mConway
Conf
{ genesisHashesPolicy
, tempAbsPath=TmpAbsolutePath tmpAbsPath
} = do

testMinimumConfigurationRequirements testnetOptions

AnyShelleyBasedEra sbe <- pure asbe
_ <- createSPOGenesisAndFiles
testnetOptions genesisOptions
mShelley mAlonzo mConway
(TmpAbsolutePath tmpAbsPath)

configurationFile <- H.noteShow $ tmpAbsPath </> "configuration.yaml"
-- Add Byron, Shelley and Alonzo genesis hashes to node configuration
config' <- case genesisHashesPolicy of
WithHashes -> createConfigJson (TmpAbsolutePath tmpAbsPath) sbe
WithoutHashes -> pure $ createConfigJsonNoHash sbe
-- Setup P2P configuration value
let config = A.insert
"EnableP2P"
(Bool $ topologyType == P2PTopology)
config'
H.evalIO $ LBS.writeFile configurationFile $ A.encodePretty $ Object config

-- Create network topology, with abstract IDs in lieu of addresses
let nodeIds = fst <$> zip [1..] cardanoNodes
forM_ nodeIds $ \i -> do
let nodeDataDir = tmpAbsPath </> Defaults.defaultNodeDataDir i
H.evalIO $ IO.createDirectoryIfMissing True nodeDataDir

let producers = NodeId <$> filter (/= i) nodeIds
case topologyType of
DirectTopology ->
let topology = Direct.RealNodeTopology producers
in H.lbsWriteFile (nodeDataDir </> "topology.json") $ A.encodePretty topology
P2PTopology ->
let topology = Defaults.defaultP2PTopology producers
in H.lbsWriteFile (nodeDataDir </> "topology.json") $ A.encodePretty topology
} = case createEnvUpdateTime of

CreateEnv -> do
testMinimumConfigurationRequirements testnetOptions

AnyShelleyBasedEra sbe <- pure asbe
_ <- createSPOGenesisAndFiles
testnetOptions genesisOptions
mShelley mAlonzo mConway
(TmpAbsolutePath tmpAbsPath)

configurationFile <- H.noteShow $ tmpAbsPath </> "configuration.yaml"
-- Add Byron, Shelley and Alonzo genesis hashes to node configuration
config' <- case genesisHashesPolicy of
WithHashes -> createConfigJson (TmpAbsolutePath tmpAbsPath) sbe
WithoutHashes -> pure $ createConfigJsonNoHash sbe
-- Setup P2P configuration value
let config = A.insert
"EnableP2P"
(Bool $ topologyType == P2PTopology)
config'
H.evalIO $ LBS.writeFile configurationFile $ A.encodePretty $ Object config

-- Create network topology, with abstract IDs in lieu of addresses
let nodeIds = fst <$> zip [1..] cardanoNodes
forM_ nodeIds $ \i -> do
let nodeDataDir = tmpAbsPath </> Defaults.defaultNodeDataDir i
H.evalIO $ IO.createDirectoryIfMissing True nodeDataDir

let producers = NodeId <$> filter (/= i) nodeIds
case topologyType of
DirectTopology ->
let topology = Direct.RealNodeTopology producers
in H.lbsWriteFile (nodeDataDir </> "topology.json") $ A.encodePretty topology
P2PTopology ->
let topology = Defaults.defaultP2PTopology producers
in H.lbsWriteFile (nodeDataDir </> "topology.json") $ A.encodePretty topology

UpdateTimeAndExit -> do
let byronGenesisFile = tmpAbsPath </> "byron-genesis.json"
shelleyGenesisFile = tmpAbsPath </> "shelley-genesis.json"

currentTime <- H.noteShowIO DTC.getCurrentTime
startTime <- H.noteShow $ DTC.addUTCTime startTimeOffsetSeconds currentTime

-- Update start time in Byron genesis file
eByron <- runExceptT $ Byron.readGenesisData byronGenesisFile
(byronGenesis', _byronHash) <- H.leftFail eByron
let byronGenesis = byronGenesis'{gdStartTime = startTime}
H.lbsWriteFile byronGenesisFile $ canonicalEncodePretty byronGenesis

-- Update start time in Shelley genesis file
eShelley <- H.readJsonFile shelleyGenesisFile
shelleyGenesis' :: ShelleyGenesis <- H.leftFail eShelley
let shelleyGenesis = shelleyGenesis'{sgSystemStart = startTime}
H.lbsWriteFile shelleyGenesisFile $ A.encodePretty shelleyGenesis

-- | Starts a number of nodes, as configured by the value of the 'cardanoNodes'
-- field in the 'CardanoTestnetOptions' argument. Regarding this field, you can either:
Expand Down
23 changes: 22 additions & 1 deletion cardano-testnet/src/Testnet/Start/Types.hs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ module Testnet.Start.Types
, anyShelleyBasedEraToString
, eraToString

, CreateEnvOptions(..)
, CreateEnvUpdateTime(..)
, NodeOption(..)
, isRelayNodeOptions
, cardanoDefaultTestnetNodeOptions
Expand Down Expand Up @@ -88,6 +90,25 @@ data TopologyType
instance Default TopologyType where
def = DirectTopology

data CreateEnvUpdateTime
= CreateEnv
| UpdateTimeAndExit
deriving (Eq, Show)

instance Default CreateEnvUpdateTime where
def = CreateEnv

data CreateEnvOptions = CreateEnvOptions
{ ceoTopologyType :: TopologyType
, ceoUpdateTime :: CreateEnvUpdateTime
} deriving (Eq, Show)

instance Default CreateEnvOptions where
def = CreateEnvOptions
{ ceoTopologyType = def
, ceoUpdateTime = def
}

-- | An abstract node id, used as placeholder in topology files
-- when the actual ports/addresses aren't known yet (i.e. before runtime)
newtype NodeId = NodeId Int
Expand All @@ -107,7 +128,7 @@ data CardanoTestnetCreateEnvOptions = CardanoTestnetCreateEnvOptions
{ createEnvTestnetOptions :: CardanoTestnetOptions
, createEnvGenesisOptions :: GenesisOptions
, createEnvOutputDir :: FilePath
, createEnvTopologyType :: TopologyType
, createEnvCreateEnvOptions :: CreateEnvOptions
} 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 @@ -40,6 +40,7 @@ Usage: cardano-testnet create-env [--num-pool-nodes COUNT]
[--active-slots-coeff DOUBLE]
--output DIRECTORY
[--p2p-topology]
[--update-time]

Create a sandbox for Cardano testnet

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Usage: cardano-testnet create-env [--num-pool-nodes COUNT]
[--active-slots-coeff DOUBLE]
--output DIRECTORY
[--p2p-topology]
[--update-time]

Create a sandbox for Cardano testnet

Expand Down Expand Up @@ -61,4 +62,6 @@ Available options:
--output DIRECTORY Directory where to create the sandbox environment.
--p2p-topology Use P2P topology files instead of "direct" topology
files
--update-time Don't create anything, just update the time stamps in
existing files
-h,--help Show this help text
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE NumericUnderscores #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
Expand All @@ -8,34 +7,27 @@ module Cardano.Testnet.Test.DumpConfig
( hprop_dump_config
) where

import Cardano.Api (BlockNo (..), ChainTip (..), ShelleyGenesis, runExceptT,
sgSystemStart)
import Cardano.Api (ShelleyGenesis, runExceptT, sgSystemStart)
import Cardano.Api.Byron (GenesisData (..))
import qualified Cardano.Api.Byron as Byron

import Cardano.CLI.Type.Output (QueryTipLocalStateOutput (..))
import Cardano.Prelude (canonicalEncodePretty)
import Cardano.Testnet hiding (shelleyGenesisFile)
import Cardano.Testnet.Test.Utils (nodesProduceBlocks)

import Prelude

import qualified Data.Aeson as A
import Data.Aeson.Encode.Pretty (encodePretty)
import qualified Data.ByteString.Lazy.Char8 as B
import Data.Default.Class (def)
import qualified Data.Time.Clock as Time
import GHC.Float (double2Int)
import System.Exit (ExitCode (..))
import System.FilePath ((</>))
import qualified System.Process as IO

import Testnet.Components.Configuration (startTimeOffsetSeconds)
import Testnet.Process.Run (execCli', mkExecConfig)
import Testnet.Property.Util (integrationRetryWorkspace)
import Testnet.Start.Types (GenesisHashesPolicy (..), GenesisOptions (..),
UserProvidedData (..), UserProvidedEnv (..))

import Hedgehog ((===))
import qualified Hedgehog as H
import qualified Hedgehog.Extras as H

Expand Down Expand Up @@ -78,41 +70,6 @@ hprop_dump_config = integrationRetryWorkspace 2 "dump-config-files" $ \tmpDir ->
H.lbsWriteFile shelleyGenesisFile $ encodePretty shelleyGenesis

-- Run testnet with generated config
TestnetRuntime
{ testnetNodes
, testnetMagic
} <- cardanoTestnet testnetOptions genesisOptions conf

-- There should only be one SPO node among three
TestnetNode
{ nodeProcessHandle
, nodeSprocket
} <- case testnetNodes of
[spoNode, _relayNode1, _relayNode2] -> do
(isTestnetNodeSpo <$> testnetNodes) === [True, False, False]
pure spoNode
_ -> H.failure

-- Check that blocks have been produced on the chain after 2 minutes at most
H.byDurationM 5 120 "Expected blocks to be minted" $ do
execConfig <- mkExecConfig tmpDir nodeSprocket testnetMagic
tipStr <- H.noteM $ execCli' execConfig
[ "query", "tip"
, "--output-json"
]
QueryTipLocalStateOutput
{ localStateChainTip = tip
} <- H.nothingFail $ A.decode $ B.pack tipStr

case tip of
ChainTipAtGenesis -> H.failure
ChainTip _ _ (BlockNo blockNo) ->
-- Blocks have been produced if the tip of the chain is > 0
H.assertWith blockNo (> 0)

-- If everything went fine, terminate the node and exit with success
exit <- H.evalIO $ do
IO.terminateProcess nodeProcessHandle
IO.waitForProcess nodeProcessHandle
-- Nodes are expected to exit successfully when terminated
exit === ExitSuccess
runtime <- cardanoTestnet testnetOptions genesisOptions conf

nodesProduceBlocks tmpDir runtime
Loading
Loading