{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE UndecidableInstances #-}
module Ouroboros.Consensus.Genesis.Governor (
DensityBounds (..)
, GDDDebugInfo (..)
, GDDStateView (..)
, TraceGDDEvent (..)
, densityDisconnect
, gddWatcher
, sharedCandidatePrefix
) where
import Cardano.Ledger.BaseTypes (unNonZero)
import Control.Monad (guard, void, when)
import Control.Tracer (Tracer, traceWith)
import Data.Bifunctor (second)
import Data.Containers.ListUtils (nubOrd)
import Data.Foldable (for_, toList)
import Data.Functor.Compose (Compose (..))
import Data.List.NonEmpty (NonEmpty)
import qualified Data.List.NonEmpty as NE
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
import Data.Maybe (maybeToList)
import Data.Maybe.Strict (StrictMaybe)
import Data.Typeable (Typeable)
import Data.Word (Word64)
import Ouroboros.Consensus.Block
import Ouroboros.Consensus.Config (TopLevelConfig, configLedger,
configSecurityParam)
import Ouroboros.Consensus.Config.SecurityParam
(SecurityParam (SecurityParam))
import Ouroboros.Consensus.HardFork.Abstract (HasHardForkHistory (..))
import Ouroboros.Consensus.HardFork.History.Qry (qryFromExpr,
runQuery, slotToGenesisWindow)
import Ouroboros.Consensus.HeaderValidation (HeaderWithTime (..))
import Ouroboros.Consensus.Ledger.Basics (EmptyMK)
import Ouroboros.Consensus.Ledger.Extended (ExtLedgerState,
ledgerState)
import Ouroboros.Consensus.Ledger.SupportsProtocol
(LedgerSupportsProtocol)
import Ouroboros.Consensus.MiniProtocol.ChainSync.Client
(ChainSyncClientHandle (..), ChainSyncState (..))
import Ouroboros.Consensus.Node.GsmState
import Ouroboros.Consensus.Storage.ChainDB.API (ChainDB)
import qualified Ouroboros.Consensus.Storage.ChainDB.API as ChainDB
import Ouroboros.Consensus.Util (eitherToMaybe, whenJust)
import Ouroboros.Consensus.Util.AnchoredFragment (stripCommonPrefix)
import Ouroboros.Consensus.Util.IOLike
import Ouroboros.Consensus.Util.STM (Watcher (..))
import Ouroboros.Network.AnchoredFragment (AnchoredFragment)
import qualified Ouroboros.Network.AnchoredFragment as AF
gddWatcher ::
forall m blk peer.
( IOLike m
, Ord peer
, LedgerSupportsProtocol blk
, HasHardForkHistory blk
)
=> TopLevelConfig blk
-> Tracer m (TraceGDDEvent peer blk)
-> ChainDB m blk
-> DiffTime
-> STM m GsmState
-> STM m (Map peer (ChainSyncClientHandle m blk))
-> StrictTVar m (AnchoredFragment (HeaderWithTime blk))
-> Watcher m
(GsmState, GDDStateView m blk peer)
(Map peer (StrictMaybe (WithOrigin SlotNo), Bool))
gddWatcher :: forall (m :: * -> *) blk peer.
(IOLike m, Ord peer, LedgerSupportsProtocol blk,
HasHardForkHistory blk) =>
TopLevelConfig blk
-> Tracer m (TraceGDDEvent peer blk)
-> ChainDB m blk
-> DiffTime
-> STM m GsmState
-> STM m (Map peer (ChainSyncClientHandle m blk))
-> StrictTVar m (AnchoredFragment (HeaderWithTime blk))
-> Watcher
m
(GsmState, GDDStateView m blk peer)
(Map peer (StrictMaybe (WithOrigin SlotNo), Bool))
gddWatcher TopLevelConfig blk
cfg Tracer m (TraceGDDEvent peer blk)
tracer ChainDB m blk
chainDb DiffTime
rateLimit STM m GsmState
getGsmState STM m (Map peer (ChainSyncClientHandle m blk))
getHandles StrictTVar m (AnchoredFragment (HeaderWithTime blk))
varLoEFrag =
Watcher {
wInitial :: Maybe (Map peer (StrictMaybe (WithOrigin SlotNo), Bool))
wInitial = Maybe (Map peer (StrictMaybe (WithOrigin SlotNo), Bool))
forall a. Maybe a
Nothing
, wReader :: STM m (GsmState, GDDStateView m blk peer)
wReader = (,) (GsmState
-> GDDStateView m blk peer -> (GsmState, GDDStateView m blk peer))
-> STM m GsmState
-> STM
m (GDDStateView m blk peer -> (GsmState, GDDStateView m blk peer))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> STM m GsmState
getGsmState STM
m (GDDStateView m blk peer -> (GsmState, GDDStateView m blk peer))
-> STM m (GDDStateView m blk peer)
-> STM m (GsmState, GDDStateView m blk peer)
forall a b. STM m (a -> b) -> STM m a -> STM m b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> STM m (GDDStateView m blk peer)
getGDDStateView
, (GsmState, GDDStateView m blk peer)
-> Map peer (StrictMaybe (WithOrigin SlotNo), Bool)
wFingerprint :: (GsmState, GDDStateView m blk peer)
-> Map peer (StrictMaybe (WithOrigin SlotNo), Bool)
wFingerprint :: (GsmState, GDDStateView m blk peer)
-> Map peer (StrictMaybe (WithOrigin SlotNo), Bool)
wFingerprint
, (GsmState, GDDStateView m blk peer) -> m ()
wNotify :: (GsmState, GDDStateView m blk peer) -> m ()
wNotify :: (GsmState, GDDStateView m blk peer) -> m ()
wNotify
}
where
getGDDStateView :: STM m (GDDStateView m blk peer)
getGDDStateView :: STM m (GDDStateView m blk peer)
getGDDStateView = do
curChain <- ChainDB m blk -> STM m (AnchoredFragment (HeaderWithTime blk))
forall (m :: * -> *) blk.
ChainDB m blk -> STM m (AnchoredFragment (HeaderWithTime blk))
ChainDB.getCurrentChainWithTime ChainDB m blk
chainDb
immutableLedgerSt <- ChainDB.getImmutableLedger chainDb
handles <- getHandles
states <- traverse (readTVar . cschState) handles
pure GDDStateView {
gddCtxCurChain = curChain
, gddCtxImmutableLedgerSt = immutableLedgerSt
, gddCtxKillActions = Map.map cschGDDKill handles
, gddCtxStates = states
}
wFingerprint ::
(GsmState, GDDStateView m blk peer)
-> Map peer (StrictMaybe (WithOrigin SlotNo), Bool)
wFingerprint :: (GsmState, GDDStateView m blk peer)
-> Map peer (StrictMaybe (WithOrigin SlotNo), Bool)
wFingerprint (GsmState
gsmState, GDDStateView{Map peer (ChainSyncState blk)
gddCtxStates :: forall (m :: * -> *) blk peer.
GDDStateView m blk peer -> Map peer (ChainSyncState blk)
gddCtxStates :: Map peer (ChainSyncState blk)
gddCtxStates}) = case GsmState
gsmState of
GsmState
PreSyncing -> Map peer (StrictMaybe (WithOrigin SlotNo), Bool)
forall k a. Map k a
Map.empty
GsmState
CaughtUp -> Map peer (StrictMaybe (WithOrigin SlotNo), Bool)
forall k a. Map k a
Map.empty
GsmState
Syncing ->
(ChainSyncState blk -> (StrictMaybe (WithOrigin SlotNo), Bool))
-> Map peer (ChainSyncState blk)
-> Map peer (StrictMaybe (WithOrigin SlotNo), Bool)
forall a b k. (a -> b) -> Map k a -> Map k b
Map.map (\ChainSyncState blk
css -> (ChainSyncState blk -> StrictMaybe (WithOrigin SlotNo)
forall blk. ChainSyncState blk -> StrictMaybe (WithOrigin SlotNo)
csLatestSlot ChainSyncState blk
css, ChainSyncState blk -> Bool
forall blk. ChainSyncState blk -> Bool
csIdling ChainSyncState blk
css)) Map peer (ChainSyncState blk)
gddCtxStates
wNotify :: (GsmState, GDDStateView m blk peer) -> m ()
wNotify :: (GsmState, GDDStateView m blk peer) -> m ()
wNotify (GsmState
_gsmState, GDDStateView m blk peer
stateView) = do
t0 <- m Time
forall (m :: * -> *). MonadMonotonicTime m => m Time
getMonotonicTime
loeFrag <- evaluateGDD cfg tracer stateView
oldLoEFrag <- atomically $ swapTVar varLoEFrag loeFrag
when (AF.headHash oldLoEFrag /= AF.headHash loeFrag) $
void $ ChainDB.triggerChainSelectionAsync chainDb
tf <- getMonotonicTime
threadDelay $ rateLimit - diffTime tf t0
data GDDStateView m blk peer = GDDStateView {
forall (m :: * -> *) blk peer.
GDDStateView m blk peer -> AnchoredFragment (HeaderWithTime blk)
gddCtxCurChain :: AnchoredFragment (HeaderWithTime blk)
, forall (m :: * -> *) blk peer.
GDDStateView m blk peer -> ExtLedgerState blk EmptyMK
gddCtxImmutableLedgerSt :: ExtLedgerState blk EmptyMK
, forall (m :: * -> *) blk peer.
GDDStateView m blk peer -> Map peer (m ())
gddCtxKillActions :: Map peer (m ())
, forall (m :: * -> *) blk peer.
GDDStateView m blk peer -> Map peer (ChainSyncState blk)
gddCtxStates :: Map peer (ChainSyncState blk)
}
evaluateGDD ::
forall m blk peer.
( IOLike m
, Ord peer
, LedgerSupportsProtocol blk
, HasHardForkHistory blk
)
=> TopLevelConfig blk
-> Tracer m (TraceGDDEvent peer blk)
-> GDDStateView m blk peer
-> m (AnchoredFragment (HeaderWithTime blk))
evaluateGDD :: forall (m :: * -> *) blk peer.
(IOLike m, Ord peer, LedgerSupportsProtocol blk,
HasHardForkHistory blk) =>
TopLevelConfig blk
-> Tracer m (TraceGDDEvent peer blk)
-> GDDStateView m blk peer
-> m (AnchoredFragment (HeaderWithTime blk))
evaluateGDD TopLevelConfig blk
cfg Tracer m (TraceGDDEvent peer blk)
tracer GDDStateView m blk peer
stateView = do
let GDDStateView {
gddCtxCurChain :: forall (m :: * -> *) blk peer.
GDDStateView m blk peer -> AnchoredFragment (HeaderWithTime blk)
gddCtxCurChain = AnchoredFragment (HeaderWithTime blk)
curChain
, gddCtxImmutableLedgerSt :: forall (m :: * -> *) blk peer.
GDDStateView m blk peer -> ExtLedgerState blk EmptyMK
gddCtxImmutableLedgerSt = ExtLedgerState blk EmptyMK
immutableLedgerSt
, gddCtxKillActions :: forall (m :: * -> *) blk peer.
GDDStateView m blk peer -> Map peer (m ())
gddCtxKillActions = Map peer (m ())
killActions
, gddCtxStates :: forall (m :: * -> *) blk peer.
GDDStateView m blk peer -> Map peer (ChainSyncState blk)
gddCtxStates = Map peer (ChainSyncState blk)
states
} = GDDStateView m blk peer
stateView
(AnchoredFragment (HeaderWithTime blk)
loeFrag, [(peer, AnchoredFragment (HeaderWithTime blk))]
candidateSuffixes) =
AnchoredFragment (HeaderWithTime blk)
-> [(peer, AnchoredFragment (HeaderWithTime blk))]
-> (AnchoredFragment (HeaderWithTime blk),
[(peer, AnchoredFragment (HeaderWithTime blk))])
forall blk peer.
(GetHeader blk, Typeable blk) =>
AnchoredFragment (HeaderWithTime blk)
-> [(peer, AnchoredFragment (HeaderWithTime blk))]
-> (AnchoredFragment (HeaderWithTime blk),
[(peer, AnchoredFragment (HeaderWithTime blk))])
sharedCandidatePrefix AnchoredFragment (HeaderWithTime blk)
curChain [(peer, AnchoredFragment (HeaderWithTime blk))]
candidates
candidates :: [(peer, AnchoredFragment (HeaderWithTime blk))]
candidates = Map peer (AnchoredFragment (HeaderWithTime blk))
-> [(peer, AnchoredFragment (HeaderWithTime blk))]
forall k a. Map k a -> [(k, a)]
Map.toList (ChainSyncState blk -> AnchoredFragment (HeaderWithTime blk)
forall blk.
ChainSyncState blk -> AnchoredFragment (HeaderWithTime blk)
csCandidate (ChainSyncState blk -> AnchoredFragment (HeaderWithTime blk))
-> Map peer (ChainSyncState blk)
-> Map peer (AnchoredFragment (HeaderWithTime blk))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Map peer (ChainSyncState blk)
states)
msgen :: Maybe GenesisWindow
msgen :: Maybe GenesisWindow
msgen = Either PastHorizonException GenesisWindow -> Maybe GenesisWindow
forall a b. Either a b -> Maybe b
eitherToMaybe (Either PastHorizonException GenesisWindow -> Maybe GenesisWindow)
-> Either PastHorizonException GenesisWindow -> Maybe GenesisWindow
forall a b. (a -> b) -> a -> b
$ Qry GenesisWindow
-> Summary (HardForkIndices blk)
-> Either PastHorizonException GenesisWindow
forall a (xs :: [*]).
HasCallStack =>
Qry a -> Summary xs -> Either PastHorizonException a
runQuery Qry GenesisWindow
qry Summary (HardForkIndices blk)
summary
where
slot :: SlotNo
slot = WithOrigin SlotNo -> SlotNo
forall t. (Bounded t, Enum t) => WithOrigin t -> t
succWithOrigin (WithOrigin SlotNo -> SlotNo) -> WithOrigin SlotNo -> SlotNo
forall a b. (a -> b) -> a -> b
$ AnchoredFragment (HeaderWithTime blk) -> WithOrigin SlotNo
forall block.
HasHeader block =>
AnchoredFragment block -> WithOrigin SlotNo
AF.headSlot AnchoredFragment (HeaderWithTime blk)
loeFrag
qry :: Qry GenesisWindow
qry = (forall (f :: * -> *). Expr f GenesisWindow) -> Qry GenesisWindow
forall a. (forall (f :: * -> *). Expr f a) -> Qry a
qryFromExpr ((forall (f :: * -> *). Expr f GenesisWindow) -> Qry GenesisWindow)
-> (forall (f :: * -> *). Expr f GenesisWindow)
-> Qry GenesisWindow
forall a b. (a -> b) -> a -> b
$ SlotNo -> Expr f GenesisWindow
forall (f :: * -> *). SlotNo -> Expr f GenesisWindow
slotToGenesisWindow SlotNo
slot
summary :: Summary (HardForkIndices blk)
summary =
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)
hardForkSummary
(TopLevelConfig blk -> LedgerConfig blk
forall blk. TopLevelConfig blk -> LedgerConfig blk
configLedger TopLevelConfig blk
cfg)
(ExtLedgerState blk EmptyMK -> LedgerState blk EmptyMK
forall blk (mk :: MapKind).
ExtLedgerState blk mk -> LedgerState blk mk
ledgerState ExtLedgerState blk EmptyMK
immutableLedgerSt)
Maybe GenesisWindow -> (GenesisWindow -> m ()) -> m ()
forall (f :: * -> *) a.
Applicative f =>
Maybe a -> (a -> f ()) -> f ()
whenJust Maybe GenesisWindow
msgen ((GenesisWindow -> m ()) -> m ())
-> (GenesisWindow -> m ()) -> m ()
forall a b. (a -> b) -> a -> b
$ \GenesisWindow
sgen -> do
let
([peer]
losingPeers, [(peer, DensityBounds blk)]
bounds) =
GenesisWindow
-> SecurityParam
-> Map peer (ChainSyncState blk)
-> [(peer, AnchoredFragment (HeaderWithTime blk))]
-> AnchoredFragment (HeaderWithTime blk)
-> ([peer], [(peer, DensityBounds blk)])
forall peer blk.
(Ord peer, LedgerSupportsProtocol blk) =>
GenesisWindow
-> SecurityParam
-> Map peer (ChainSyncState blk)
-> [(peer, AnchoredFragment (HeaderWithTime blk))]
-> AnchoredFragment (HeaderWithTime blk)
-> ([peer], [(peer, DensityBounds blk)])
densityDisconnect GenesisWindow
sgen (TopLevelConfig blk -> SecurityParam
forall blk.
ConsensusProtocol (BlockProtocol blk) =>
TopLevelConfig blk -> SecurityParam
configSecurityParam TopLevelConfig blk
cfg) Map peer (ChainSyncState blk)
states [(peer, AnchoredFragment (HeaderWithTime blk))]
candidateSuffixes AnchoredFragment (HeaderWithTime blk)
loeFrag
loeHead :: Anchor (Header blk)
loeHead = Anchor (HeaderWithTime blk) -> Anchor (Header blk)
forall a b. (HeaderHash a ~ HeaderHash b) => Anchor a -> Anchor b
AF.castAnchor (Anchor (HeaderWithTime blk) -> Anchor (Header blk))
-> Anchor (HeaderWithTime blk) -> Anchor (Header blk)
forall a b. (a -> b) -> a -> b
$ AnchoredFragment (HeaderWithTime blk)
-> Anchor (HeaderWithTime blk)
forall v a b. Anchorable v a b => AnchoredSeq v a b -> a
AF.headAnchor AnchoredFragment (HeaderWithTime blk)
loeFrag
dropTimes :: [(a, AnchoredFragment (HeaderWithTime blk))]
-> [(a, AnchoredFragment (Header blk))]
dropTimes = ((a, AnchoredFragment (HeaderWithTime blk))
-> (a, AnchoredFragment (Header blk)))
-> [(a, AnchoredFragment (HeaderWithTime blk))]
-> [(a, AnchoredFragment (Header blk))]
forall a b. (a -> b) -> [a] -> [b]
map ((AnchoredFragment (HeaderWithTime blk)
-> AnchoredFragment (Header blk))
-> (a, AnchoredFragment (HeaderWithTime blk))
-> (a, AnchoredFragment (Header blk))
forall b c a. (b -> c) -> (a, b) -> (a, c)
forall (p :: MapKind) b c a.
Bifunctor p =>
(b -> c) -> p a b -> p a c
second ((HeaderWithTime blk -> Header blk)
-> AnchoredFragment (HeaderWithTime blk)
-> AnchoredFragment (Header blk)
forall block2 block1.
(HasHeader block2, HeaderHash block1 ~ HeaderHash block2) =>
(block1 -> block2)
-> AnchoredFragment block1 -> AnchoredFragment block2
AF.mapAnchoredFragment HeaderWithTime blk -> Header blk
forall blk. HeaderWithTime blk -> Header blk
hwtHeader))
Tracer m (TraceGDDEvent peer blk) -> TraceGDDEvent peer blk -> m ()
forall (m :: * -> *) a. Tracer m a -> a -> m ()
traceWith Tracer m (TraceGDDEvent peer blk)
tracer (TraceGDDEvent peer blk -> m ()) -> TraceGDDEvent peer blk -> m ()
forall a b. (a -> b) -> a -> b
$ GDDDebugInfo peer blk -> TraceGDDEvent peer blk
forall peer blk. GDDDebugInfo peer blk -> TraceGDDEvent peer blk
TraceGDDDebug (GDDDebugInfo peer blk -> TraceGDDEvent peer blk)
-> GDDDebugInfo peer blk -> TraceGDDEvent peer blk
forall a b. (a -> b) -> a -> b
$ GDDDebugInfo
{ GenesisWindow
sgen :: GenesisWindow
sgen :: GenesisWindow
sgen
, AnchoredFragment (HeaderWithTime blk)
curChain :: AnchoredFragment (HeaderWithTime blk)
curChain :: AnchoredFragment (HeaderWithTime blk)
curChain
, [(peer, DensityBounds blk)]
bounds :: [(peer, DensityBounds blk)]
bounds :: [(peer, DensityBounds blk)]
bounds
, candidates :: [(peer, AnchoredFragment (Header blk))]
candidates = [(peer, AnchoredFragment (HeaderWithTime blk))]
-> [(peer, AnchoredFragment (Header blk))]
forall {a}.
[(a, AnchoredFragment (HeaderWithTime blk))]
-> [(a, AnchoredFragment (Header blk))]
dropTimes [(peer, AnchoredFragment (HeaderWithTime blk))]
candidates
, candidateSuffixes :: [(peer, AnchoredFragment (Header blk))]
candidateSuffixes = [(peer, AnchoredFragment (HeaderWithTime blk))]
-> [(peer, AnchoredFragment (Header blk))]
forall {a}.
[(a, AnchoredFragment (HeaderWithTime blk))]
-> [(a, AnchoredFragment (Header blk))]
dropTimes [(peer, AnchoredFragment (HeaderWithTime blk))]
candidateSuffixes
, [peer]
losingPeers :: [peer]
losingPeers :: [peer]
losingPeers
, Anchor (Header blk)
loeHead :: Anchor (Header blk)
loeHead :: Anchor (Header blk)
loeHead
}
Maybe (NonEmpty peer) -> (NonEmpty peer -> m ()) -> m ()
forall (f :: * -> *) a.
Applicative f =>
Maybe a -> (a -> f ()) -> f ()
whenJust ([peer] -> Maybe (NonEmpty peer)
forall a. [a] -> Maybe (NonEmpty a)
NE.nonEmpty [peer]
losingPeers) ((NonEmpty peer -> m ()) -> m ())
-> (NonEmpty peer -> m ()) -> m ()
forall a b. (a -> b) -> a -> b
$ \NonEmpty peer
losingPeersNE -> do
NonEmpty peer -> (peer -> m ()) -> m ()
forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ NonEmpty peer
losingPeersNE ((peer -> m ()) -> m ()) -> (peer -> m ()) -> m ()
forall a b. (a -> b) -> a -> b
$ \peer
peer -> Map peer (m ())
killActions Map peer (m ()) -> peer -> m ()
forall k a. Ord k => Map k a -> k -> a
Map.! peer
peer
Tracer m (TraceGDDEvent peer blk) -> TraceGDDEvent peer blk -> m ()
forall (m :: * -> *) a. Tracer m a -> a -> m ()
traceWith Tracer m (TraceGDDEvent peer blk)
tracer (TraceGDDEvent peer blk -> m ()) -> TraceGDDEvent peer blk -> m ()
forall a b. (a -> b) -> a -> b
$ NonEmpty peer -> TraceGDDEvent peer blk
forall peer blk. NonEmpty peer -> TraceGDDEvent peer blk
TraceGDDDisconnected NonEmpty peer
losingPeersNE
AnchoredFragment (HeaderWithTime blk)
-> m (AnchoredFragment (HeaderWithTime blk))
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure AnchoredFragment (HeaderWithTime blk)
loeFrag
sharedCandidatePrefix ::
(GetHeader blk, Typeable blk) =>
AnchoredFragment (HeaderWithTime blk) ->
[(peer, AnchoredFragment (HeaderWithTime blk))] ->
(AnchoredFragment (HeaderWithTime blk), [(peer, AnchoredFragment (HeaderWithTime blk))])
sharedCandidatePrefix :: forall blk peer.
(GetHeader blk, Typeable blk) =>
AnchoredFragment (HeaderWithTime blk)
-> [(peer, AnchoredFragment (HeaderWithTime blk))]
-> (AnchoredFragment (HeaderWithTime blk),
[(peer, AnchoredFragment (HeaderWithTime blk))])
sharedCandidatePrefix AnchoredFragment (HeaderWithTime blk)
curChain [(peer, AnchoredFragment (HeaderWithTime blk))]
candidates =
(Compose [] ((,) peer) (AnchoredFragment (HeaderWithTime blk))
-> [(peer, AnchoredFragment (HeaderWithTime blk))])
-> (AnchoredFragment (HeaderWithTime blk),
Compose [] ((,) peer) (AnchoredFragment (HeaderWithTime blk)))
-> (AnchoredFragment (HeaderWithTime blk),
[(peer, AnchoredFragment (HeaderWithTime blk))])
forall b c a. (b -> c) -> (a, b) -> (a, c)
forall (p :: MapKind) b c a.
Bifunctor p =>
(b -> c) -> p a b -> p a c
second Compose [] ((,) peer) (AnchoredFragment (HeaderWithTime blk))
-> [(peer, AnchoredFragment (HeaderWithTime blk))]
forall {k1} {k2} (f :: k1 -> *) (g :: k2 -> k1) (a :: k2).
Compose f g a -> f (g a)
getCompose ((AnchoredFragment (HeaderWithTime blk),
Compose [] ((,) peer) (AnchoredFragment (HeaderWithTime blk)))
-> (AnchoredFragment (HeaderWithTime blk),
[(peer, AnchoredFragment (HeaderWithTime blk))]))
-> (AnchoredFragment (HeaderWithTime blk),
Compose [] ((,) peer) (AnchoredFragment (HeaderWithTime blk)))
-> (AnchoredFragment (HeaderWithTime blk),
[(peer, AnchoredFragment (HeaderWithTime blk))])
forall a b. (a -> b) -> a -> b
$
Anchor (HeaderWithTime blk)
-> Compose [] ((,) peer) (AnchoredFragment (HeaderWithTime blk))
-> (AnchoredFragment (HeaderWithTime blk),
Compose [] ((,) peer) (AnchoredFragment (HeaderWithTime blk)))
forall (f :: * -> *) blk.
(Functor f, Foldable f, HasHeader blk) =>
Anchor blk
-> f (AnchoredFragment blk)
-> (AnchoredFragment blk, f (AnchoredFragment blk))
stripCommonPrefix (Anchor (HeaderWithTime blk) -> Anchor (HeaderWithTime blk)
forall a b. (HeaderHash a ~ HeaderHash b) => Anchor a -> Anchor b
AF.castAnchor (Anchor (HeaderWithTime blk) -> Anchor (HeaderWithTime blk))
-> Anchor (HeaderWithTime blk) -> Anchor (HeaderWithTime blk)
forall a b. (a -> b) -> a -> b
$ AnchoredFragment (HeaderWithTime blk)
-> Anchor (HeaderWithTime blk)
forall v a b. AnchoredSeq v a b -> a
AF.anchor AnchoredFragment (HeaderWithTime blk)
curChain) (Compose [] ((,) peer) (AnchoredFragment (HeaderWithTime blk))
-> (AnchoredFragment (HeaderWithTime blk),
Compose [] ((,) peer) (AnchoredFragment (HeaderWithTime blk))))
-> Compose [] ((,) peer) (AnchoredFragment (HeaderWithTime blk))
-> (AnchoredFragment (HeaderWithTime blk),
Compose [] ((,) peer) (AnchoredFragment (HeaderWithTime blk)))
forall a b. (a -> b) -> a -> b
$
[(peer, AnchoredFragment (HeaderWithTime blk))]
-> Compose [] ((,) peer) (AnchoredFragment (HeaderWithTime blk))
forall {k} {k1} (f :: k -> *) (g :: k1 -> k) (a :: k1).
f (g a) -> Compose f g a
Compose [(peer, AnchoredFragment (HeaderWithTime blk))]
immutableTipSuffixes
where
immutableTip :: Point (HeaderWithTime blk)
immutableTip = AnchoredFragment (HeaderWithTime blk) -> Point (HeaderWithTime blk)
forall block. AnchoredFragment block -> Point block
AF.anchorPoint AnchoredFragment (HeaderWithTime blk)
curChain
splitAfterImmutableTip :: (peer, AnchoredFragment (HeaderWithTime blk))
-> (peer, AnchoredFragment (HeaderWithTime blk))
splitAfterImmutableTip (peer
peer, AnchoredFragment (HeaderWithTime blk)
frag) =
case AnchoredFragment (HeaderWithTime blk)
-> Point (HeaderWithTime blk)
-> Maybe
(AnchoredFragment (HeaderWithTime blk),
AnchoredFragment (HeaderWithTime blk))
forall block1 block2.
(HasHeader block1, HeaderHash block1 ~ HeaderHash block2) =>
AnchoredFragment block1
-> Point block2
-> Maybe (AnchoredFragment block1, AnchoredFragment block1)
AF.splitAfterPoint AnchoredFragment (HeaderWithTime blk)
frag Point (HeaderWithTime blk)
immutableTip of
Maybe
(AnchoredFragment (HeaderWithTime blk),
AnchoredFragment (HeaderWithTime blk))
Nothing -> (peer
peer, Int
-> AnchoredFragment (HeaderWithTime blk)
-> AnchoredFragment (HeaderWithTime blk)
forall v a b.
Anchorable v a b =>
Int -> AnchoredSeq v a b -> AnchoredSeq v a b
AF.takeOldest Int
0 AnchoredFragment (HeaderWithTime blk)
curChain)
Just (AnchoredFragment (HeaderWithTime blk)
_, AnchoredFragment (HeaderWithTime blk)
suffix) -> (peer
peer, AnchoredFragment (HeaderWithTime blk)
suffix)
immutableTipSuffixes :: [(peer, AnchoredFragment (HeaderWithTime blk))]
immutableTipSuffixes =
((peer, AnchoredFragment (HeaderWithTime blk))
-> (peer, AnchoredFragment (HeaderWithTime blk)))
-> [(peer, AnchoredFragment (HeaderWithTime blk))]
-> [(peer, AnchoredFragment (HeaderWithTime blk))]
forall a b. (a -> b) -> [a] -> [b]
map (peer, AnchoredFragment (HeaderWithTime blk))
-> (peer, AnchoredFragment (HeaderWithTime blk))
splitAfterImmutableTip [(peer, AnchoredFragment (HeaderWithTime blk))]
candidates
data DensityBounds blk =
DensityBounds {
forall blk.
DensityBounds blk -> AnchoredFragment (HeaderWithTime blk)
clippedFragment :: AnchoredFragment (HeaderWithTime blk),
forall blk. DensityBounds blk -> Bool
offersMoreThanK :: Bool,
forall blk. DensityBounds blk -> Word64
lowerBound :: Word64,
forall blk. DensityBounds blk -> Word64
upperBound :: Word64,
forall blk. DensityBounds blk -> Bool
hasBlockAfter :: Bool,
forall blk. DensityBounds blk -> WithOrigin SlotNo
latestSlot :: WithOrigin SlotNo,
forall blk. DensityBounds blk -> Bool
idling :: Bool
}
deriving stock instance (Show (Header blk), GetHeader blk) => Show (DensityBounds blk)
densityDisconnect ::
( Ord peer
, LedgerSupportsProtocol blk
)
=> GenesisWindow
-> SecurityParam
-> Map peer (ChainSyncState blk)
-> [(peer, AnchoredFragment (HeaderWithTime blk))]
-> AnchoredFragment (HeaderWithTime blk)
-> ([peer], [(peer, DensityBounds blk)])
densityDisconnect :: forall peer blk.
(Ord peer, LedgerSupportsProtocol blk) =>
GenesisWindow
-> SecurityParam
-> Map peer (ChainSyncState blk)
-> [(peer, AnchoredFragment (HeaderWithTime blk))]
-> AnchoredFragment (HeaderWithTime blk)
-> ([peer], [(peer, DensityBounds blk)])
densityDisconnect (GenesisWindow Word64
sgen) (SecurityParam NonZero Word64
k) Map peer (ChainSyncState blk)
states [(peer, AnchoredFragment (HeaderWithTime blk))]
candidateSuffixes AnchoredFragment (HeaderWithTime blk)
loeFrag =
([peer]
losingPeers, [(peer, DensityBounds blk)]
densityBounds)
where
densityBounds :: [(peer, DensityBounds blk)]
densityBounds = do
(peer, candidateSuffix) <- [(peer, AnchoredFragment (HeaderWithTime blk))]
candidateSuffixes
let (clippedFragment, _) =
AF.splitAtSlot firstSlotAfterGenesisWindow candidateSuffix
state <- maybeToList (states Map.!? peer)
latestSlot <- toList (csLatestSlot state)
let idling = ChainSyncState blk -> Bool
forall blk. ChainSyncState blk -> Bool
csIdling ChainSyncState blk
state
hasBlockAfter =
WithOrigin SlotNo -> WithOrigin SlotNo -> WithOrigin SlotNo
forall a. Ord a => a -> a -> a
max (AnchoredFragment (HeaderWithTime blk) -> WithOrigin SlotNo
forall block.
HasHeader block =>
AnchoredFragment block -> WithOrigin SlotNo
AF.headSlot AnchoredFragment (HeaderWithTime blk)
candidateSuffix) WithOrigin SlotNo
latestSlot
WithOrigin SlotNo -> WithOrigin SlotNo -> Bool
forall a. Ord a => a -> a -> Bool
>= SlotNo -> WithOrigin SlotNo
forall t. t -> WithOrigin t
NotOrigin SlotNo
firstSlotAfterGenesisWindow
potentialSlots =
if Bool
hasBlockAfter then Word64
0
else Word64
unknownTrailingSlots
unknownTrailingSlots = SlotNo -> Word64
unSlotNo (SlotNo -> Word64) -> SlotNo -> Word64
forall a b. (a -> b) -> a -> b
$
SlotNo
firstSlotAfterGenesisWindow SlotNo -> SlotNo -> SlotNo
forall a. Num a => a -> a -> a
- WithOrigin SlotNo -> SlotNo
forall t. (Bounded t, Enum t) => WithOrigin t -> t
succWithOrigin (AnchoredFragment (HeaderWithTime blk) -> WithOrigin SlotNo
forall block.
HasHeader block =>
AnchoredFragment block -> WithOrigin SlotNo
AF.headSlot AnchoredFragment (HeaderWithTime blk)
clippedFragment)
lowerBound = Int -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Word64) -> Int -> Word64
forall a b. (a -> b) -> a -> b
$ AnchoredFragment (HeaderWithTime blk) -> Int
forall v a b. Anchorable v a b => AnchoredSeq v a b -> Int
AF.length AnchoredFragment (HeaderWithTime blk)
clippedFragment
upperBound = Word64
lowerBound Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
+ Word64
potentialSlots
totalBlockCount = Int -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (AnchoredFragment (HeaderWithTime blk) -> Int
forall v a b. Anchorable v a b => AnchoredSeq v a b -> Int
AF.length AnchoredFragment (HeaderWithTime blk)
candidateSuffix)
offersMoreThanK = Word64
totalBlockCount Word64 -> Word64 -> Bool
forall a. Ord a => a -> a -> Bool
> NonZero Word64 -> Word64
forall a. NonZero a -> a
unNonZero NonZero Word64
k
pure (peer, DensityBounds {clippedFragment, offersMoreThanK, lowerBound, upperBound, hasBlockAfter, latestSlot, idling})
losingPeers :: [peer]
losingPeers = [peer] -> [peer]
forall a. Ord a => [a] -> [a]
nubOrd ([peer] -> [peer]) -> [peer] -> [peer]
forall a b. (a -> b) -> a -> b
$ [(peer, DensityBounds blk)]
densityBounds [(peer, DensityBounds blk)]
-> ((peer, DensityBounds blk) -> [peer]) -> [peer]
forall a b. [a] -> (a -> [b]) -> [b]
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \
(peer
peer0 , DensityBounds { clippedFragment :: forall blk.
DensityBounds blk -> AnchoredFragment (HeaderWithTime blk)
clippedFragment = AnchoredFragment (HeaderWithTime blk)
frag0
, lowerBound :: forall blk. DensityBounds blk -> Word64
lowerBound = Word64
lb0
, upperBound :: forall blk. DensityBounds blk -> Word64
upperBound = Word64
ub0
, hasBlockAfter :: forall blk. DensityBounds blk -> Bool
hasBlockAfter = Bool
hasBlockAfter0
, idling :: forall blk. DensityBounds blk -> Bool
idling = Bool
idling0
}) -> do
(_peer1, DensityBounds {clippedFragment = frag1, offersMoreThanK, lowerBound = lb1 }) <-
[(peer, DensityBounds blk)]
densityBounds
guard $ idling0 || not (AF.null frag0) || hasBlockAfter0
guard $ AF.lastPoint frag0 /= AF.lastPoint frag1
guard $ offersMoreThanK || lb0 == ub0
guard $ lb1 >= (if idling0 then lb0 else ub0)
pure peer0
loeIntersectionSlot :: WithOrigin SlotNo
loeIntersectionSlot = AnchoredFragment (HeaderWithTime blk) -> WithOrigin SlotNo
forall block.
HasHeader block =>
AnchoredFragment block -> WithOrigin SlotNo
AF.headSlot AnchoredFragment (HeaderWithTime blk)
loeFrag
firstSlotAfterGenesisWindow :: SlotNo
firstSlotAfterGenesisWindow =
WithOrigin SlotNo -> SlotNo
forall t. (Bounded t, Enum t) => WithOrigin t -> t
succWithOrigin WithOrigin SlotNo
loeIntersectionSlot SlotNo -> SlotNo -> SlotNo
forall a. Num a => a -> a -> a
+ Word64 -> SlotNo
SlotNo Word64
sgen
data GDDDebugInfo peer blk =
GDDDebugInfo {
forall peer blk.
GDDDebugInfo peer blk -> [(peer, DensityBounds blk)]
bounds :: [(peer, DensityBounds blk)],
forall peer blk.
GDDDebugInfo peer blk -> AnchoredFragment (HeaderWithTime blk)
curChain :: AnchoredFragment (HeaderWithTime blk),
forall peer blk.
GDDDebugInfo peer blk -> [(peer, AnchoredFragment (Header blk))]
candidates :: [(peer, AnchoredFragment (Header blk))],
forall peer blk.
GDDDebugInfo peer blk -> [(peer, AnchoredFragment (Header blk))]
candidateSuffixes :: [(peer, AnchoredFragment (Header blk))],
forall peer blk. GDDDebugInfo peer blk -> [peer]
losingPeers :: [peer],
forall peer blk. GDDDebugInfo peer blk -> Anchor (Header blk)
loeHead :: AF.Anchor (Header blk),
forall peer blk. GDDDebugInfo peer blk -> GenesisWindow
sgen :: GenesisWindow
}
deriving stock instance
( GetHeader blk, Show (Header blk), Show peer
) => Show (GDDDebugInfo peer blk)
data TraceGDDEvent peer blk =
TraceGDDDisconnected (NonEmpty peer)
|
TraceGDDDebug (GDDDebugInfo peer blk)
deriving stock instance
( GetHeader blk, Show (Header blk), Show peer
) => Show (TraceGDDEvent peer blk)