{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE ViewPatterns #-}
module Ouroboros.Consensus.Node.GSM (
CandidateVersusSelection (..)
, DurationFromNow (..)
, GsmEntryPoints (..)
, GsmNodeKernelArgs (..)
, GsmState (..)
, GsmView (..)
, MarkerFileView (..)
, WrapDurationUntilTooOld (..)
, TraceGsmEvent (..)
, gsmStateToLedgerJudgement
, initializationGsmState
, realDurationUntilTooOld
, realGsmEntryPoints
, realMarkerFileView
, module Ouroboros.Consensus.Node.GsmState
) where
import Cardano.Network.Types (LedgerStateJudgement (..))
import qualified Cardano.Slotting.Slot as Slot
import qualified Control.Concurrent.Class.MonadSTM.TVar as LazySTM
import Control.Monad (forever, join, unless)
import Control.Monad.Class.MonadSTM (MonadSTM, STM, atomically, check,
orElse)
import Control.Monad.Class.MonadThrow (MonadThrow)
import Control.Monad.Class.MonadTimer (threadDelay)
import qualified Control.Monad.Class.MonadTimer.SI as SI
import Control.Tracer (Tracer, traceWith)
import Data.Functor ((<&>))
import qualified Data.Map.Strict as Map
import Data.Time (NominalDiffTime)
import qualified Ouroboros.Consensus.BlockchainTime.WallClock.Types as Clock
import qualified Ouroboros.Consensus.HardFork.Abstract as HardFork
import qualified Ouroboros.Consensus.HardFork.History as HardFork
import qualified Ouroboros.Consensus.HardFork.History.Qry as Qry
import qualified Ouroboros.Consensus.Ledger.Basics as L
import Ouroboros.Consensus.Node.GsmState
import Ouroboros.Consensus.Storage.ChainDB.API (ChainDB)
import Ouroboros.Consensus.Util.NormalForm.StrictTVar (StrictTVar)
import qualified Ouroboros.Consensus.Util.NormalForm.StrictTVar as StrictSTM
import System.FS.API (HasFS, createDirectoryIfMissing, doesFileExist,
removeFile, withFile)
import System.FS.API.Types (AllowExisting (..), FsPath, OpenMode (..),
mkFsPath)
import System.Random (StdGen, uniformR)
data DurationFromNow =
After !NominalDiffTime
|
Already
deriving (DurationFromNow -> DurationFromNow -> Bool
(DurationFromNow -> DurationFromNow -> Bool)
-> (DurationFromNow -> DurationFromNow -> Bool)
-> Eq DurationFromNow
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: DurationFromNow -> DurationFromNow -> Bool
== :: DurationFromNow -> DurationFromNow -> Bool
$c/= :: DurationFromNow -> DurationFromNow -> Bool
/= :: DurationFromNow -> DurationFromNow -> Bool
Eq, Int -> DurationFromNow -> ShowS
[DurationFromNow] -> ShowS
DurationFromNow -> String
(Int -> DurationFromNow -> ShowS)
-> (DurationFromNow -> String)
-> ([DurationFromNow] -> ShowS)
-> Show DurationFromNow
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> DurationFromNow -> ShowS
showsPrec :: Int -> DurationFromNow -> ShowS
$cshow :: DurationFromNow -> String
show :: DurationFromNow -> String
$cshowList :: [DurationFromNow] -> ShowS
showList :: [DurationFromNow] -> ShowS
Show)
data CandidateVersusSelection =
CandidateDoesNotIntersect
|
WhetherCandidateIsBetter !Bool
deriving (CandidateVersusSelection -> CandidateVersusSelection -> Bool
(CandidateVersusSelection -> CandidateVersusSelection -> Bool)
-> (CandidateVersusSelection -> CandidateVersusSelection -> Bool)
-> Eq CandidateVersusSelection
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: CandidateVersusSelection -> CandidateVersusSelection -> Bool
== :: CandidateVersusSelection -> CandidateVersusSelection -> Bool
$c/= :: CandidateVersusSelection -> CandidateVersusSelection -> Bool
/= :: CandidateVersusSelection -> CandidateVersusSelection -> Bool
Eq, Int -> CandidateVersusSelection -> ShowS
[CandidateVersusSelection] -> ShowS
CandidateVersusSelection -> String
(Int -> CandidateVersusSelection -> ShowS)
-> (CandidateVersusSelection -> String)
-> ([CandidateVersusSelection] -> ShowS)
-> Show CandidateVersusSelection
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> CandidateVersusSelection -> ShowS
showsPrec :: Int -> CandidateVersusSelection -> ShowS
$cshow :: CandidateVersusSelection -> String
show :: CandidateVersusSelection -> String
$cshowList :: [CandidateVersusSelection] -> ShowS
showList :: [CandidateVersusSelection] -> ShowS
Show)
data GsmView m upstreamPeer selection chainSyncState = GsmView {
forall (m :: * -> *) upstreamPeer selection chainSyncState.
GsmView m upstreamPeer selection chainSyncState -> Maybe StdGen
antiThunderingHerd :: Maybe StdGen
,
forall (m :: * -> *) upstreamPeer selection chainSyncState.
GsmView m upstreamPeer selection chainSyncState
-> selection -> chainSyncState -> CandidateVersusSelection
candidateOverSelection ::
selection -> chainSyncState -> CandidateVersusSelection
,
forall (m :: * -> *) upstreamPeer selection chainSyncState.
GsmView m upstreamPeer selection chainSyncState
-> chainSyncState -> Bool
peerIsIdle :: chainSyncState -> Bool
,
forall (m :: * -> *) upstreamPeer selection chainSyncState.
GsmView m upstreamPeer selection chainSyncState
-> Maybe (selection -> m DurationFromNow)
durationUntilTooOld :: Maybe (selection -> m DurationFromNow)
,
forall (m :: * -> *) upstreamPeer selection chainSyncState.
GsmView m upstreamPeer selection chainSyncState
-> selection -> selection -> Bool
equivalent :: selection -> selection -> Bool
,
forall (m :: * -> *) upstreamPeer selection chainSyncState.
GsmView m upstreamPeer selection chainSyncState
-> STM m (Map upstreamPeer (StrictTVar m chainSyncState))
getChainSyncStates ::
STM m (Map.Map upstreamPeer (StrictTVar m chainSyncState))
,
forall (m :: * -> *) upstreamPeer selection chainSyncState.
GsmView m upstreamPeer selection chainSyncState -> STM m selection
getCurrentSelection :: STM m selection
,
forall (m :: * -> *) upstreamPeer selection chainSyncState.
GsmView m upstreamPeer selection chainSyncState -> NominalDiffTime
minCaughtUpDuration :: NominalDiffTime
,
forall (m :: * -> *) upstreamPeer selection chainSyncState.
GsmView m upstreamPeer selection chainSyncState -> Bool -> m ()
setCaughtUpPersistentMark :: Bool -> m ()
,
forall (m :: * -> *) upstreamPeer selection chainSyncState.
GsmView m upstreamPeer selection chainSyncState -> GsmState -> m ()
writeGsmState :: GsmState -> m ()
,
forall (m :: * -> *) upstreamPeer selection chainSyncState.
GsmView m upstreamPeer selection chainSyncState -> STM m Bool
isHaaSatisfied :: STM m Bool
}
data GsmEntryPoints m = GsmEntryPoints {
forall (m :: * -> *).
GsmEntryPoints m -> forall neverTerminates. m neverTerminates
enterCaughtUp :: forall neverTerminates. m neverTerminates
,
forall (m :: * -> *).
GsmEntryPoints m -> forall neverTerminates. m neverTerminates
enterPreSyncing :: forall neverTerminates. m neverTerminates
}
initializationGsmState ::
( L.GetTip (L.LedgerState blk)
, Monad m
)
=> m (L.LedgerState blk L.EmptyMK)
-> Maybe (WrapDurationUntilTooOld m blk)
-> MarkerFileView m
-> m GsmState
initializationGsmState :: forall blk (m :: * -> *).
(GetTip (LedgerState blk), Monad m) =>
m (LedgerState blk EmptyMK)
-> Maybe (WrapDurationUntilTooOld m blk)
-> MarkerFileView m
-> m GsmState
initializationGsmState
m (LedgerState blk EmptyMK)
getCurrentLedger
Maybe (WrapDurationUntilTooOld m blk)
mbDurationUntilTooOld
MarkerFileView m
markerFileView
= do
wasCaughtUp <- MarkerFileView m -> m Bool
forall (m :: * -> *). MarkerFileView m -> m Bool
hasMarkerFile MarkerFileView m
markerFileView
if not wasCaughtUp then pure PreSyncing else do
case mbDurationUntilTooOld of
Maybe (WrapDurationUntilTooOld m blk)
Nothing -> GsmState -> m GsmState
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return GsmState
CaughtUp
Just WrapDurationUntilTooOld m blk
wd -> do
sno <- LedgerState blk EmptyMK -> WithOrigin SlotNo
forall (l :: LedgerStateKind) (mk :: MapKind).
GetTip l =>
l mk -> WithOrigin SlotNo
L.getTipSlot (LedgerState blk EmptyMK -> WithOrigin SlotNo)
-> m (LedgerState blk EmptyMK) -> m (WithOrigin SlotNo)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> m (LedgerState blk EmptyMK)
getCurrentLedger
getDurationUntilTooOld wd sno >>= \case
After{} -> GsmState -> m GsmState
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return GsmState
CaughtUp
DurationFromNow
Already -> do
MarkerFileView m -> m ()
forall (m :: * -> *). MarkerFileView m -> m ()
removeMarkerFile MarkerFileView m
markerFileView
GsmState -> m GsmState
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return GsmState
PreSyncing
gsmStateToLedgerJudgement :: GsmState -> LedgerStateJudgement
gsmStateToLedgerJudgement :: GsmState -> LedgerStateJudgement
gsmStateToLedgerJudgement = \case
GsmState
PreSyncing -> LedgerStateJudgement
TooOld
GsmState
Syncing -> LedgerStateJudgement
TooOld
GsmState
CaughtUp -> LedgerStateJudgement
YoungEnough
realGsmEntryPoints :: forall m upstreamPeer selection tracedSelection candidate.
( SI.MonadDelay m
, SI.MonadTimer m
)
=> (selection -> tracedSelection, Tracer m (TraceGsmEvent tracedSelection))
-> GsmView m upstreamPeer selection candidate
-> GsmEntryPoints m
realGsmEntryPoints :: forall (m :: * -> *) upstreamPeer selection tracedSelection
candidate.
(MonadDelay m, MonadTimer m) =>
(selection -> tracedSelection,
Tracer m (TraceGsmEvent tracedSelection))
-> GsmView m upstreamPeer selection candidate -> GsmEntryPoints m
realGsmEntryPoints (selection -> tracedSelection,
Tracer m (TraceGsmEvent tracedSelection))
tracerArgs GsmView m upstreamPeer selection candidate
gsmView = GsmEntryPoints {
m neverTerminates
forall neverTerminates. m neverTerminates
enterCaughtUp :: forall neverTerminates. m neverTerminates
enterCaughtUp :: forall neverTerminates. m neverTerminates
enterCaughtUp
,
m neverTerminates
forall neverTerminates. m neverTerminates
enterPreSyncing :: forall neverTerminates. m neverTerminates
enterPreSyncing :: forall neverTerminates. m neverTerminates
enterPreSyncing
}
where
(selection -> tracedSelection
cnvSelection, Tracer m (TraceGsmEvent tracedSelection)
tracer) = (selection -> tracedSelection,
Tracer m (TraceGsmEvent tracedSelection))
tracerArgs
GsmView {
Maybe StdGen
antiThunderingHerd :: forall (m :: * -> *) upstreamPeer selection chainSyncState.
GsmView m upstreamPeer selection chainSyncState -> Maybe StdGen
antiThunderingHerd :: Maybe StdGen
antiThunderingHerd
,
selection -> candidate -> CandidateVersusSelection
candidateOverSelection :: forall (m :: * -> *) upstreamPeer selection chainSyncState.
GsmView m upstreamPeer selection chainSyncState
-> selection -> chainSyncState -> CandidateVersusSelection
candidateOverSelection :: selection -> candidate -> CandidateVersusSelection
candidateOverSelection
,
candidate -> Bool
peerIsIdle :: forall (m :: * -> *) upstreamPeer selection chainSyncState.
GsmView m upstreamPeer selection chainSyncState
-> chainSyncState -> Bool
peerIsIdle :: candidate -> Bool
peerIsIdle
,
Maybe (selection -> m DurationFromNow)
durationUntilTooOld :: forall (m :: * -> *) upstreamPeer selection chainSyncState.
GsmView m upstreamPeer selection chainSyncState
-> Maybe (selection -> m DurationFromNow)
durationUntilTooOld :: Maybe (selection -> m DurationFromNow)
durationUntilTooOld
,
selection -> selection -> Bool
equivalent :: forall (m :: * -> *) upstreamPeer selection chainSyncState.
GsmView m upstreamPeer selection chainSyncState
-> selection -> selection -> Bool
equivalent :: selection -> selection -> Bool
equivalent
,
STM m (Map upstreamPeer (StrictTVar m candidate))
getChainSyncStates :: forall (m :: * -> *) upstreamPeer selection chainSyncState.
GsmView m upstreamPeer selection chainSyncState
-> STM m (Map upstreamPeer (StrictTVar m chainSyncState))
getChainSyncStates :: STM m (Map upstreamPeer (StrictTVar m candidate))
getChainSyncStates
,
STM m selection
getCurrentSelection :: forall (m :: * -> *) upstreamPeer selection chainSyncState.
GsmView m upstreamPeer selection chainSyncState -> STM m selection
getCurrentSelection :: STM m selection
getCurrentSelection
,
NominalDiffTime
minCaughtUpDuration :: forall (m :: * -> *) upstreamPeer selection chainSyncState.
GsmView m upstreamPeer selection chainSyncState -> NominalDiffTime
minCaughtUpDuration :: NominalDiffTime
minCaughtUpDuration
,
Bool -> m ()
setCaughtUpPersistentMark :: forall (m :: * -> *) upstreamPeer selection chainSyncState.
GsmView m upstreamPeer selection chainSyncState -> Bool -> m ()
setCaughtUpPersistentMark :: Bool -> m ()
setCaughtUpPersistentMark
,
GsmState -> m ()
writeGsmState :: forall (m :: * -> *) upstreamPeer selection chainSyncState.
GsmView m upstreamPeer selection chainSyncState -> GsmState -> m ()
writeGsmState :: GsmState -> m ()
writeGsmState
,
STM m Bool
isHaaSatisfied :: forall (m :: * -> *) upstreamPeer selection chainSyncState.
GsmView m upstreamPeer selection chainSyncState -> STM m Bool
isHaaSatisfied :: STM m Bool
isHaaSatisfied
} = GsmView m upstreamPeer selection candidate
gsmView
enterCaughtUp :: forall neverTerminates. m neverTerminates
enterCaughtUp :: forall neverTerminates. m neverTerminates
enterCaughtUp = Maybe StdGen -> m neverTerminates
forall neverTerminates. Maybe StdGen -> m neverTerminates
enterCaughtUp' Maybe StdGen
antiThunderingHerd
enterPreSyncing :: forall neverTerminates. m neverTerminates
enterPreSyncing :: forall neverTerminates. m neverTerminates
enterPreSyncing = Maybe StdGen -> forall neverTerminates. m neverTerminates
enterPreSyncing' Maybe StdGen
antiThunderingHerd
enterCaughtUp' :: forall neverTerminates. Maybe StdGen -> m neverTerminates
enterCaughtUp' :: forall neverTerminates. Maybe StdGen -> m neverTerminates
enterCaughtUp' Maybe StdGen
g = do
(g', ev) <- Maybe StdGen -> m (Maybe StdGen, TraceGsmEvent tracedSelection)
blockWhileCaughtUp Maybe StdGen
g
setCaughtUpPersistentMark False
writeGsmState PreSyncing
traceWith tracer ev
enterPreSyncing' g'
enterPreSyncing' :: Maybe StdGen -> forall neverTerminates. m neverTerminates
enterPreSyncing' :: Maybe StdGen -> forall neverTerminates. m neverTerminates
enterPreSyncing' Maybe StdGen
g = do
m ()
blockUntilHonestAvailabilityAssumption
GsmState -> m ()
writeGsmState GsmState
Syncing
Tracer m (TraceGsmEvent tracedSelection)
-> TraceGsmEvent tracedSelection -> m ()
forall (m :: * -> *) a. Tracer m a -> a -> m ()
traceWith Tracer m (TraceGsmEvent tracedSelection)
tracer TraceGsmEvent tracedSelection
forall selection. TraceGsmEvent selection
GsmEventPreSyncingToSyncing
Maybe StdGen -> forall neverTerminates. m neverTerminates
enterSyncing' Maybe StdGen
g
enterSyncing' :: Maybe StdGen -> forall neverTerminates. m neverTerminates
enterSyncing' :: Maybe StdGen -> forall neverTerminates. m neverTerminates
enterSyncing' Maybe StdGen
g = do
mev <- STM m (Maybe (TraceGsmEvent tracedSelection))
-> m (Maybe (TraceGsmEvent tracedSelection))
forall a. HasCallStack => STM m a -> m a
forall (m :: * -> *) a.
(MonadSTM m, HasCallStack) =>
STM m a -> m a
atomically (STM m (Maybe (TraceGsmEvent tracedSelection))
-> m (Maybe (TraceGsmEvent tracedSelection)))
-> STM m (Maybe (TraceGsmEvent tracedSelection))
-> m (Maybe (TraceGsmEvent tracedSelection))
forall a b. (a -> b) -> a -> b
$
(Maybe (TraceGsmEvent tracedSelection)
forall a. Maybe a
Nothing Maybe (TraceGsmEvent tracedSelection)
-> STM m () -> STM m (Maybe (TraceGsmEvent tracedSelection))
forall a b. a -> STM m b -> STM m a
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ STM m ()
blockWhileHonestAvailabilityAssumption)
STM m (Maybe (TraceGsmEvent tracedSelection))
-> STM m (Maybe (TraceGsmEvent tracedSelection))
-> STM m (Maybe (TraceGsmEvent tracedSelection))
forall a. STM m a -> STM m a -> STM m a
forall (m :: * -> *) a. MonadSTM m => STM m a -> STM m a -> STM m a
`orElse`
(TraceGsmEvent tracedSelection
-> Maybe (TraceGsmEvent tracedSelection)
forall a. a -> Maybe a
Just (TraceGsmEvent tracedSelection
-> Maybe (TraceGsmEvent tracedSelection))
-> STM m (TraceGsmEvent tracedSelection)
-> STM m (Maybe (TraceGsmEvent tracedSelection))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> STM m (TraceGsmEvent tracedSelection)
blockUntilCaughtUp)
case mev of
Maybe (TraceGsmEvent tracedSelection)
Nothing -> do
GsmState -> m ()
writeGsmState GsmState
PreSyncing
Tracer m (TraceGsmEvent tracedSelection)
-> TraceGsmEvent tracedSelection -> m ()
forall (m :: * -> *) a. Tracer m a -> a -> m ()
traceWith Tracer m (TraceGsmEvent tracedSelection)
tracer TraceGsmEvent tracedSelection
forall selection. TraceGsmEvent selection
GsmEventSyncingToPreSyncing
Maybe StdGen -> forall neverTerminates. m neverTerminates
enterPreSyncing' Maybe StdGen
g
Just TraceGsmEvent tracedSelection
ev -> do
GsmState -> m ()
writeGsmState GsmState
CaughtUp
Bool -> m ()
setCaughtUpPersistentMark Bool
True
Tracer m (TraceGsmEvent tracedSelection)
-> TraceGsmEvent tracedSelection -> m ()
forall (m :: * -> *) a. Tracer m a -> a -> m ()
traceWith Tracer m (TraceGsmEvent tracedSelection)
tracer TraceGsmEvent tracedSelection
ev
DiffTime -> m ()
forall (m :: * -> *). MonadDelay m => DiffTime -> m ()
SI.threadDelay (DiffTime -> m ()) -> DiffTime -> m ()
forall a b. (a -> b) -> a -> b
$ NominalDiffTime -> DiffTime
forall a b. (Real a, Fractional b) => a -> b
realToFrac NominalDiffTime
minCaughtUpDuration
Maybe StdGen -> m neverTerminates
forall neverTerminates. Maybe StdGen -> m neverTerminates
enterCaughtUp' Maybe StdGen
g
blockWhileCaughtUp ::
Maybe StdGen
-> m (Maybe StdGen, TraceGsmEvent tracedSelection)
blockWhileCaughtUp :: Maybe StdGen -> m (Maybe StdGen, TraceGsmEvent tracedSelection)
blockWhileCaughtUp Maybe StdGen
g = do
let (DiffTime
bonus, Maybe StdGen
g') = case Maybe StdGen
g of
Maybe StdGen
Nothing -> (DiffTime
0, Maybe StdGen
forall a. Maybe a
Nothing)
Just StdGen
x ->
let (Int
seconds, !StdGen
g'') =
(Int, Int) -> StdGen -> (Int, StdGen)
forall g a. (RandomGen g, UniformRange a) => (a, a) -> g -> (a, g)
uniformR (Int
0, Int
300 :: Int) StdGen
x
in
(Int -> DiffTime
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
seconds, StdGen -> Maybe StdGen
forall a. a -> Maybe a
Just StdGen
g'')
ev <- STM m selection -> m selection
forall a. HasCallStack => STM m a -> m a
forall (m :: * -> *) a.
(MonadSTM m, HasCallStack) =>
STM m a -> m a
atomically STM m selection
getCurrentSelection m selection
-> (selection -> m (TraceGsmEvent tracedSelection))
-> m (TraceGsmEvent tracedSelection)
forall a b. m a -> (a -> m b) -> m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= DiffTime -> selection -> m (TraceGsmEvent tracedSelection)
blockWhileCaughtUpHelper DiffTime
bonus
pure (g', ev)
blockWhileCaughtUpHelper ::
SI.DiffTime
-> selection
-> m (TraceGsmEvent tracedSelection)
blockWhileCaughtUpHelper :: DiffTime -> selection -> m (TraceGsmEvent tracedSelection)
blockWhileCaughtUpHelper DiffTime
bonus selection
selection = do
let tracedSelection :: tracedSelection
tracedSelection = selection -> tracedSelection
cnvSelection selection
selection
computeDuration :: m (Maybe DurationFromNow)
computeDuration :: m (Maybe DurationFromNow)
computeDuration = ((selection -> m DurationFromNow) -> m DurationFromNow)
-> Maybe (selection -> m DurationFromNow)
-> m (Maybe DurationFromNow)
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b.
Monad m =>
(a -> m b) -> Maybe a -> m (Maybe b)
mapM ((selection -> m DurationFromNow) -> selection -> m DurationFromNow
forall a b. (a -> b) -> a -> b
$ selection
selection) Maybe (selection -> m DurationFromNow)
durationUntilTooOld
m (Maybe DurationFromNow)
computeDuration m (Maybe DurationFromNow)
-> (Maybe DurationFromNow -> m (TraceGsmEvent tracedSelection))
-> m (TraceGsmEvent tracedSelection)
forall a b. m a -> (a -> m b) -> m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
Maybe DurationFromNow
Nothing -> m () -> m (TraceGsmEvent tracedSelection)
forall (f :: * -> *) a b. Applicative f => f a -> f b
forever (m () -> m (TraceGsmEvent tracedSelection))
-> m () -> m (TraceGsmEvent tracedSelection)
forall a b. (a -> b) -> a -> b
$ Int -> m ()
forall (m :: * -> *). MonadDelay m => Int -> m ()
threadDelay Int
forall a. Bounded a => a
maxBound
Just DurationFromNow
Already -> do
TraceGsmEvent tracedSelection -> m (TraceGsmEvent tracedSelection)
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (TraceGsmEvent tracedSelection
-> m (TraceGsmEvent tracedSelection))
-> TraceGsmEvent tracedSelection
-> m (TraceGsmEvent tracedSelection)
forall a b. (a -> b) -> a -> b
$ tracedSelection -> DurationFromNow -> TraceGsmEvent tracedSelection
forall selection.
selection -> DurationFromNow -> TraceGsmEvent selection
GsmEventLeaveCaughtUp tracedSelection
tracedSelection DurationFromNow
Already
Just (After NominalDiffTime
dur) -> do
varTimeoutExpired <- DiffTime -> m (TVar m Bool)
forall (m :: * -> *). MonadTimer m => DiffTime -> m (TVar m Bool)
SI.registerDelay (NominalDiffTime -> DiffTime
forall a b. (Real a, Fractional b) => a -> b
realToFrac NominalDiffTime
dur DiffTime -> DiffTime -> DiffTime
forall a. Num a => a -> a -> a
+ DiffTime
bonus)
join $ atomically $ do
expired <- LazySTM.readTVar varTimeoutExpired
let ev = tracedSelection -> DurationFromNow -> TraceGsmEvent tracedSelection
forall selection.
selection -> DurationFromNow -> TraceGsmEvent selection
GsmEventLeaveCaughtUp tracedSelection
tracedSelection (NominalDiffTime -> DurationFromNow
After NominalDiffTime
dur)
if expired then pure (pure ev) else do
selection' <- getCurrentSelection
check $ not $ equivalent selection selection'
pure $ blockWhileCaughtUpHelper bonus selection'
blockUntilCaughtUp :: STM m (TraceGsmEvent tracedSelection)
blockUntilCaughtUp :: STM m (TraceGsmEvent tracedSelection)
blockUntilCaughtUp = do
varsState <- STM m (Map upstreamPeer (StrictTVar m candidate))
getChainSyncStates
states <- traverse StrictSTM.readTVar varsState
check $
not (Map.null states)
&& all peerIsIdle states
selection <- getCurrentSelection
candidates <- traverse StrictSTM.readTVar varsState
let ok candidate
candidate =
Bool -> CandidateVersusSelection
WhetherCandidateIsBetter Bool
False
CandidateVersusSelection -> CandidateVersusSelection -> Bool
forall a. Eq a => a -> a -> Bool
== selection -> candidate -> CandidateVersusSelection
candidateOverSelection selection
selection candidate
candidate
check $ all ok candidates
pure $ GsmEventEnterCaughtUp
(Map.size states)
(cnvSelection selection)
blockUntilHonestAvailabilityAssumption :: m ()
blockUntilHonestAvailabilityAssumption :: m ()
blockUntilHonestAvailabilityAssumption =
STM m () -> m ()
forall a. HasCallStack => STM m a -> m a
forall (m :: * -> *) a.
(MonadSTM m, HasCallStack) =>
STM m a -> m a
atomically (STM m () -> m ()) -> STM m () -> m ()
forall a b. (a -> b) -> a -> b
$ Bool -> STM m ()
forall (m :: * -> *). MonadSTM m => Bool -> STM m ()
check (Bool -> STM m ()) -> STM m Bool -> STM m ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< STM m Bool
isHaaSatisfied
blockWhileHonestAvailabilityAssumption :: STM m ()
blockWhileHonestAvailabilityAssumption :: STM m ()
blockWhileHonestAvailabilityAssumption =
Bool -> STM m ()
forall (m :: * -> *). MonadSTM m => Bool -> STM m ()
check (Bool -> STM m ()) -> (Bool -> Bool) -> Bool -> STM m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bool -> Bool
not (Bool -> STM m ()) -> STM m Bool -> STM m ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< STM m Bool
isHaaSatisfied
data TraceGsmEvent selection =
GsmEventEnterCaughtUp !Int !selection
|
GsmEventLeaveCaughtUp !selection !DurationFromNow
|
GsmEventPreSyncingToSyncing
|
GsmEventSyncingToPreSyncing
deriving (TraceGsmEvent selection -> TraceGsmEvent selection -> Bool
(TraceGsmEvent selection -> TraceGsmEvent selection -> Bool)
-> (TraceGsmEvent selection -> TraceGsmEvent selection -> Bool)
-> Eq (TraceGsmEvent selection)
forall selection.
Eq selection =>
TraceGsmEvent selection -> TraceGsmEvent selection -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: forall selection.
Eq selection =>
TraceGsmEvent selection -> TraceGsmEvent selection -> Bool
== :: TraceGsmEvent selection -> TraceGsmEvent selection -> Bool
$c/= :: forall selection.
Eq selection =>
TraceGsmEvent selection -> TraceGsmEvent selection -> Bool
/= :: TraceGsmEvent selection -> TraceGsmEvent selection -> Bool
Eq, Int -> TraceGsmEvent selection -> ShowS
[TraceGsmEvent selection] -> ShowS
TraceGsmEvent selection -> String
(Int -> TraceGsmEvent selection -> ShowS)
-> (TraceGsmEvent selection -> String)
-> ([TraceGsmEvent selection] -> ShowS)
-> Show (TraceGsmEvent selection)
forall selection.
Show selection =>
Int -> TraceGsmEvent selection -> ShowS
forall selection.
Show selection =>
[TraceGsmEvent selection] -> ShowS
forall selection.
Show selection =>
TraceGsmEvent selection -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: forall selection.
Show selection =>
Int -> TraceGsmEvent selection -> ShowS
showsPrec :: Int -> TraceGsmEvent selection -> ShowS
$cshow :: forall selection.
Show selection =>
TraceGsmEvent selection -> String
show :: TraceGsmEvent selection -> String
$cshowList :: forall selection.
Show selection =>
[TraceGsmEvent selection] -> ShowS
showList :: [TraceGsmEvent selection] -> ShowS
Show)
newtype WrapDurationUntilTooOld m blk = DurationUntilTooOld {
forall (m :: * -> *) blk.
WrapDurationUntilTooOld m blk
-> WithOrigin SlotNo -> m DurationFromNow
getDurationUntilTooOld :: Slot.WithOrigin Slot.SlotNo -> m DurationFromNow
}
realDurationUntilTooOld ::
( HardFork.HasHardForkHistory blk
, MonadSTM m
)
=> L.LedgerConfig blk
-> STM m (L.LedgerState blk L.EmptyMK)
-> NominalDiffTime
-> Clock.SystemTime m
-> m (WrapDurationUntilTooOld m blk)
realDurationUntilTooOld :: forall blk (m :: * -> *).
(HasHardForkHistory blk, MonadSTM m) =>
LedgerConfig blk
-> STM m (LedgerState blk EmptyMK)
-> NominalDiffTime
-> SystemTime m
-> m (WrapDurationUntilTooOld m blk)
realDurationUntilTooOld LedgerConfig blk
lcfg STM m (LedgerState blk EmptyMK)
getLedgerState NominalDiffTime
maxCaughtUpAge SystemTime m
systemTime = do
runner <-
STM m (Summary (HardForkIndices blk))
-> m (RunWithCachedSummary (HardForkIndices blk) m)
forall (m :: * -> *) (xs :: [*]).
MonadSTM m =>
STM m (Summary xs) -> m (RunWithCachedSummary xs m)
HardFork.runWithCachedSummary
(STM m (Summary (HardForkIndices blk))
-> m (RunWithCachedSummary (HardForkIndices blk) m))
-> STM m (Summary (HardForkIndices blk))
-> m (RunWithCachedSummary (HardForkIndices blk) m)
forall a b. (a -> b) -> a -> b
$ LedgerConfig blk
-> LedgerState blk EmptyMK -> Summary (HardForkIndices blk)
forall blk (mk :: MapKind).
HasHardForkHistory blk =>
LedgerConfig blk
-> LedgerState blk mk -> Summary (HardForkIndices blk)
forall (mk :: MapKind).
LedgerConfig blk
-> LedgerState blk mk -> Summary (HardForkIndices blk)
HardFork.hardForkSummary LedgerConfig blk
lcfg (LedgerState blk EmptyMK -> Summary (HardForkIndices blk))
-> STM m (LedgerState blk EmptyMK)
-> STM m (Summary (HardForkIndices blk))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> STM m (LedgerState blk EmptyMK)
getLedgerState
pure $ DurationUntilTooOld $ \WithOrigin SlotNo
woSlot -> do
now <- SystemTime m -> m RelativeTime
forall (m :: * -> *). SystemTime m -> m RelativeTime
Clock.systemTimeCurrent SystemTime m
systemTime
case woSlot of
WithOrigin SlotNo
Slot.Origin -> DurationFromNow -> m DurationFromNow
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (DurationFromNow -> m DurationFromNow)
-> DurationFromNow -> m DurationFromNow
forall a b. (a -> b) -> a -> b
$ RelativeTime -> RelativeTime -> DurationFromNow
toDur RelativeTime
now (RelativeTime -> DurationFromNow)
-> RelativeTime -> DurationFromNow
forall a b. (a -> b) -> a -> b
$ NominalDiffTime -> RelativeTime
Clock.RelativeTime NominalDiffTime
0
Slot.At SlotNo
slot -> do
let qry :: Qry (RelativeTime, SlotLength)
qry = SlotNo -> Qry (RelativeTime, SlotLength)
Qry.slotToWallclock SlotNo
slot
STM m DurationFromNow -> m DurationFromNow
forall a. HasCallStack => STM m a -> m a
forall (m :: * -> *) a.
(MonadSTM m, HasCallStack) =>
STM m a -> m a
atomically (STM m DurationFromNow -> m DurationFromNow)
-> STM m DurationFromNow -> m DurationFromNow
forall a b. (a -> b) -> a -> b
$ RunWithCachedSummary (HardForkIndices blk) m
-> forall a. Qry a -> STM m (Either PastHorizonException a)
forall (xs :: [*]) (m :: * -> *).
RunWithCachedSummary xs m
-> forall a. Qry a -> STM m (Either PastHorizonException a)
HardFork.cachedRunQuery RunWithCachedSummary (HardForkIndices blk) m
runner Qry (RelativeTime, SlotLength)
qry STM m (Either PastHorizonException (RelativeTime, SlotLength))
-> (Either PastHorizonException (RelativeTime, SlotLength)
-> DurationFromNow)
-> STM m DurationFromNow
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> \case
Left Qry.PastHorizon{} -> DurationFromNow
Already
Right (RelativeTime
onset, SlotLength
_slotLen) -> RelativeTime -> RelativeTime -> DurationFromNow
toDur RelativeTime
now RelativeTime
onset
where
toDur :: RelativeTime -> RelativeTime -> DurationFromNow
toDur
(Clock.RelativeTime NominalDiffTime
now)
(RelativeTime -> NominalDiffTime
Clock.getRelativeTime -> (NominalDiffTime -> NominalDiffTime -> NominalDiffTime
forall a. Num a => a -> a -> a
+ NominalDiffTime
maxCaughtUpAge) -> NominalDiffTime
limit)
= if NominalDiffTime
limit NominalDiffTime -> NominalDiffTime -> Bool
forall a. Ord a => a -> a -> Bool
<= NominalDiffTime
now then DurationFromNow
Already else NominalDiffTime -> DurationFromNow
After (NominalDiffTime
limit NominalDiffTime -> NominalDiffTime -> NominalDiffTime
forall a. Num a => a -> a -> a
- NominalDiffTime
now)
data MarkerFileView m = MarkerFileView {
forall (m :: * -> *). MarkerFileView m -> m Bool
hasMarkerFile :: m Bool
,
forall (m :: * -> *). MarkerFileView m -> m ()
removeMarkerFile :: m ()
,
forall (m :: * -> *). MarkerFileView m -> m ()
touchMarkerFile :: m ()
}
realMarkerFileView ::
MonadThrow m
=> ChainDB m blk
-> HasFS m h
-> MarkerFileView m
realMarkerFileView :: forall (m :: * -> *) blk h.
MonadThrow m =>
ChainDB m blk -> HasFS m h -> MarkerFileView m
realMarkerFileView !ChainDB m blk
_cdb HasFS m h
hasFS =
MarkerFileView {
m Bool
hasMarkerFile :: m Bool
hasMarkerFile :: m Bool
hasMarkerFile
,
removeMarkerFile :: m ()
removeMarkerFile = HasFS m h -> HasCallStack => FsPath -> m ()
forall (m :: * -> *) h. HasFS m h -> HasCallStack => FsPath -> m ()
removeFile HasFS m h
hasFS FsPath
markerFile
,
touchMarkerFile :: m ()
touchMarkerFile = do
HasFS m h -> HasCallStack => Bool -> FsPath -> m ()
forall (m :: * -> *) h.
HasFS m h -> HasCallStack => Bool -> FsPath -> m ()
createDirectoryIfMissing HasFS m h
hasFS Bool
True ([String] -> FsPath
mkFsPath [])
alreadyExists <- m Bool
hasMarkerFile
unless alreadyExists $
withFile hasFS markerFile (WriteMode MustBeNew) $ \Handle h
_h ->
() -> m ()
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
}
where
hasMarkerFile :: m Bool
hasMarkerFile = HasFS m h -> HasCallStack => FsPath -> m Bool
forall (m :: * -> *) h.
HasFS m h -> HasCallStack => FsPath -> m Bool
doesFileExist HasFS m h
hasFS FsPath
markerFile
markerFile :: FsPath
markerFile :: FsPath
markerFile = [String] -> FsPath
mkFsPath [String
"CaughtUpMarker"]
data GsmNodeKernelArgs m blk = GsmNodeKernelArgs {
forall (m :: * -> *) blk. GsmNodeKernelArgs m blk -> StdGen
gsmAntiThunderingHerd :: StdGen
,
forall (m :: * -> *) blk.
GsmNodeKernelArgs m blk -> Maybe (WrapDurationUntilTooOld m blk)
gsmDurationUntilTooOld :: Maybe (WrapDurationUntilTooOld m blk)
,
forall (m :: * -> *) blk.
GsmNodeKernelArgs m blk -> MarkerFileView m
gsmMarkerFileView :: MarkerFileView m
,
forall (m :: * -> *) blk.
GsmNodeKernelArgs m blk -> NominalDiffTime
gsmMinCaughtUpDuration :: NominalDiffTime
}