From fe26038f268ed677f67000988a13a3342938df92 Mon Sep 17 00:00:00 2001 From: Sasha Bogicevic Date: Wed, 27 Dec 2023 18:07:46 +0100 Subject: [PATCH 1/2] Wait for cardano-node sync Smoke tests were failing because we would query the protocol-parameters while the node is not yet in sync and that would throw era missmatch because of the latest changes to hydra-node. We solve this by waiting for the cardano-node to be in sync immediately since this workflow is used only when running smoke-tests. We should investigate if this error we get makes sense for the potential users trying to run their hydra-node using the cardano-node that is not fully synced. --- hydra-cluster/bench/Bench/EndToEnd.hs | 4 +-- hydra-cluster/exe/hydra-cluster/Main.hs | 2 -- hydra-cluster/src/CardanoClient.hs | 30 +++++++++++++++-- hydra-cluster/src/CardanoNode.hs | 32 ++++--------------- hydra-cluster/src/Hydra/Cluster/Faucet.hs | 2 +- hydra-cluster/src/Hydra/Cluster/Scenarios.hs | 3 +- hydra-cluster/test/Test/CardanoClientSpec.hs | 4 +-- hydra-cluster/test/Test/CardanoNodeSpec.hs | 3 +- hydra-cluster/test/Test/ChainObserverSpec.hs | 4 +-- hydra-cluster/test/Test/DirectChainSpec.hs | 4 ++- hydra-cluster/test/Test/EndToEndSpec.hs | 16 +++++++--- .../test/Test/Hydra/Cluster/FaucetSpec.hs | 3 +- hydra-tui/test/Hydra/TUISpec.hs | 3 +- 13 files changed, 62 insertions(+), 48 deletions(-) diff --git a/hydra-cluster/bench/Bench/EndToEnd.hs b/hydra-cluster/bench/Bench/EndToEnd.hs index 5a1e9ef0f04..2418a0be88c 100644 --- a/hydra-cluster/bench/Bench/EndToEnd.hs +++ b/hydra-cluster/bench/Bench/EndToEnd.hs @@ -6,8 +6,8 @@ import Hydra.Prelude import Test.Hydra.Prelude import Bench.Summary (Summary (..), makeQuantiles) -import CardanoClient (awaitTransaction, submitTransaction, submitTx) -import CardanoNode (RunningNode (..), withCardanoNodeDevnet) +import CardanoClient (RunningNode (..), awaitTransaction, submitTransaction, submitTx) +import CardanoNode (withCardanoNodeDevnet) import Control.Concurrent.Class.MonadSTM ( MonadSTM (readTVarIO), check, diff --git a/hydra-cluster/exe/hydra-cluster/Main.hs b/hydra-cluster/exe/hydra-cluster/Main.hs index 93109a65236..73323e46c41 100644 --- a/hydra-cluster/exe/hydra-cluster/Main.hs +++ b/hydra-cluster/exe/hydra-cluster/Main.hs @@ -2,7 +2,6 @@ module Main where import Hydra.Prelude -import CardanoClient (waitForFullySynchronized) import CardanoNode (withCardanoNodeDevnet, withCardanoNodeOnKnownNetwork) import Hydra.Cluster.Faucet (publishHydraScriptsAs) import Hydra.Cluster.Fixture (Actor (Faucet)) @@ -25,7 +24,6 @@ run options = case knownNetwork of Just network -> withCardanoNodeOnKnownNetwork fromCardanoNode workDir network $ \node -> do - waitForFullySynchronized fromCardanoNode node publishOrReuseHydraScripts tracer node >>= singlePartyHeadFullLifeCycle tracer workDir node Nothing -> diff --git a/hydra-cluster/src/CardanoClient.hs b/hydra-cluster/src/CardanoClient.hs index 5e5eb538dea..7ac70c70dea 100644 --- a/hydra-cluster/src/CardanoClient.hs +++ b/hydra-cluster/src/CardanoClient.hs @@ -15,9 +15,11 @@ import Hydra.Cardano.Api hiding (Block) import Hydra.Chain.CardanoClient import Cardano.Api.UTxO qualified as UTxO +import Cardano.Ledger.Core (PParams) import Cardano.Slotting.Time (RelativeTime (getRelativeTime), diffRelativeTime, toRelativeTime) -import CardanoNode (NodeLog (..), RunningNode (..)) +import Data.Fixed (Centi) import Data.Map qualified as Map +import Hydra.Cardano.Api qualified as Api import Hydra.Chain.CardanoClient qualified as CardanoClient import Hydra.Logging (Tracer, traceWith) @@ -164,13 +166,35 @@ mkGenesisTx networkId pparams signingKey initialAmount recipients = TxOutDatumNone ReferenceScriptNone +data RunningNode = RunningNode + { nodeSocket :: SocketPath + , networkId :: NetworkId + , pparams :: PParams Api.LedgerEra + } + +-- Logging + +data NodeLog + = MsgNodeCmdSpec Text + | MsgCLI [Text] + | MsgCLIStatus Text Text + | MsgCLIRetry Text + | MsgCLIRetryResult Text Int + | MsgNodeStarting {stateDirectory :: FilePath} + | MsgSocketIsReady FilePath + | MsgSynchronizing {percentDone :: Centi} + | MsgNodeIsReady + deriving stock (Eq, Show, Generic) + deriving anyclass (ToJSON, FromJSON) + -- | Wait until the node is fully caught up with the network. This can take a -- while! waitForFullySynchronized :: Tracer IO NodeLog -> - RunningNode -> + NetworkId -> + SocketPath -> IO () -waitForFullySynchronized tracer RunningNode{nodeSocket, networkId} = do +waitForFullySynchronized tracer networkId nodeSocket = do systemStart <- querySystemStart networkId nodeSocket QueryTip check systemStart where diff --git a/hydra-cluster/src/CardanoNode.hs b/hydra-cluster/src/CardanoNode.hs index 2e321fa8b1e..c73551e0e49 100644 --- a/hydra-cluster/src/CardanoNode.hs +++ b/hydra-cluster/src/CardanoNode.hs @@ -4,13 +4,12 @@ module CardanoNode where import Hydra.Prelude -import Cardano.Ledger.Core (PParams) +import CardanoClient (NodeLog (..), RunningNode (..), waitForFullySynchronized) import Control.Lens ((?~), (^?!)) import Control.Tracer (Tracer, traceWith) import Data.Aeson (Value (String), (.=)) import Data.Aeson qualified as Aeson import Data.Aeson.Lens (atKey, key, _Number) -import Data.Fixed (Centi) import Data.Text qualified as Text import Data.Time.Clock.POSIX (posixSecondsToUTCTime, utcTimeToPOSIXSeconds) import Hydra.Cardano.Api (AsType (AsPaymentKey), File (..), NetworkId, PaymentKey, SigningKey, SocketPath, VerificationKey, generateSigningKey, getVerificationKey) @@ -40,12 +39,6 @@ type Port = Int newtype NodeId = NodeId Int deriving newtype (Eq, Show, Num, ToJSON, FromJSON) -data RunningNode = RunningNode - { nodeSocket :: SocketPath - , networkId :: NetworkId - , pparams :: PParams Api.LedgerEra - } - -- | Configuration parameters for a single node devnet data DevnetConfig = DevnetConfig { stateDirectory :: FilePath @@ -121,7 +114,7 @@ withCardanoNodeDevnet :: IO a withCardanoNodeDevnet tracer stateDirectory action = do args <- setupCardanoDevnet stateDirectory - withCardanoNode tracer stateDirectory args $ \nodeSocket -> do + withCardanoNode tracer stateDirectory args networkId $ \nodeSocket -> do traceWith tracer MsgNodeIsReady pparams <- queryProtocolParameters networkId nodeSocket QueryTip let rn = @@ -147,7 +140,7 @@ withCardanoNodeOnKnownNetwork :: withCardanoNodeOnKnownNetwork tracer workDir knownNetwork action = do copyKnownNetworkFiles networkId <- readNetworkId - withCardanoNode tracer workDir args $ \nodeSocket -> do + withCardanoNode tracer workDir args networkId $ \nodeSocket -> do traceWith tracer MsgNodeIsReady pparams <- queryProtocolParameters networkId nodeSocket QueryTip let rn = @@ -279,9 +272,10 @@ withCardanoNode :: Tracer IO NodeLog -> FilePath -> CardanoNodeArgs -> + NetworkId -> (SocketPath -> IO a) -> IO a -withCardanoNode tr stateDirectory args@CardanoNodeArgs{nodeSocket} action = do +withCardanoNode tr stateDirectory args@CardanoNodeArgs{nodeSocket} networkId action = do traceWith tr $ MsgNodeCmdSpec (show $ cmdspec process) traceWith tr $ MsgNodeStarting{stateDirectory} withLogFile logFilePath $ \out -> do @@ -306,6 +300,7 @@ withCardanoNode tr stateDirectory args@CardanoNodeArgs{nodeSocket} action = do waitForNode = do let nodeSocketPath = File socketPath waitForSocket nodeSocketPath + _ <- waitForFullySynchronized tr networkId nodeSocketPath traceWith tr $ MsgSocketIsReady $ unFile nodeSocketPath action nodeSocketPath @@ -416,21 +411,6 @@ data ProcessHasExited = ProcessHasExited Text ExitCode instance Exception ProcessHasExited --- Logging - -data NodeLog - = MsgNodeCmdSpec Text - | MsgCLI [Text] - | MsgCLIStatus Text Text - | MsgCLIRetry Text - | MsgCLIRetryResult Text Int - | MsgNodeStarting {stateDirectory :: FilePath} - | MsgSocketIsReady FilePath - | MsgSynchronizing {percentDone :: Centi} - | MsgNodeIsReady - deriving stock (Eq, Show, Generic) - deriving anyclass (ToJSON, FromJSON) - -- -- Helpers -- diff --git a/hydra-cluster/src/Hydra/Cluster/Faucet.hs b/hydra-cluster/src/Hydra/Cluster/Faucet.hs index 28bab418101..3cfd8421b7c 100644 --- a/hydra-cluster/src/Hydra/Cluster/Faucet.hs +++ b/hydra-cluster/src/Hydra/Cluster/Faucet.hs @@ -8,6 +8,7 @@ import Cardano.Api.UTxO qualified as UTxO import Cardano.Ledger.Core (PParams) import CardanoClient ( QueryPoint (QueryTip), + RunningNode (..), SubmitTransactionException, awaitTransaction, buildAddress, @@ -18,7 +19,6 @@ import CardanoClient ( submitTransaction, waitForPayment, ) -import CardanoNode (RunningNode (..)) import Control.Exception (IOException) import Control.Monad.Class.MonadThrow (Handler (Handler), catches) import Control.Tracer (Tracer, traceWith) diff --git a/hydra-cluster/src/Hydra/Cluster/Scenarios.hs b/hydra-cluster/src/Hydra/Cluster/Scenarios.hs index 78d60a2f012..b5939319740 100644 --- a/hydra-cluster/src/Hydra/Cluster/Scenarios.hs +++ b/hydra-cluster/src/Hydra/Cluster/Scenarios.hs @@ -8,13 +8,14 @@ import Test.Hydra.Prelude import Cardano.Api.UTxO qualified as UTxO import CardanoClient ( + NodeLog, QueryPoint (QueryTip), + RunningNode (..), buildTransaction, queryTip, queryUTxOFor, submitTx, ) -import CardanoNode (NodeLog, RunningNode (..)) import Control.Concurrent.Async (mapConcurrently_) import Control.Lens ((^?)) import Data.Aeson (Value, object, (.=)) diff --git a/hydra-cluster/test/Test/CardanoClientSpec.hs b/hydra-cluster/test/Test/CardanoClientSpec.hs index 740752a1186..dab2b2c93d1 100644 --- a/hydra-cluster/test/Test/CardanoClientSpec.hs +++ b/hydra-cluster/test/Test/CardanoClientSpec.hs @@ -3,8 +3,8 @@ module Test.CardanoClientSpec where import Hydra.Prelude import Test.Hydra.Prelude -import CardanoClient (QueryPoint (..), queryGenesisParameters) -import CardanoNode (RunningNode (..), withCardanoNodeDevnet) +import CardanoClient (QueryPoint (..), RunningNode (..), queryGenesisParameters) +import CardanoNode (withCardanoNodeDevnet) import Data.Aeson ((.:)) import Data.Aeson qualified as Aeson import Hydra.Cardano.Api (GenesisParameters (..)) diff --git a/hydra-cluster/test/Test/CardanoNodeSpec.hs b/hydra-cluster/test/Test/CardanoNodeSpec.hs index ef709475ed0..be6ff0e60f6 100644 --- a/hydra-cluster/test/Test/CardanoNodeSpec.hs +++ b/hydra-cluster/test/Test/CardanoNodeSpec.hs @@ -4,12 +4,11 @@ import Hydra.Prelude import Test.Hydra.Prelude import CardanoNode ( - RunningNode (..), getCardanoNodeVersion, withCardanoNodeDevnet, ) -import CardanoClient (queryTipSlotNo) +import CardanoClient (RunningNode (..), queryTipSlotNo) import Hydra.Cardano.Api (NetworkId (Testnet), NetworkMagic (NetworkMagic), unFile) import Hydra.Logging (showLogsOnFailure) import System.Directory (doesFileExist) diff --git a/hydra-cluster/test/Test/ChainObserverSpec.hs b/hydra-cluster/test/Test/ChainObserverSpec.hs index 20bb7e408e9..6c9e17140a3 100644 --- a/hydra-cluster/test/Test/ChainObserverSpec.hs +++ b/hydra-cluster/test/Test/ChainObserverSpec.hs @@ -9,8 +9,8 @@ module Test.ChainObserverSpec where import Hydra.Prelude import Test.Hydra.Prelude -import CardanoClient (submitTx) -import CardanoNode (NodeLog, RunningNode (..), withCardanoNodeDevnet) +import CardanoClient (NodeLog, RunningNode (..), submitTx) +import CardanoNode (withCardanoNodeDevnet) import Control.Concurrent.Class.MonadSTM (modifyTVar', newTVarIO, readTVarIO) import Control.Exception (IOException) import Control.Lens ((^?)) diff --git a/hydra-cluster/test/Test/DirectChainSpec.hs b/hydra-cluster/test/Test/DirectChainSpec.hs index 51cad68a59c..b5a6148243d 100644 --- a/hydra-cluster/test/Test/DirectChainSpec.hs +++ b/hydra-cluster/test/Test/DirectChainSpec.hs @@ -7,14 +7,16 @@ import Test.Hydra.Prelude import Cardano.Api.UTxO (UTxO' (UTxO, toMap)) import CardanoClient ( + NodeLog, QueryPoint (QueryTip), + RunningNode (..), buildAddress, queryTip, queryUTxO, submitTx, waitForUTxO, ) -import CardanoNode (NodeLog, RunningNode (..), withCardanoNodeDevnet) +import CardanoNode (withCardanoNodeDevnet) import Control.Concurrent.STM (newEmptyTMVarIO, takeTMVar) import Control.Concurrent.STM.TMVar (putTMVar) import Hydra.Cardano.Api ( diff --git a/hydra-cluster/test/Test/EndToEndSpec.hs b/hydra-cluster/test/Test/EndToEndSpec.hs index 15aaf949e5d..944aad7e999 100644 --- a/hydra-cluster/test/Test/EndToEndSpec.hs +++ b/hydra-cluster/test/Test/EndToEndSpec.hs @@ -7,10 +7,18 @@ import Hydra.Prelude import Test.Hydra.Prelude import Cardano.Api.UTxO qualified as UTxO -import CardanoClient (QueryPoint (..), queryEpochNo, queryGenesisParameters, queryTip, queryTipSlotNo, submitTx, waitForUTxO) +import CardanoClient ( + QueryPoint (..), + RunningNode (..), + queryEpochNo, + queryGenesisParameters, + queryTip, + queryTipSlotNo, + submitTx, + waitForUTxO, + ) import CardanoNode ( CardanoNodeArgs (..), - RunningNode (..), forkIntoConwayInEpoch, setupCardanoDevnet, unsafeDecodeJsonFile, @@ -522,7 +530,7 @@ spec = around (showLogsOnFailure "EndToEndSpec") $ do withClusterTempDir "unsupported-era" $ \tmpDir -> do args <- setupCardanoDevnet tmpDir forkIntoConwayInEpoch tmpDir args 1 - withCardanoNode (contramap FromCardanoNode tracer) tmpDir args $ \nodeSocket -> do + withCardanoNode (contramap FromCardanoNode tracer) tmpDir args defaultNetworkId $ \nodeSocket -> do let pparams = defaultPParams let node = RunningNode{nodeSocket, networkId = defaultNetworkId, pparams} hydraScriptsTxId <- publishHydraScriptsAs node Faucet @@ -542,7 +550,7 @@ spec = around (showLogsOnFailure "EndToEndSpec") $ do withClusterTempDir "unsupported-era-startup" $ \tmpDir -> do args <- setupCardanoDevnet tmpDir forkIntoConwayInEpoch tmpDir args 1 - withCardanoNode (contramap FromCardanoNode tracer) tmpDir args $ \nodeSocket -> do + withCardanoNode (contramap FromCardanoNode tracer) tmpDir args defaultNetworkId $ \nodeSocket -> do let pparams = defaultPParams let node = RunningNode{nodeSocket, networkId = defaultNetworkId, pparams} hydraScriptsTxId <- publishHydraScriptsAs node Faucet diff --git a/hydra-cluster/test/Test/Hydra/Cluster/FaucetSpec.hs b/hydra-cluster/test/Test/Hydra/Cluster/FaucetSpec.hs index 048c74f81ce..65a2c921480 100644 --- a/hydra-cluster/test/Test/Hydra/Cluster/FaucetSpec.hs +++ b/hydra-cluster/test/Test/Hydra/Cluster/FaucetSpec.hs @@ -3,7 +3,8 @@ module Test.Hydra.Cluster.FaucetSpec where import Hydra.Prelude import Test.Hydra.Prelude -import CardanoNode (RunningNode (..), withCardanoNodeDevnet) +import CardanoClient (RunningNode (..)) +import CardanoNode (withCardanoNodeDevnet) import Control.Concurrent.Async (replicateConcurrently_) import Hydra.Cardano.Api (AssetId (AdaAssetId), selectAsset, txOutValue) import Hydra.Chain.CardanoClient (QueryPoint (..), queryUTxOFor) diff --git a/hydra-tui/test/Hydra/TUISpec.hs b/hydra-tui/test/Hydra/TUISpec.hs index 26e091c665b..6fd7828221c 100644 --- a/hydra-tui/test/Hydra/TUISpec.hs +++ b/hydra-tui/test/Hydra/TUISpec.hs @@ -7,7 +7,8 @@ import Hydra.Prelude import Test.Hydra.Prelude import Blaze.ByteString.Builder.Char8 (writeChar) -import CardanoNode (NodeLog, RunningNode (..), withCardanoNodeDevnet) +import CardanoClient (NodeLog, RunningNode (..)) +import CardanoNode (withCardanoNodeDevnet) import Control.Concurrent.Class.MonadSTM (newTQueueIO, readTQueue, tryReadTQueue, writeTQueue) import Data.ByteString qualified as BS import Graphics.Vty ( From e6fcb0ebbfc54bbfd1153324b4c49e604b86c8f8 Mon Sep 17 00:00:00 2001 From: Sasha Bogicevic Date: Wed, 27 Dec 2023 18:28:03 +0100 Subject: [PATCH 2/2] Explain why we need to wait --- hydra-cluster/src/CardanoNode.hs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hydra-cluster/src/CardanoNode.hs b/hydra-cluster/src/CardanoNode.hs index c73551e0e49..716726fe27e 100644 --- a/hydra-cluster/src/CardanoNode.hs +++ b/hydra-cluster/src/CardanoNode.hs @@ -300,6 +300,9 @@ withCardanoNode tr stateDirectory args@CardanoNodeArgs{nodeSocket} networkId act waitForNode = do let nodeSocketPath = File socketPath waitForSocket nodeSocketPath + -- we wait for synchronization since otherwise we will receive a query + -- exception when trying to obtain pparams and the era is not the one we + -- expect. _ <- waitForFullySynchronized tr networkId nodeSocketPath traceWith tr $ MsgSocketIsReady $ unFile nodeSocketPath action nodeSocketPath