Skip to content

Commit 36d8f01

Browse files
geo2aamesgen
authored andcommitted
Adapt the HFC time translation layer for Peras
- Add `PerasRoundLength` - introduce the `PerasEnabled` datatype to track values are only used when Peras is enabled - HFC: translate between Peras rounds and slots
1 parent 233f1b2 commit 36d8f01

File tree

16 files changed

+401
-27
lines changed

16 files changed

+401
-27
lines changed

ouroboros-consensus-cardano/src/byron/Ouroboros/Consensus/Byron/Ledger/Ledger.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,7 @@ byronEraParams genesis =
333333
, eraSlotLength = fromByronSlotLength $ genesisSlotLength genesis
334334
, eraSafeZone = HardFork.StandardSafeZone (2 * k)
335335
, eraGenesisWin = GenesisWindow (2 * k)
336+
, eraPerasRoundLength = HardFork.NoPerasEnabled
336337
}
337338
where
338339
k = unNonZero $ maxRollbacks $ genesisSecurityParam genesis
@@ -345,6 +346,7 @@ byronEraParamsNeverHardForks genesis =
345346
, eraSlotLength = fromByronSlotLength $ genesisSlotLength genesis
346347
, eraSafeZone = HardFork.UnsafeIndefiniteSafeZone
347348
, eraGenesisWin = GenesisWindow (2 * Gen.unBlockCount (Gen.configK genesis))
349+
, eraPerasRoundLength = HardFork.NoPerasEnabled
348350
}
349351

350352
instance HasHardForkHistory ByronBlock where

ouroboros-consensus-cardano/src/shelley/Ouroboros/Consensus/Shelley/Ledger/Ledger.hs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ import Ouroboros.Consensus.Config
113113
import Ouroboros.Consensus.HardFork.Abstract
114114
import Ouroboros.Consensus.HardFork.Combinator.PartialConfig
115115
import qualified Ouroboros.Consensus.HardFork.History as HardFork
116+
import Ouroboros.Consensus.HardFork.History.EraParams (EraParams (..))
116117
import Ouroboros.Consensus.HardFork.History.Util
117118
import Ouroboros.Consensus.HardFork.Simple
118119
import Ouroboros.Consensus.HeaderValidation
@@ -168,6 +169,8 @@ shelleyEraParams genesis =
168169
, eraSlotLength = mkSlotLength $ SL.fromNominalDiffTimeMicro $ SL.sgSlotLength genesis
169170
, eraSafeZone = HardFork.StandardSafeZone stabilityWindow
170171
, eraGenesisWin = GenesisWindow stabilityWindow
172+
, -- TODO(geo2a): enabled Peras conditionally in the Dijkstra era
173+
eraPerasRoundLength = HardFork.NoPerasEnabled
171174
}
172175
where
173176
stabilityWindow =
@@ -183,6 +186,7 @@ shelleyEraParamsNeverHardForks genesis =
183186
, eraSlotLength = mkSlotLength $ SL.fromNominalDiffTimeMicro $ SL.sgSlotLength genesis
184187
, eraSafeZone = HardFork.UnsafeIndefiniteSafeZone
185188
, eraGenesisWin = GenesisWindow stabilityWindow
189+
, eraPerasRoundLength = HardFork.NoPerasEnabled
186190
}
187191
where
188192
stabilityWindow =

ouroboros-consensus-cardano/src/unstable-cardano-testlib/Test/Consensus/Cardano/Generators.hs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -993,11 +993,11 @@ instance Arbitrary History.EraEnd where
993993
]
994994

995995
instance Arbitrary History.EraSummary where
996-
arbitrary =
997-
History.EraSummary
998-
<$> arbitrary
999-
<*> arbitrary
1000-
<*> arbitrary
996+
-- Note: this generator may produce EraSummary with nonsensical bounds,
997+
-- i.e. with existing PerasRoundNo at era start and Nothing for it at the end.
998+
-- However, we only use this generator to check that the serialisation roundtrips,
999+
-- and the internal structure of EraSummary is irrelevant for that.
1000+
arbitrary = History.EraSummary <$> arbitrary <*> arbitrary <*> arbitrary
10011001

10021002
instance (Arbitrary a, SListI xs) => Arbitrary (NonEmpty xs a) where
10031003
arbitrary = do

ouroboros-consensus-diffusion/test/consensus-test/Test/Consensus/HardFork/Combinator.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ prop_simple_hfc_convergence testSetup@TestSetup{..} =
164164
(History.StandardSafeZone (safeFromTipA k))
165165
(safeZoneB k)
166166
<*> pure (GenesisWindow ((unNonZero $ maxRollbacks k) * 2))
167+
<*> pure (History.PerasEnabled defaultPerasRoundLength)
167168

168169
shape :: History.Shape '[BlockA, BlockB]
169170
shape = History.Shape $ exactlyTwo eraParamsA eraParamsB

