diff --git a/hydra-cluster/src/Hydra/Cluster/Scenarios.hs b/hydra-cluster/src/Hydra/Cluster/Scenarios.hs index 91e82b2411c..51ec8f9d220 100644 --- a/hydra-cluster/src/Hydra/Cluster/Scenarios.hs +++ b/hydra-cluster/src/Hydra/Cluster/Scenarios.hs @@ -1096,6 +1096,48 @@ threeNodesNoErrorsOnOpen tracer tmpDir node@RunningNode{nodeSocket} hydraScripts Right _headIsOpen -> pure () +-- | Hydra nodes ABC run on ABC cluster and connect to each other. +-- Hydra nodes BC shut down. +-- Hydra nodes BC run on BC cluster and connect to each other. +-- Hydra nodes BC shut down. +-- Hydra nodes BC run and connect ABC cluster again. +nodeCanSupportMultipleEtcdClusters :: Tracer IO EndToEndLog -> FilePath -> RunningNode -> [TxId] -> IO () +nodeCanSupportMultipleEtcdClusters tracer workDir RunningNode{networkId, nodeSocket} hydraScriptsTxId = do + let contestationPeriod = UnsafeContestationPeriod 2 + let depositDeadline = UnsafeDepositDeadline 50 + + aliceChainConfig <- + chainConfigFor Alice workDir nodeSocket hydraScriptsTxId [Bob, Carol] contestationPeriod depositDeadline + <&> setNetworkId networkId + bobChainConfig <- + chainConfigFor Bob workDir nodeSocket hydraScriptsTxId [Alice, Carol] contestationPeriod depositDeadline + <&> setNetworkId networkId + carolChainConfig <- + chainConfigFor Carol workDir nodeSocket hydraScriptsTxId [Alice, Bob] contestationPeriod depositDeadline + <&> setNetworkId networkId + + let hydraTracer = contramap FromHydraNode tracer + + withHydraNode hydraTracer aliceChainConfig workDir 1 aliceSk [bobVk, carolVk] [1, 2, 3] $ \n1 -> do + withHydraNode hydraTracer bobChainConfig workDir 2 bobSk [aliceVk, carolVk] [1, 2, 3] $ \n2 -> do + withHydraNode hydraTracer carolChainConfig workDir 3 carolSk [aliceVk, bobVk] [1, 2, 3] $ \n3 -> do + waitForNodesConnected hydraTracer 30 $ n1 :| [n2, n3] + + bobChainConfig' <- + chainConfigFor Bob workDir nodeSocket hydraScriptsTxId [Carol] contestationPeriod depositDeadline + <&> setNetworkId networkId + carolChainConfig' <- + chainConfigFor Carol workDir nodeSocket hydraScriptsTxId [Bob] contestationPeriod depositDeadline + <&> setNetworkId networkId + + withHydraNode hydraTracer bobChainConfig' workDir 2 bobSk [carolVk] [2, 3] $ \n2 -> do + withHydraNode hydraTracer carolChainConfig' workDir 3 carolSk [bobVk] [2, 3] $ \n3 -> do + waitForNodesConnected hydraTracer 30 $ n2 :| [n3] + + withHydraNode hydraTracer bobChainConfig workDir 2 bobSk [aliceVk, carolVk] [1, 2, 3] $ \n2 -> do + withHydraNode hydraTracer carolChainConfig workDir 3 carolSk [aliceVk, bobVk] [1, 2, 3] $ \n3 -> do + waitForNodesConnected hydraTracer 30 $ n1 :| [n2, n3] + -- | Two hydra node setup where Alice is wrongly configured to use Carol's -- cardano keys instead of Bob's which will prevent him to be notified the -- `HeadIsInitializing` but he should still receive some notification. diff --git a/hydra-cluster/test/Test/EndToEndSpec.hs b/hydra-cluster/test/Test/EndToEndSpec.hs index b37cdd7653f..dd48dc9e154 100644 --- a/hydra-cluster/test/Test/EndToEndSpec.hs +++ b/hydra-cluster/test/Test/EndToEndSpec.hs @@ -60,6 +60,7 @@ import Hydra.Cluster.Scenarios ( checkFanout, headIsInitializingWith, initWithWrongKeys, + nodeCanSupportMultipleEtcdClusters, nodeReObservesOnChainTxs, oneOfThreeNodesStopsForAWhile, persistenceCanLoadWithEmptyCommit, @@ -282,6 +283,13 @@ spec = around (showLogsOnFailure "EndToEndSpec") $ do publishHydraScriptsAs node Faucet >>= threeNodesNoErrorsOnOpen tracer tmpDir node + it "node can support multiple etcd clusters" $ \tracer -> + failAfter 60 $ + withClusterTempDir $ \tmpDir -> do + withCardanoNodeDevnet (contramap FromCardanoNode tracer) tmpDir $ \node -> do + publishHydraScriptsAs node Faucet + >>= nodeCanSupportMultipleEtcdClusters tracer tmpDir node + it "inits a Head, processes a single Cardano transaction and closes it again" $ \tracer -> failAfter 60 $ withClusterTempDir $ \tmpDir -> do diff --git a/hydra-node/src/Hydra/Network/Etcd.hs b/hydra-node/src/Hydra/Network/Etcd.hs index 7ffb33d1797..13ed19ed2f7 100644 --- a/hydra-node/src/Hydra/Network/Etcd.hs +++ b/hydra-node/src/Hydra/Network/Etcd.hs @@ -44,6 +44,7 @@ module Hydra.Network.Etcd where import Hydra.Prelude import Cardano.Binary (decodeFull', serialize') +import Cardano.Crypto.Hash (SHA256, hashToStringAsHex, hashWithSerialiser) import Control.Concurrent.Class.MonadSTM ( modifyTVar', newTBQueueIO, @@ -61,6 +62,7 @@ import Data.Aeson qualified as Aeson import Data.Aeson.Types (Value) import Data.Bits ((.|.)) import Data.ByteString qualified as BS +import Data.ByteString.Char8 qualified as BS8 import Data.List ((\\)) import Data.List qualified as List import Data.Map qualified as Map @@ -205,7 +207,7 @@ withEtcdNetwork tracer protocolVersion config callback action = do $ concat [ -- NOTE: Must be used in clusterPeers ["--name", show advertise] - , ["--data-dir", persistenceDir "etcd"] + , ["--data-dir", persistenceDir "etcd" hashToStringAsHex (hashWithSerialiser @SHA256 toCBOR $ BS8.pack clusterPeers)] , ["--listen-peer-urls", httpUrl listen] , ["--initial-advertise-peer-urls", httpUrl advertise] , ["--listen-client-urls", httpUrl clientHost] diff --git a/hydra-node/test/Hydra/NetworkSpec.hs b/hydra-node/test/Hydra/NetworkSpec.hs index 6292317fe66..dd2d4df0940 100644 --- a/hydra-node/test/Hydra/NetworkSpec.hs +++ b/hydra-node/test/Hydra/NetworkSpec.hs @@ -113,7 +113,7 @@ spec = do it "emits connectivity events" $ \tracer -> do withTempDir "test-etcd" $ \tmp -> do - failAfter 20 $ do + failAfter 30 $ do PeerConfig3{aliceConfig, bobConfig, carolConfig} <- setup3Peers tmp -- Record and assert connectivity events from alice's perspective (recordReceived, _, waitConnectivity) <- newRecordingCallback