Skip to content

Commit

Permalink
Add a fromDiffTime to ensure ContestationPeriod is positive and non-zero
Browse files Browse the repository at this point in the history
Usage of UnsafeContestationPeriod should be kept to a minimum.
  • Loading branch information
ch1bo committed Jan 11, 2024
1 parent 7e7b7db commit dbc79f6
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 10 deletions.
4 changes: 2 additions & 2 deletions hydra-cluster/src/Hydra/Cluster/Scenarios.hs
Expand Up @@ -60,7 +60,7 @@ import Hydra.Cluster.Faucet (FaucetLog, createOutputAtAddress, seedFromFaucet, s
import Hydra.Cluster.Faucet qualified as Faucet
import Hydra.Cluster.Fixture (Actor (..), actorName, alice, aliceSk, aliceVk, bob, bobSk, bobVk, carol, carolSk)
import Hydra.Cluster.Util (chainConfigFor, keysFor, modifyConfig, setNetworkId)
import Hydra.ContestationPeriod (ContestationPeriod (UnsafeContestationPeriod))
import Hydra.ContestationPeriod (ContestationPeriod (UnsafeContestationPeriod), fromDiffTime)
import Hydra.HeadId (HeadId)
import Hydra.Ledger (IsTx (balance))
import Hydra.Ledger.Cardano (genKeyPair)
Expand Down Expand Up @@ -232,7 +232,7 @@ singlePartyHeadFullLifeCycle tracer workDir node hydraScriptsTxId =
refuelIfNeeded tracer node Alice 25_000_000
-- Start hydra-node on chain tip
tip <- queryTip networkId nodeSocket
let contestationPeriod = UnsafeContestationPeriod $ max 1 . truncate $ 10 * blockTime
contestationPeriod <- fromDiffTime $ 10 * blockTime
aliceChainConfig <-
chainConfigFor Alice workDir nodeSocket hydraScriptsTxId [] contestationPeriod
<&> modifyConfig (\config -> config{networkId, startChainFrom = Just tip})
Expand Down
1 change: 1 addition & 0 deletions hydra-node/hydra-node.cabal
Expand Up @@ -292,6 +292,7 @@ test-suite tests
Hydra.Chain.Direct.TimeHandleSpec
Hydra.Chain.Direct.TxSpec
Hydra.Chain.Direct.WalletSpec
Hydra.ContestationPeriodSpec
Hydra.CryptoSpec
Hydra.FireForgetSpec
Hydra.HeadLogicSnapshotSpec
Expand Down
11 changes: 11 additions & 0 deletions hydra-node/src/Hydra/ContestationPeriod.hs
Expand Up @@ -2,6 +2,7 @@ module Hydra.ContestationPeriod where

import Hydra.Prelude hiding (Show, show)

import Data.Fixed (Pico)
import Data.Ratio ((%))
import Data.Time (secondsToNominalDiffTime)
import Hydra.Data.ContestationPeriod qualified as OnChain
Expand Down Expand Up @@ -36,6 +37,16 @@ instance Arbitrary ContestationPeriod where
oneMonth = oneDay * 30
oneYear = oneDay * 365

-- | Create a 'ContestationPeriod' from a 'DiffTime'. This will fail if a
-- negative DiffTime is provided and truncates to 1s if values < 1s are given.
fromDiffTime :: MonadFail m => DiffTime -> m ContestationPeriod
fromDiffTime dt =
if seconds > 0
then pure . UnsafeContestationPeriod $ truncate seconds
else fail $ "fromDiffTime: contestation period <= 0: " <> show dt
where
seconds :: Pico = realToFrac dt

-- | Convert an off-chain contestation period to its on-chain representation.
toChain :: ContestationPeriod -> OnChain.ContestationPeriod
toChain (UnsafeContestationPeriod s) =
Expand Down
11 changes: 3 additions & 8 deletions hydra-node/src/Hydra/Options.hs
Expand Up @@ -35,7 +35,7 @@ import Hydra.Cardano.Api (
serialiseToRawBytesHexText,
)
import Hydra.Chain (maximumNumberOfParties)
import Hydra.ContestationPeriod (ContestationPeriod (UnsafeContestationPeriod))
import Hydra.ContestationPeriod (ContestationPeriod (UnsafeContestationPeriod), fromDiffTime)
import Hydra.Contract qualified as Contract
import Hydra.Ledger.Cardano ()
import Hydra.Logging (Verbosity (..))
Expand Down Expand Up @@ -732,7 +732,7 @@ defaultContestationPeriod = UnsafeContestationPeriod 60
contestationPeriodParser :: Parser ContestationPeriod
contestationPeriodParser =
option
(parseNatural <|> parseNominalDiffTime)
(parseNatural <|> parseViaDiffTime)
( long "contestation-period"
<> metavar "SECONDS"
<> value defaultContestationPeriod
Expand All @@ -746,12 +746,7 @@ contestationPeriodParser =
where
parseNatural = UnsafeContestationPeriod <$> auto

parseNominalDiffTime =
auto >>= \dt -> do
let s = nominalDiffTimeToSeconds dt
if s <= 0
then fail $ "contestation period <= 0: " <> show s
else pure $ UnsafeContestationPeriod $ truncate s
parseViaDiffTime = auto >>= fromDiffTime

data InvalidOptions
= MaximumNumberOfPartiesExceeded
Expand Down
18 changes: 18 additions & 0 deletions hydra-node/test/Hydra/ContestationPeriodSpec.hs
@@ -0,0 +1,18 @@
module Hydra.ContestationPeriodSpec where

import Hydra.Prelude

import Hydra.ContestationPeriod (fromDiffTime)
import Test.Hspec (Spec, describe)
import Test.Hspec.QuickCheck (prop)
import Test.QuickCheck (getNonPositive, getPositive)
import Test.QuickCheck.Instances.Time ()

spec :: Spec
spec = do
describe "fromDiffTime" $ do
prop "works for diff times > 0" $
isJust . fromDiffTime . getPositive

prop "fails for diff times <= 0" $
isNothing . fromDiffTime . getNonPositive

0 comments on commit dbc79f6

Please sign in to comment.