ouroboros-consensus-diffusion/test/mock-test/Test/ThreadNet/BFT.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ prop_simple_bft_convergence
103103
, version = newestVersion (Proxy @MockBftBlock)
104104
}
105105

106+
testOutput :: TestOutput MockBftBlock
106107
testOutput =
107108
runTestNetwork
108109
testConfig

ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/Block/SupportsPeras.hs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ module Ouroboros.Consensus.Block.SupportsPeras
2323
, getPerasCertRound
2424
, getPerasCertBoostedBlock
2525
, getPerasCertBoost
26+
27+
-- * Ouroboros Peras round length
28+
, PerasRoundLength (..)
29+
, defaultPerasRoundLength
2630
) where
2731

2832
import Codec.Serialise (Serialise (..))
@@ -41,7 +45,7 @@ import Quiet (Quiet (..))
4145
newtype PerasRoundNo = PerasRoundNo {unPerasRoundNo :: Word64}
4246
deriving Show via Quiet PerasRoundNo
4347
deriving stock Generic
44-
deriving newtype (Eq, Ord, NoThunks, Serialise)
48+
deriving newtype (Enum, Eq, Ord, NoThunks, Serialise)
4549

4650
instance Condense PerasRoundNo where
4751
condense = show . unPerasRoundNo
@@ -70,6 +74,20 @@ data ValidatedPerasCert blk = ValidatedPerasCert
7074
deriving stock (Show, Eq, Ord, Generic)
7175
deriving anyclass NoThunks
7276

