hydra-cluster
Safe HaskellSafe-Inferred
LanguageGHC2021

Hydra.Cluster.Util

Description

Utilities used across hydra-cluster

Synopsis

Documentation

readConfigFile :: FilePath -> IO ByteString Source #

Lookup a config file similar reading a file from disk. If the env variable HYDRA_CONFIG_DIR is set, filenames will be resolved relative to its value otherwise they will be looked up in the package's data path.

keysFor :: Actor -> IO (VerificationKey PaymentKey, Secret (SigningKey PaymentKey)) Source #

Get the "well-known" keys for given actor. The signing key is Secret-wrapped so callers cannot accidentally log or serialise it.

NOTE: These keys are committed to this repository and shipped as package data-files, so they are public and must never hold real funds. See Participant for what a run against a public network uses instead.

decodeSigningKey :: FilePath -> ByteString -> IO (Secret (SigningKey PaymentKey)) Source #

Decode a TextEnvelope-encoded payment signing key, Secret-wrapped.

NOTE: The failure names the file but never quotes it. A partly written key still holds key material, and this error reaches the logs.

createAndSaveSigningKey :: FilePath -> IO (Secret (SigningKey PaymentKey)) Source #

Create and save new signing key at the provided path, returning the key Secret-wrapped. NOTE: Uses TextEnvelope format.

trySync :: IO a -> IO (Either SomeException a) Source #

Catch synchronous failures while allowing cancellation to propagate.

Ephemeral run credentials

data Participant Source #

Fresh Cardano and Hydra credentials for the participant and its commit wallet, persisted in $sel:keyDir:Participant before funding.

Constructors

Participant 

Fields

participantParty :: Participant -> Party Source #

The Party a Participant appears as in a head.

participantKeysDir :: FilePath -> FilePath Source #

Directory holding the keys of runs against this working directory.

Deliberately not named state- anything: the runner wipes state-* before every run, and these keys have to outlive that.

sweptParticipantKeysDir :: FilePath -> FilePath Source #

Where archiveParticipantKeys moves the keys of a run whose funds are back.

participantCardanoKeyFile :: FilePath -> FilePath Source #

Path a hydra-node is pointed at with --cardano-signing-key.

participantHeadOpenFile :: FilePath -> FilePath Source #

Marker a run leaves while it has a head open on chain.

The address cannot tell: the node returns its own init change there, so a sweep of it succeeds whether or not a head was left behind.

participantPaymentKeyFiles :: [FilePath -> FilePath] Source #

Every key of a run that can hold funds, and so has to be swept.

generateParticipant :: FilePath -> IO Participant Source #

Generate a fresh Participant under participantKeysDir, in a directory named after the Cardano key's hash so runs cannot clobber each other.

Uses system entropy rather than seedable test generators.

writeSigningKey :: HasTextEnvelope (SigningKey k) => FilePath -> SigningKey k -> IO () Source #

Write an owner-only TextEnvelope, then rename it atomically into place so interruption cannot leave a truncated key at the destination.

leftoverParticipantKeys :: FilePath -> IO [(FilePath, Either Text [Secret (SigningKey PaymentKey)])] Source #

Read payment keys from each pending run directory, skipping missing files and reporting decode failures per run. Non-directory entries are ignored.

archiveParticipantKeys :: FilePath -> FilePath -> IO (Either Text ()) Source #

Move keys to sweptParticipantKeysDir without overwriting an existing archive, returning any failure.

type BlockTime = NominalDiffTime Source #

Expected time between blocks (on average)

data Timing Source #

Timing parameters that determine the behavior of a (cluster of) hydra-node.

Constructors

Timing 

Fields

  • blockTime :: BlockTime
     
  • contestationPeriod :: ContestationPeriod
     
  • depositPeriod :: DepositPeriod
     
  • depositActivation :: DepositPeriod

    Time a deposit must mature before it becomes active. Configured independently from Timing; the smart constructors default it to the same value so deposits activate as fast as they expire, but tests can set it separately to exercise decoupled activation.

Instances

Instances details
Show Timing Source # 
Instance details

Defined in Hydra.Cluster.Util

truncatedDepositPeriod :: NominalDiffTime -> DepositPeriod Source #

Truncate a duration to a whole-second DepositPeriod.

mkTestTiming :: BlockTime -> Timing Source #

Set up reasonable timing parameters for testing given a BlockTime.

mkTestTiming' :: Int -> BlockTime -> Timing Source #

Like mkTestTiming but scales Timing by the number of concurrent deposits expected. Each increment tx must be processed sequentially on-chain, so N concurrent deposits require N times the base deposit period.

