| Safe Haskell | Safe-Inferred |
|---|---|
| Language | GHC2021 |
HydraNode
Synopsis
- data HydraClient = HydraClient {
- hydraNodeId :: Int
- apiHost :: Host
- monitoringPort :: Maybe PortNumber
- connection :: Connection
- tracer :: Tracer IO HydraNodeLog
- apiEncoding :: ApiEncoding
- workDir :: Maybe FilePath
- data HydraNodePorts = HydraNodePorts {
- apiPort :: PortNumber
- listenPort :: PortNumber
- monitoringPort :: PortNumber
- allocateHydraNodePortsFor :: [Int] -> IO (Map Int HydraNodePorts)
- getProtocolParameters :: HydraClient -> IO (PParams LedgerEra)
- getSnapshotConfirmed :: HydraClient -> IO (ConfirmedSnapshot Tx)
- getSnapshotUTxO :: HydraClient -> IO UTxO
- input :: Text -> [Pair] -> Value
- output :: Text -> [Pair] -> Value
- postDecommit :: HydraClient -> Tx -> IO ()
- prepareHydraNode :: HasCallStack => ChainConfig -> FilePath -> Int -> Secret (SigningKey HydraKey) -> [VerificationKey HydraKey] -> Map Int HydraNodePorts -> (Value -> Value) -> IO RunOptions
- requestCommitTx :: HydraClient -> UTxO -> IO Tx
- scaledFailAfter :: HasCallStack => NominalDiffTime -> IO a -> IO a
- send :: HydraClient -> Value -> IO ()
- waitFor :: HasCallStack => Tracer IO HydraNodeLog -> NominalDiffTime -> [HydraClient] -> Value -> IO ()
- waitForAllMatch :: (Eq a, Show a, HasCallStack) => NominalDiffTime -> [HydraClient] -> (Value -> Maybe a) -> IO a
- waitForNodesConnected :: Tracer IO HydraNodeLog -> NominalDiffTime -> NonEmpty HydraClient -> IO ()
- waitForNodesDisconnected :: Tracer IO HydraNodeLog -> NominalDiffTime -> NonEmpty HydraClient -> IO ()
- waitForNodesSynced :: HasCallStack => NominalDiffTime -> [HydraClient] -> IO ()
- waitForSnapshotUTxO :: HasCallStack => NominalDiffTime -> HydraClient -> UTxO -> IO ()
- waitMatch :: HasCallStack => NominalDiffTime -> HydraClient -> (Value -> Maybe a) -> IO a
- withConnectionToNode :: forall a. Tracer IO HydraNodeLog -> Int -> Host -> Maybe PortNumber -> (HydraClient -> IO a) -> IO a
- withHydraCluster :: HasCallStack => Tracer IO HydraNodeLog -> Timing -> FilePath -> SocketPath -> Int -> [(VerificationKey PaymentKey, Secret (SigningKey PaymentKey))] -> [Secret (SigningKey HydraKey)] -> [TxId] -> (NonEmpty HydraClient -> IO a) -> IO a
- withHydraNode :: HasCallStack => Tracer IO HydraNodeLog -> NominalDiffTime -> ChainConfig -> FilePath -> Int -> Secret (SigningKey HydraKey) -> [VerificationKey HydraKey] -> Map Int HydraNodePorts -> (HydraClient -> IO a) -> IO a
- withHydraNodeCatchingUp :: HasCallStack => Tracer IO HydraNodeLog -> ChainConfig -> FilePath -> Int -> Secret (SigningKey HydraKey) -> [VerificationKey HydraKey] -> Map Int HydraNodePorts -> (HydraClient -> IO a) -> IO a
- withPreparedHydraNode :: HasCallStack => Tracer IO HydraNodeLog -> FilePath -> Int -> RunOptions -> (HydraClient -> IO a) -> IO a
- withPreparedHydraNodeWithEnv :: HasCallStack => [(String, String)] -> Tracer IO HydraNodeLog -> FilePath -> Int -> RunOptions -> (HydraClient -> IO a) -> IO a
- withSoloHydraNode :: HasCallStack => Tracer IO HydraNodeLog -> NominalDiffTime -> ChainConfig -> FilePath -> Int -> Secret (SigningKey HydraKey) -> [VerificationKey HydraKey] -> (HydraClient -> IO a) -> IO a
- withSoloHydraNodeCatchingUp :: HasCallStack => Tracer IO HydraNodeLog -> ChainConfig -> FilePath -> Int -> Secret (SigningKey HydraKey) -> [VerificationKey HydraKey] -> (HydraClient -> IO a) -> IO a
- withUnsyncedHydraNode :: HasCallStack => Tracer IO HydraNodeLog -> ChainConfig -> FilePath -> Int -> Secret (SigningKey HydraKey) -> [VerificationKey HydraKey] -> Map Int HydraNodePorts -> (HydraClient -> IO a) -> IO a
- withUnsyncedSoloHydraNode :: HasCallStack => Tracer IO HydraNodeLog -> ChainConfig -> FilePath -> Int -> Secret (SigningKey HydraKey) -> [VerificationKey HydraKey] -> (HydraClient -> IO a) -> IO a
- waitNext :: HasCallStack => HydraClient -> IO Value
- scaleWaitTime :: NominalDiffTime -> IO NominalDiffTime
- waitForAll :: HasCallStack => Tracer IO HydraNodeLog -> NominalDiffTime -> [HydraClient] -> [Value] -> IO ()
- waitNoMatch :: HasCallStack => NominalDiffTime -> HydraClient -> (Value -> Maybe a) -> IO ()
- waitMatchWith :: HasCallStack => NominalDiffTime -> HydraClient -> (Value -> Maybe a) -> IO a
- getMetrics :: HasCallStack => HydraClient -> IO ByteString
- withHydraClusterWith :: HasCallStack => Maybe String -> (RunOptions -> RunOptions) -> Tracer IO HydraNodeLog -> Timing -> FilePath -> SocketPath -> Int -> [(VerificationKey PaymentKey, Secret (SigningKey PaymentKey))] -> [Secret (SigningKey HydraKey)] -> [TxId] -> (NonEmpty HydraClient -> IO a) -> IO a
- withHydraNodeWith :: HasCallStack => Maybe String -> (RunOptions -> RunOptions) -> Tracer IO HydraNodeLog -> NominalDiffTime -> ChainConfig -> FilePath -> Int -> Secret (SigningKey HydraKey) -> [VerificationKey HydraKey] -> Map Int HydraNodePorts -> (HydraClient -> IO a) -> IO a
- allocateHydraNodePorts :: IO HydraNodePorts
- soloHydraNodePortsCache :: IORef (Map (FilePath, Int) HydraNodePorts)
- soloHydraNodePortsFor :: FilePath -> Int -> IO HydraNodePorts
- preparePParams :: ChainConfig -> FilePath -> (Value -> Value) -> IO FilePath
- withPreparedHydraNodeWithQuery :: HasCallStack => Maybe String -> [(String, String)] -> Tracer IO HydraNodeLog -> FilePath -> Int -> RunOptions -> (HydraClient -> IO a) -> IO a
- withConnectionToNodeHost :: forall a. Tracer IO HydraNodeLog -> Int -> Host -> Maybe PortNumber -> Maybe String -> (HydraClient -> IO a) -> IO a
- data HydraNodeLog
- = HydraNodeCommandSpec {
- cmd :: Text
- | NodeStarted { }
- | SentMessage { }
- | StartWaiting { }
- | ReceivedMessage { }
- | EndWaiting { }
- = HydraNodeCommandSpec {
Documentation
data HydraClient Source #
Constructors
| HydraClient | |
Fields
| |
data HydraNodePorts Source #
The three ports a hydra-node binds: API, peer-to-peer listen, and the
optional Prometheus monitoring endpoint. Callers allocate these via
allocateHydraNodePorts (or pre-allocate a full cluster) and thread them
through prepareHydraNode / withHydraNode.
Constructors
| HydraNodePorts | |
Fields
| |
Instances
| Show HydraNodePorts Source # | |
| Eq HydraNodePorts Source # | |
Defined in HydraNode Methods (==) :: HydraNodePorts -> HydraNodePorts -> Bool Source # (/=) :: HydraNodePorts -> HydraNodePorts -> Bool Source # | |
allocateHydraNodePortsFor :: [Int] -> IO (Map Int HydraNodePorts) Source #
Allocate ports for every node in a cluster up front. The returned map
must be passed to every prepareHydraNode / withHydraNode call for
nodes in this cluster so peers can be addressed correctly.
Listen ports are taken via randomUnusedTCPPortsWithDerived so each
listen port's derived etcd client port — peerPortToClientPort — is
actually held bound at allocation time. That defends against two
failure modes: an unrelated process on the host occupying the derived
port (which a plain randomUnusedTCPPorts would not catch and which
explodes as EADDRINUSE the moment etcd starts), and an unlucky draw
where the derived port lands on top of another node's api/monitoring
port (which used to make the GRPC client talk to Warp instead of
etcd).
Api and monitoring ports are then acquired in a second batch and checked to be disjoint from both the listen ports and the derived client ports; on collision we retry that second batch.
getProtocolParameters :: HydraClient -> IO (PParams LedgerEra) Source #
Get the protocol-parameters from the hydra-node.
getSnapshotConfirmed :: HydraClient -> IO (ConfirmedSnapshot Tx) Source #
Get the latest snapshot from the hydra-node. NOTE: While we usually
avoid parsing responses using the same data types as the system under test,
this parses the response as a ConfirmedSnapshot type as we often need to pick it apart.
getSnapshotUTxO :: HydraClient -> IO UTxO Source #
Get the latest snapshot UTxO from the hydra-node. NOTE: While we usually
avoid parsing responses using the same data types as the system under test,
this parses the response as a UTxO type as we often need to pick it apart.
output :: Text -> [Pair] -> Value Source #
Create an output as expected by waitFor and waitForAll.
postDecommit :: HydraClient -> Tx -> IO () Source #
Submit a decommit transaction to the hydra-node.
prepareHydraNode :: HasCallStack => ChainConfig -> FilePath -> Int -> Secret (SigningKey HydraKey) -> [VerificationKey HydraKey] -> Map Int HydraNodePorts -> (Value -> Value) -> IO RunOptions Source #
Prepare RunOptions to run a hydra-node with given ChainConfig and using the config from
config/.
The nodePorts map must contain an entry for this hydraNodeId and for
every peer this node should connect to. Use allocateHydraNodePortsFor to
build it for a cluster, or allocateHydraNodePorts + a singleton map for a
standalone node.
requestCommitTx :: HydraClient -> UTxO -> IO Tx Source #
Helper to make it easy to obtain a commit tx using some wallet utxo
scaledFailAfter :: HasCallStack => NominalDiffTime -> IO a -> IO a Source #
failAfter with the budget scaled like scaleWaitTime. Use for
whole-test backstops in end-to-end tests.
send :: HydraClient -> Value -> IO () Source #
waitFor :: HasCallStack => Tracer IO HydraNodeLog -> NominalDiffTime -> [HydraClient] -> Value -> IO () Source #
Wait some time for a single API server output from each of given nodes.
This function waits for delay seconds for message expected to be seen by all
given nodes.
waitForAllMatch :: (Eq a, Show a, HasCallStack) => NominalDiffTime -> [HydraClient] -> (Value -> Maybe a) -> IO a Source #
Wait up to some delay for some JSON Value to match given function.
This is a generalisation of waitMatch to multiple nodes.
waitForNodesConnected :: Tracer IO HydraNodeLog -> NominalDiffTime -> NonEmpty HydraClient -> IO () Source #
waitForNodesDisconnected :: Tracer IO HydraNodeLog -> NominalDiffTime -> NonEmpty HydraClient -> IO () Source #
waitForNodesSynced :: HasCallStack => NominalDiffTime -> [HydraClient] -> IO () Source #
waitForSnapshotUTxO :: HasCallStack => NominalDiffTime -> HydraClient -> UTxO -> IO () Source #
Wait for the node's confirmed snapshot to hold exactly the given UTxO.
NOTE: snapshotutxo serves the latest confirmed snapshot, which can still
predate an increment or decommit just after its finalisation event. Sampling
it once therefore races on a slow machine, reporting the UTxO as it was one
snapshot ago. The last value seen is kept so that a genuine mismatch is still
reported as a mismatch, rather than as a bare timeout.
waitMatch :: HasCallStack => NominalDiffTime -> HydraClient -> (Value -> Maybe a) -> IO a Source #
Wait up to some time for an API server output to match the given predicate.
The budget is scaled to the environment, see scaleWaitTime.
withConnectionToNode :: forall a. Tracer IO HydraNodeLog -> Int -> Host -> Maybe PortNumber -> (HydraClient -> IO a) -> IO a Source #
Arguments
| :: HasCallStack | |
| => Tracer IO HydraNodeLog | |
| -> Timing | |
| -> FilePath | |
| -> SocketPath | |
| -> Int | First node id This sets the starting point for assigning ports |
| -> [(VerificationKey PaymentKey, Secret (SigningKey PaymentKey))] | NOTE: This decides on the size of the cluster! |
| -> [Secret (SigningKey HydraKey)] | |
| -> [TxId] | Transaction ids at which Hydra scripts should have been published. |
| -> (NonEmpty HydraClient -> IO a) | |
| -> IO a |
withHydraNode :: HasCallStack => Tracer IO HydraNodeLog -> NominalDiffTime -> ChainConfig -> FilePath -> Int -> Secret (SigningKey HydraKey) -> [VerificationKey HydraKey] -> Map Int HydraNodePorts -> (HydraClient -> IO a) -> IO a Source #
Run a hydra-node just like withHydraNode; but before running any
action, observe a Greetings message with the node in sync first. NOTE
that importantly, any messages seen BEFORE we observe this will be lost;
i.e. unobservable by subsequent waitFors.
See prepareHydraNode for how to build the port map.
withHydraNodeCatchingUp :: HasCallStack => Tracer IO HydraNodeLog -> ChainConfig -> FilePath -> Int -> Secret (SigningKey HydraKey) -> [VerificationKey HydraKey] -> Map Int HydraNodePorts -> (HydraClient -> IO a) -> IO a Source #
Run a hydra-node with given ChainConfig and using the config from
config and catching up with chain backend/.
withPreparedHydraNode :: HasCallStack => Tracer IO HydraNodeLog -> FilePath -> Int -> RunOptions -> (HydraClient -> IO a) -> IO a Source #
Run a hydra-node with given RunOptions.
withPreparedHydraNodeWithEnv :: HasCallStack => [(String, String)] -> Tracer IO HydraNodeLog -> FilePath -> Int -> RunOptions -> (HydraClient -> IO a) -> IO a Source #
Like withPreparedHydraNode but with extra environment entries for the
hydra-node process (also inherited by its etcd child). Use this instead of
a process-global setEnv, which would leak into every other concurrently
spawned node.
withSoloHydraNode :: HasCallStack => Tracer IO HydraNodeLog -> NominalDiffTime -> ChainConfig -> FilePath -> Int -> Secret (SigningKey HydraKey) -> [VerificationKey HydraKey] -> (HydraClient -> IO a) -> IO a Source #
Convenience: run a single hydra-node with no peers and freshly
allocated dynamic ports. Equivalent to withHydraNode with a singleton
port map.
withSoloHydraNodeCatchingUp :: HasCallStack => Tracer IO HydraNodeLog -> ChainConfig -> FilePath -> Int -> Secret (SigningKey HydraKey) -> [VerificationKey HydraKey] -> (HydraClient -> IO a) -> IO a Source #
Convenience: withHydraNodeCatchingUp for a single node with freshly
allocated dynamic ports.
withUnsyncedHydraNode :: HasCallStack => Tracer IO HydraNodeLog -> ChainConfig -> FilePath -> Int -> Secret (SigningKey HydraKey) -> [VerificationKey HydraKey] -> Map Int HydraNodePorts -> (HydraClient -> IO a) -> IO a Source #
Run a hydra-node with given ChainConfig and using the config from
config/, but, importantly, do NOT wait for the sync status to be reported.
withUnsyncedSoloHydraNode :: HasCallStack => Tracer IO HydraNodeLog -> ChainConfig -> FilePath -> Int -> Secret (SigningKey HydraKey) -> [VerificationKey HydraKey] -> (HydraClient -> IO a) -> IO a Source #
Convenience: withUnsyncedHydraNode for a single node with freshly
allocated dynamic ports.
waitNext :: HasCallStack => HydraClient -> IO Value Source #
scaleWaitTime :: NominalDiffTime -> IO NominalDiffTime Source #
Scale a wait budget to the environment. Blockfrost runs triple it (the follower observes ~1 block behind tip plus one poll interval, on a network with much longer block times than the devnet timings most waits are written for) and HYDRA_TEST_WAIT_MULTIPLIER multiplies further; CI sets it to compensate for slow shared runners, local runs default to 1. Only failure latency is affected: a passing wait returns as soon as its message arrives.
Budgets get a constant floor: the many N * blockTime waits come to well
under a second on the 0.1s devnet, underestimating the fixed costs they
also cover (tx submission, observation, node processing). Sub-second waits
fired exactly when several suites shared one machine.
waitForAll :: HasCallStack => Tracer IO HydraNodeLog -> NominalDiffTime -> [HydraClient] -> [Value] -> IO () Source #
Wait some time for a list of outputs from each of given nodes.
This function is the generalised version of waitFor, allowing several messages
to be waited for and received in any order.
waitNoMatch :: HasCallStack => NominalDiffTime -> HydraClient -> (Value -> Maybe a) -> IO () Source #
Wait up to some time and succeed if no API server output matches the given predicate.
The window is deliberately NOT scaled by scaleWaitTime: the timeout here
is the success path, so scaling it would slow every passing run.
waitMatchWith :: HasCallStack => NominalDiffTime -> HydraClient -> (Value -> Maybe a) -> IO a Source #
Like waitMatch but with the given wall-clock budget, unscaled.
getMetrics :: HasCallStack => HydraClient -> IO ByteString Source #
withHydraClusterWith :: HasCallStack => Maybe String -> (RunOptions -> RunOptions) -> Tracer IO HydraNodeLog -> Timing -> FilePath -> SocketPath -> Int -> [(VerificationKey PaymentKey, Secret (SigningKey PaymentKey))] -> [Secret (SigningKey HydraKey)] -> [TxId] -> (NonEmpty HydraClient -> IO a) -> IO a Source #
Like withHydraCluster but connecting each node's API client with the
given query string (e.g. "/?history=yes&snapshot-utxo=no") instead of the
default "/?history=yes", and adjusting each node's RunOptions (e.g. to
disable logging) before it is started.
withHydraNodeWith :: HasCallStack => Maybe String -> (RunOptions -> RunOptions) -> Tracer IO HydraNodeLog -> NominalDiffTime -> ChainConfig -> FilePath -> Int -> Secret (SigningKey HydraKey) -> [VerificationKey HydraKey] -> Map Int HydraNodePorts -> (HydraClient -> IO a) -> IO a Source #
Like withHydraNode but connecting the API client with the given query
string instead of the default "/?history=yes", and adjusting the node's
RunOptions before it is started.
allocateHydraNodePorts :: IO HydraNodePorts Source #
Allocate three unused TCP ports from the OS for a single hydra-node.
soloHydraNodePortsCache :: IORef (Map (FilePath, Int) HydraNodePorts) Source #
Process-global cache mapping each (workDir, nodeId) to its allocated
ports. The cache exists because restart-style tests (re-running
withSoloHydraNode or similar against the same workDir) depend on
etcd's persistent cluster state, which is keyed by the listen URL. If a
restart picked fresh ports, etcd would refuse to start.
soloHydraNodePortsFor :: FilePath -> Int -> IO HydraNodePorts Source #
Allocate ports for a single hydra-node, memoizing the result for the
given (workDir, nodeId) so that subsequent calls reuse the same ports.
preparePParams :: ChainConfig -> FilePath -> (Value -> Value) -> IO FilePath Source #
Prepare protocol-parameters to run a hydra-node with given ChainConfig and using the config from
config/.
withPreparedHydraNodeWithQuery :: HasCallStack => Maybe String -> [(String, String)] -> Tracer IO HydraNodeLog -> FilePath -> Int -> RunOptions -> (HydraClient -> IO a) -> IO a Source #
Like withPreparedHydraNode but connecting the API client with the given
query string instead of the default "/?history=yes".
withConnectionToNodeHost :: forall a. Tracer IO HydraNodeLog -> Int -> Host -> Maybe PortNumber -> Maybe String -> (HydraClient -> IO a) -> IO a Source #
data HydraNodeLog Source #
Constructors
| HydraNodeCommandSpec | |
Fields
| |
| NodeStarted | |
| SentMessage | |
| StartWaiting | |
| ReceivedMessage | |
| EndWaiting | |