77+
{-------------------------------------------------------------------------------
78+
Ouroboros Peras round length
79+
-------------------------------------------------------------------------------}
80+
81+
newtype PerasRoundLength = PerasRoundLength {unPerasRoundLength :: Word64}
82+
deriving stock (Show, Eq, Ord)
83+
deriving newtype (NoThunks, Num)
84+
85+
-- | See the Protocol parameters section of the Peras design report:
86+
-- https://tweag.github.io/cardano-peras/peras-design.pdf#section.2.1
87+
-- TODO this will become a Ledger protocol parameter
88+
defaultPerasRoundLength :: PerasRoundLength
89+
defaultPerasRoundLength = 90
90+
7391
class
7492
( Show (PerasCfg blk)
7593
, NoThunks (PerasCert blk)

ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/HardFork/Abstract.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,6 @@ neverForksHardForkSummary ::
6767
LedgerState blk mk ->
6868
HardFork.Summary '[blk]
6969
neverForksHardForkSummary getParams cfg _st =
70-
HardFork.neverForksSummary eraEpochSize eraSlotLength eraGenesisWin
70+
HardFork.neverForksSummary eraEpochSize eraSlotLength eraGenesisWin eraPerasRoundLength
7171
where
7272
HardFork.EraParams{..} = getParams cfg

ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/HardFork/History/EraParams.hs

Lines changed: 74 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1+
{-# LANGUAGE BangPatterns #-}
12
{-# LANGUAGE DeriveAnyClass #-}
3+
{-# LANGUAGE DeriveFunctor #-}
24
{-# LANGUAGE DeriveGeneric #-}
35
{-# LANGUAGE DerivingStrategies #-}
46
{-# LANGUAGE FlexibleContexts #-}
7+
{-# LANGUAGE GeneralisedNewtypeDeriving #-}
58
{-# LANGUAGE LambdaCase #-}
69
{-# LANGUAGE OverloadedStrings #-}
10+
{-# LANGUAGE PatternSynonyms #-}
711
{-# LANGUAGE RecordWildCards #-}
812
{-# LANGUAGE TypeApplications #-}
913
{-# LANGUAGE UndecidableInstances #-}
@@ -12,17 +16,23 @@ module Ouroboros.Consensus.HardFork.History.EraParams
1216
( -- * API
1317
EraParams (..)
1418
, SafeZone (..)
19+
, PerasEnabled
20+
, pattern PerasEnabled
21+
, pattern NoPerasEnabled
22+
, PerasEnabledT (..)
23+
, fromPerasEnabled
1524

1625
-- * Defaults
1726
, defaultEraParams
1827
) where
1928

20-
import Cardano.Binary (enforceSize)
29+
import Cardano.Binary (DecoderError (DecoderErrorCustom), cborError)
2130
import Cardano.Ledger.BaseTypes (unNonZero)
2231
import Codec.CBOR.Decoding (Decoder, decodeListLen, decodeWord8)
2332
import Codec.CBOR.Encoding (Encoding, encodeListLen, encodeWord8)
2433
import Codec.Serialise (Serialise (..))
25-
import Control.Monad (void)
34+
import Control.Monad (ap, liftM, void)
35+
import Control.Monad.Trans.Class
2636
import Data.Word
2737
import GHC.Generics (Generic)
2838
import NoThunks.Class (NoThunks)
@@ -136,17 +146,65 @@ data EraParams = EraParams
136146
, eraSlotLength :: !SlotLength
137147
, eraSafeZone :: !SafeZone
138148
, eraGenesisWin :: !GenesisWindow
149+
, eraPerasRoundLength :: !(PerasEnabled PerasRoundLength)
150+
-- ^ Optional, as not every era will be Peras-enabled
139151
}
140152
deriving stock (Show, Eq, Generic)
141153
deriving anyclass NoThunks
142154

155+
-- | A marker for era parameters that are Peras-specific
156+
-- and are not present in pre-Peras eras
157+
newtype PerasEnabled a = MkPerasEnabled (Maybe a)
158+
deriving stock (Show, Eq, Ord, Generic)
159+
deriving anyclass NoThunks
160+
deriving newtype (Functor, Applicative, Monad)
161+
162+
pattern PerasEnabled :: a -> PerasEnabled a
163+
pattern PerasEnabled x <- MkPerasEnabled (Just !x)
164+
where
165+
PerasEnabled !x = MkPerasEnabled (Just x)
166+
167+
pattern NoPerasEnabled :: PerasEnabled a
168+
pattern NoPerasEnabled = MkPerasEnabled Nothing
169+
170+
{-# COMPLETE PerasEnabled, NoPerasEnabled #-}
171+
172+
-- | A 'fromMaybe'-like eliminator for 'PerasEnabled'
173+
fromPerasEnabled :: a -> PerasEnabled a -> a
174+
fromPerasEnabled defaultValue =
175+
\case
176+
NoPerasEnabled -> defaultValue
177+
PerasEnabled value -> value
178+
179+
-- | A 'MaybeT'-line monad transformer.
180+
--
181+
-- Used solely for the Peras-related hard fork combinator queries,
182+
-- see 'Ouroboros.Consensus.HardFork.History.Qry'.
183+
newtype PerasEnabledT m a = PerasEnabledT {runPerasEnabledT :: m (PerasEnabled a)}
184+
deriving stock Functor
185+
186+
instance (Functor m, Monad m) => Applicative (PerasEnabledT m) where
187+
pure = PerasEnabledT . pure . PerasEnabled
188+
(<*>) = ap
189+
190+
instance Monad m => Monad (PerasEnabledT m) where
191+
x >>= f = PerasEnabledT $ do
192+
v <- runPerasEnabledT x
193+
case v of
194+
NoPerasEnabled -> pure NoPerasEnabled
195+
PerasEnabled y -> runPerasEnabledT (f y)
196+
197+
instance MonadTrans PerasEnabledT where
198+
lift = PerasEnabledT . liftM PerasEnabled
199+
143200
-- | Default 'EraParams'
144201
--
145202
-- We set
146203
--
147204
-- * epoch size to @10k@ slots
148205
-- * the safe zone to @2k@ slots
149206
-- * the upper bound to 'NoLowerBound'
207+
-- * the Peras Round Length is unset
150208
--
151209
-- This is primarily useful for tests.
152210
defaultEraParams :: SecurityParam -> SlotLength -> EraParams
@@ -156,6 +214,8 @@ defaultEraParams (SecurityParam k) slotLength =
156214
, eraSlotLength = slotLength
157215
, eraSafeZone = StandardSafeZone (unNonZero k * 2)
158216
, eraGenesisWin = GenesisWindow (unNonZero k * 2)
217+
, -- Peras is disabled by default
218+
eraPerasRoundLength = NoPerasEnabled
159219
}
160220

161221
-- | Zone in which it is guaranteed that no hard fork can take place
@@ -235,17 +295,27 @@ decodeSafeBeforeEpoch = do
235295
instance Serialise EraParams where
236296
encode EraParams{..} =
237297
mconcat $
238-
[ encodeListLen 4
298+
[ encodeListLen $ case eraPerasRoundLength of
299+
NoPerasEnabled -> 4
300+
PerasEnabled{} -> 5
239301
, encode (unEpochSize eraEpochSize)
240302
, encode eraSlotLength
241303
, encode eraSafeZone
242304
, encode (unGenesisWindow eraGenesisWin)
243305
]
306+
<> case eraPerasRoundLength of
307+
NoPerasEnabled -> []
308+
PerasEnabled rl -> [encode (unPerasRoundLength rl)]
244309

245310
decode = do
246-
enforceSize "EraParams" 4
311+
len <- decodeListLen
247312
eraEpochSize <- EpochSize <$> decode
248313
eraSlotLength <- decode
249314
eraSafeZone <- decode
250315
eraGenesisWin <- GenesisWindow <$> decode
316+
eraPerasRoundLength <-
317+
case len of
318+
4 -> pure NoPerasEnabled
319+
5 -> PerasEnabled . PerasRoundLength <$> decode
320+
_ -> cborError (DecoderErrorCustom "EraParams" "unexpected list length")
251321
return EraParams{..}

0 commit comments

Comments
 (0)