mkSmokeTiming :: BlockTime -> Timing Source #

Timing for the smoke test run by the hydra-cluster executable against a public network, where a block takes ~20s and the run is dominated by waiting out Timing rather than by anything the scenario asserts.

A deposit becomes active at created + depositActivation, where created is the deposit tx's upper validity bound, set a grace time ahead of the chain tip by draftDepositTx. That grace time caps at min maxGraceTime (depositPeriod / 2), 200s here, so the wait is 200 + depositActivation and only the second term is ours: at one block time it drops from 200 + 400 to 200 + 20.

Timing is cut to the point where the close transaction's validity window stops changing, and no further. The contestation deadline is closeTxUpperBound + contestationPeriod with the close tx bounded at now + min contestationPeriod maxGraceTime, so at 10 * blockTime = 200s the wait halves from 600s to 400s while that min still yields 200s, exactly as it does at mkTestTiming's 400s. Going below 200s would start shortening the window every close, contest and increment has to be included in, with no resubmit on expiry, and would drag two things with it: the derived unsyncedPeriod (half the contestation period, against a Blockfrost follower that only observes blocks with a successor and so lags a block gap by construction) and submissionRetryPolicy, whose ~180s worst case is documented against a 200s window.

Timing keeps its mkTestTiming value. It is not on the critical path -- it sets how long a deposit stays active, not how long anything waits -- and shortening it only shrinks windows: the grace time is capped at half of it, so both the deposit tx's validity and the active window depositPeriod - graceTime fall with it. UtilSpec guards the value used here.

depositTimeout :: Timing -> NominalDiffTime Source #

Get a timeout until a deposit should have happened given a Timing. A deposit becomes active after Timing and then needs about one Timing to be picked up and incremented, so both are accounted for (with the defaults where they are equal this is 2 * depositPeriod).

The slack term covers the two on-chain round trips (deposit and increment: submit, include, observe) plus multi-node processing. Those costs are dominated by fixed latencies, not by block time, so the slack has a constant floor; with the devnet's 0.1s blocks a pure 5 * blockTime came to 0.5s and timed out regularly on loaded CI runners.

onChainObservationBudget :: NominalDiffTime -> NominalDiffTime Source #

Budget for observing the effect of one L1 transaction on the API: submission, block inclusion, chain-follower observation and node processing. The constant floor covers the fixed latencies, which dominate at devnet block times; a pure blockTime multiple (e.g. a literal 3s) fired regularly on loaded CI runners.

nodeStartupBudget :: NominalDiffTime Source #

Budget for a hydra-node (re)start up to its Greetings. Process spawn, etcd bootstrap and websocket connect are fixed costs, unrelated to block time, so this is a constant.

chainConfigFor Source #

Arguments

:: HasCallStack 
=> Actor 
-> FilePath 
-> ChainBackendOptions 
-> [TxId]

Transaction ids at which Hydra scripts should have been published.

-> [Actor] 
-> Timing 
-> IO ChainConfig 

Create a (test) chain config for a given actor.

chainConfigFor' Source #

Arguments

:: HasCallStack 
=> Actor 
-> FilePath 
-> ChainBackendOptions 
-> [TxId]

Transaction ids at which Hydra scripts should have been published.

-> [Actor] 
-> ContestationPeriod 
-> DepositPeriod 
-> DepositPeriod

Deposit activation, independent from the deposit period.

-> IO ChainConfig 

chainConfigForParticipant Source #

Arguments

:: Participant 
-> ChainBackendOptions 
-> [TxId]

Transaction ids at which Hydra scripts should have been published.

-> Timing 
-> ChainConfig 

Chain config for a head run by a generated Participant, as the solo scenarios that move real funds on public networks do.

Unlike chainConfigFor this copies nothing out of config/credentials: the node is pointed at the participant's own key, so no public fixture signing key is written into the state directory at all.

cardanoChainConfig Source #

Arguments

:: ChainBackendOptions 
-> [TxId]

Transaction ids at which Hydra scripts should have been published.

-> FilePath

Path of the node's own Cardano signing key.

-> [FilePath]

Paths of the other participants' Cardano verification keys.

-> ContestationPeriod 
-> DepositPeriod 
-> DepositPeriod

Deposit activation, independent from the deposit period.

-> ChainConfig 

Assemble a chain config from key files that are already on disk.

modifyConfig :: (CardanoChainConfig -> CardanoChainConfig) -> ChainConfig -> ChainConfig Source #

setNetworkId :: NetworkId -> ChainConfig -> ChainConfig Source #