{-# 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 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 (mapMaybe, maybeToList)
import Data.Maybe.Strict (StrictMaybe)
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.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
-> STM m GsmState
-> STM m (Map peer (ChainSyncClientHandle m blk))
-> StrictTVar m (AnchoredFragment (Header 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
-> STM m GsmState
-> STM m (Map peer (ChainSyncClientHandle m blk))
-> StrictTVar m (AnchoredFragment (Header 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 STM m GsmState
getGsmState STM m (Map peer (ChainSyncClientHandle m blk))
getHandles StrictTVar m (AnchoredFragment (Header 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
AnchoredFragment (Header blk)
curChain <- ChainDB m blk -> STM m (AnchoredFragment (Header blk))
forall (m :: * -> *) blk.
ChainDB m blk -> STM m (AnchoredFragment (Header blk))
ChainDB.getCurrentChain ChainDB m blk
chainDb
ExtLedgerState blk
immutableLedgerSt <- ChainDB m blk -> STM m (ExtLedgerState blk)
forall (m :: * -> *) blk.
Monad (STM m) =>
ChainDB m blk -> STM m (ExtLedgerState blk)
ChainDB.getImmutableLedger ChainDB m blk
chainDb
Map peer (ChainSyncClientHandle m blk)
handles <- STM m (Map peer (ChainSyncClientHandle m blk))
getHandles
Map peer (ChainSyncState blk)
states <- (ChainSyncClientHandle m blk -> STM m (ChainSyncState blk))
-> Map peer (ChainSyncClientHandle m blk)
-> STM m (Map peer (ChainSyncState blk))
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> Map peer a -> f (Map peer b)
traverse (StrictTVar m (ChainSyncState blk) -> STM m (ChainSyncState blk)
forall (m :: * -> *) a. MonadSTM m => StrictTVar m a -> STM m a
readTVar (StrictTVar m (ChainSyncState blk) -> STM m (ChainSyncState blk))
-> (ChainSyncClientHandle m blk
-> StrictTVar m (ChainSyncState blk))
-> ChainSyncClientHandle m blk
-> STM m (ChainSyncState blk)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ChainSyncClientHandle m blk -> StrictTVar m (ChainSyncState blk)
forall (m :: * -> *) blk.
ChainSyncClientHandle m blk -> StrictTVar m (ChainSyncState blk)
cschState) Map peer (ChainSyncClientHandle m blk)
handles
GDDStateView m blk peer -> STM m (GDDStateView m blk peer)
forall a. a -> STM m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure GDDStateView {
gddCtxCurChain :: AnchoredFragment (Header blk)
gddCtxCurChain = AnchoredFragment (Header blk)
curChain
, gddCtxImmutableLedgerSt :: ExtLedgerState blk
gddCtxImmutableLedgerSt = ExtLedgerState blk
immutableLedgerSt
, gddCtxKillActions :: Map peer (m ())
gddCtxKillActions = (ChainSyncClientHandle m blk -> m ())
-> Map peer (ChainSyncClientHandle m blk) -> Map peer (m ())
forall a b k. (a -> b) -> Map k a -> Map k b
Map.map ChainSyncClientHandle m blk -> m ()
forall (m :: * -> *) blk. ChainSyncClientHandle m blk -> m ()
cschGDDKill Map peer (ChainSyncClientHandle m blk)
handles
, gddCtxStates :: Map peer (ChainSyncState blk)
gddCtxStates = Map peer (ChainSyncState blk)
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
AnchoredFragment (Header blk)
loeFrag <- TopLevelConfig blk
-> Tracer m (TraceGDDEvent peer blk)
-> GDDStateView m blk peer
-> m (AnchoredFragment (Header blk))
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 (Header blk))
evaluateGDD TopLevelConfig blk
cfg Tracer m (TraceGDDEvent peer blk)
tracer GDDStateView m blk peer
stateView
AnchoredFragment (Header blk)
oldLoEFrag <- STM m (AnchoredFragment (Header blk))
-> m (AnchoredFragment (Header blk))
forall a. HasCallStack => STM m a -> m a
forall (m :: * -> *) a.
(MonadSTM m, HasCallStack) =>
STM m a -> m a
atomically (STM m (AnchoredFragment (Header blk))
-> m (AnchoredFragment (Header blk)))
-> STM m (AnchoredFragment (Header blk))
-> m (AnchoredFragment (Header blk))
forall a b. (a -> b) -> a -> b
$ StrictTVar m (AnchoredFragment (Header blk))
-> AnchoredFragment (Header blk)
-> STM m (AnchoredFragment (Header blk))
forall (m :: * -> *) a.
MonadSTM m =>
StrictTVar m a -> a -> STM m a
swapTVar StrictTVar m (AnchoredFragment (Header blk))
varLoEFrag AnchoredFragment (Header blk)
loeFrag
Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (AnchoredFragment (Header blk) -> ChainHash (Header blk)
forall block.
HasHeader block =>
AnchoredFragment block -> ChainHash block
AF.headHash AnchoredFragment (Header blk)
oldLoEFrag ChainHash (Header blk) -> ChainHash (Header blk) -> Bool
forall a. Eq a => a -> a -> Bool
/= AnchoredFragment (Header blk) -> ChainHash (Header blk)
forall block.
HasHeader block =>
AnchoredFragment block -> ChainHash block
AF.headHash AnchoredFragment (Header blk)
loeFrag) (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$
m (ChainSelectionPromise m) -> m ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (m (ChainSelectionPromise m) -> m ())
-> m (ChainSelectionPromise m) -> m ()
forall a b. (a -> b) -> a -> b
$ ChainDB m blk -> m (ChainSelectionPromise m)
forall (m :: * -> *) blk.
ChainDB m blk -> m (ChainSelectionPromise m)
ChainDB.triggerChainSelectionAsync ChainDB m blk
chainDb
data GDDStateView m blk peer = GDDStateView {
forall (m :: * -> *) blk peer.
GDDStateView m blk peer -> AnchoredFragment (Header blk)
gddCtxCurChain :: AnchoredFragment (Header blk)
, forall (m :: * -> *) blk peer.
GDDStateView m blk peer -> ExtLedgerState blk
gddCtxImmutableLedgerSt :: ExtLedgerState blk
, 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 (Header 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 (Header 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 (Header blk)
gddCtxCurChain = AnchoredFragment (Header blk)
curChain
, gddCtxImmutableLedgerSt :: forall (m :: * -> *) blk peer.
GDDStateView m blk peer -> ExtLedgerState blk
gddCtxImmutableLedgerSt = ExtLedgerState blk
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 (Header blk)
loeFrag, [(peer, AnchoredFragment (Header blk))]
candidateSuffixes) =
AnchoredFragment (Header blk)
-> [(peer, AnchoredFragment (Header blk))]
-> (AnchoredFragment (Header blk),
[(peer, AnchoredFragment (Header blk))])
forall blk peer.
GetHeader blk =>
AnchoredFragment (Header blk)
-> [(peer, AnchoredFragment (Header blk))]
-> (AnchoredFragment (Header blk),
[(peer, AnchoredFragment (Header blk))])
sharedCandidatePrefix AnchoredFragment (Header blk)
curChain [(peer, AnchoredFragment (Header blk))]
candidates
candidates :: [(peer, AnchoredFragment (Header blk))]
candidates = Map peer (AnchoredFragment (Header blk))
-> [(peer, AnchoredFragment (Header blk))]
forall k a. Map k a -> [(k, a)]
Map.toList (ChainSyncState blk -> AnchoredFragment (Header blk)
forall blk. ChainSyncState blk -> AnchoredFragment (Header blk)
csCandidate (ChainSyncState blk -> AnchoredFragment (Header blk))
-> Map peer (ChainSyncState blk)
-> Map peer (AnchoredFragment (Header 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 (Header blk) -> WithOrigin SlotNo
forall block.
HasHeader block =>
AnchoredFragment block -> WithOrigin SlotNo
AF.headSlot AnchoredFragment (Header 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 -> Summary (HardForkIndices blk)
forall blk.
HasHardForkHistory blk =>
LedgerConfig blk
-> LedgerState blk -> Summary (HardForkIndices blk)
hardForkSummary
(TopLevelConfig blk -> LedgerConfig blk
forall blk. TopLevelConfig blk -> LedgerConfig blk
configLedger TopLevelConfig blk
cfg)
(ExtLedgerState blk -> LedgerState blk
forall blk. ExtLedgerState blk -> LedgerState blk
ledgerState ExtLedgerState blk
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 (Header blk))]
-> AnchoredFragment (Header blk)
-> ([peer], [(peer, DensityBounds blk)])
forall peer blk.
(Ord peer, LedgerSupportsProtocol blk) =>
GenesisWindow
-> SecurityParam
-> Map peer (ChainSyncState blk)
-> [(peer, AnchoredFragment (Header blk))]
-> AnchoredFragment (Header 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 (Header blk))]
candidateSuffixes AnchoredFragment (Header blk)
loeFrag
loeHead :: Anchor (Header blk)
loeHead = AnchoredFragment (Header blk) -> Anchor (Header blk)
forall v a b. Anchorable v a b => AnchoredSeq v a b -> a
AF.headAnchor AnchoredFragment (Header blk)
loeFrag
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 {GenesisWindow
sgen :: GenesisWindow
sgen :: GenesisWindow
sgen, AnchoredFragment (Header blk)
curChain :: AnchoredFragment (Header blk)
curChain :: AnchoredFragment (Header blk)
curChain, [(peer, DensityBounds blk)]
bounds :: [(peer, DensityBounds blk)]
bounds :: [(peer, DensityBounds blk)]
bounds, [(peer, AnchoredFragment (Header blk))]
candidates :: [(peer, AnchoredFragment (Header blk))]
candidates :: [(peer, AnchoredFragment (Header blk))]
candidates, [(peer, AnchoredFragment (Header blk))]
candidateSuffixes :: [(peer, AnchoredFragment (Header blk))]
candidateSuffixes :: [(peer, AnchoredFragment (Header 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 (Header blk) -> m (AnchoredFragment (Header blk))
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure AnchoredFragment (Header blk)
loeFrag
sharedCandidatePrefix ::
GetHeader blk =>
AnchoredFragment (Header blk) ->
[(peer, AnchoredFragment (Header blk))] ->
(AnchoredFragment (Header blk), [(peer, AnchoredFragment (Header blk))])
sharedCandidatePrefix :: forall blk peer.
GetHeader blk =>
AnchoredFragment (Header blk)
-> [(peer, AnchoredFragment (Header blk))]
-> (AnchoredFragment (Header blk),
[(peer, AnchoredFragment (Header blk))])
sharedCandidatePrefix AnchoredFragment (Header blk)
curChain [(peer, AnchoredFragment (Header blk))]
candidates =
(Compose [] ((,) peer) (AnchoredFragment (Header blk))
-> [(peer, AnchoredFragment (Header blk))])
-> (AnchoredFragment (Header blk),
Compose [] ((,) peer) (AnchoredFragment (Header blk)))
-> (AnchoredFragment (Header blk),
[(peer, AnchoredFragment (Header blk))])
forall b c a. (b -> c) -> (a, b) -> (a, c)
forall (p :: * -> * -> *) b c a.
Bifunctor p =>
(b -> c) -> p a b -> p a c
second Compose [] ((,) peer) (AnchoredFragment (Header blk))
-> [(peer, AnchoredFragment (Header blk))]
forall {k1} {k2} (f :: k1 -> *) (g :: k2 -> k1) (a :: k2).
Compose f g a -> f (g a)
getCompose ((AnchoredFragment (Header blk),
Compose [] ((,) peer) (AnchoredFragment (Header blk)))
-> (AnchoredFragment (Header blk),
[(peer, AnchoredFragment (Header blk))]))
-> (AnchoredFragment (Header blk),
Compose [] ((,) peer) (AnchoredFragment (Header blk)))
-> (AnchoredFragment (Header blk),
[(peer, AnchoredFragment (Header blk))])
forall a b. (a -> b) -> a -> b
$
Anchor (Header blk)
-> Compose [] ((,) peer) (AnchoredFragment (Header blk))
-> (AnchoredFragment (Header blk),
Compose [] ((,) peer) (AnchoredFragment (Header blk)))
forall (f :: * -> *) blk.
(Functor f, Foldable f, HasHeader blk) =>
Anchor blk
-> f (AnchoredFragment blk)
-> (AnchoredFragment blk, f (AnchoredFragment blk))
stripCommonPrefix (AnchoredFragment (Header blk) -> Anchor (Header blk)
forall v a b. AnchoredSeq v a b -> a
AF.anchor AnchoredFragment (Header blk)
curChain) (Compose [] ((,) peer) (AnchoredFragment (Header blk))
-> (AnchoredFragment (Header blk),
Compose [] ((,) peer) (AnchoredFragment (Header blk))))
-> Compose [] ((,) peer) (AnchoredFragment (Header blk))
-> (AnchoredFragment (Header blk),
Compose [] ((,) peer) (AnchoredFragment (Header blk)))
forall a b. (a -> b) -> a -> b
$
[(peer, AnchoredFragment (Header blk))]
-> Compose [] ((,) peer) (AnchoredFragment (Header blk))
forall {k} {k1} (f :: k -> *) (g :: k1 -> k) (a :: k1).
f (g a) -> Compose f g a
Compose [(peer, AnchoredFragment (Header blk))]
immutableTipSuffixes
where
immutableTip :: Point (Header blk)
immutableTip = AnchoredFragment (Header blk) -> Point (Header blk)
forall block. AnchoredFragment block -> Point block
AF.anchorPoint AnchoredFragment (Header blk)
curChain
splitAfterImmutableTip :: (peer, AnchoredFragment (Header blk))
-> Maybe (peer, AnchoredFragment (Header blk))
splitAfterImmutableTip (peer
peer, AnchoredFragment (Header blk)
frag) =
(,) peer
peer (AnchoredFragment (Header blk)
-> (peer, AnchoredFragment (Header blk)))
-> ((AnchoredFragment (Header blk), AnchoredFragment (Header blk))
-> AnchoredFragment (Header blk))
-> (AnchoredFragment (Header blk), AnchoredFragment (Header blk))
-> (peer, AnchoredFragment (Header blk))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (AnchoredFragment (Header blk), AnchoredFragment (Header blk))
-> AnchoredFragment (Header blk)
forall a b. (a, b) -> b
snd ((AnchoredFragment (Header blk), AnchoredFragment (Header blk))
-> (peer, AnchoredFragment (Header blk)))
-> Maybe
(AnchoredFragment (Header blk), AnchoredFragment (Header blk))
-> Maybe (peer, AnchoredFragment (Header blk))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> AnchoredFragment (Header blk)
-> Point (Header blk)
-> Maybe
(AnchoredFragment (Header blk), AnchoredFragment (Header blk))
forall block1 block2.
(HasHeader block1, HeaderHash block1 ~ HeaderHash block2) =>
AnchoredFragment block1
-> Point block2
-> Maybe (AnchoredFragment block1, AnchoredFragment block1)
AF.splitAfterPoint AnchoredFragment (Header blk)
frag Point (Header blk)
immutableTip
immutableTipSuffixes :: [(peer, AnchoredFragment (Header blk))]
immutableTipSuffixes =
((peer, AnchoredFragment (Header blk))
-> Maybe (peer, AnchoredFragment (Header blk)))
-> [(peer, AnchoredFragment (Header blk))]
-> [(peer, AnchoredFragment (Header blk))]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe (peer, AnchoredFragment (Header blk))
-> Maybe (peer, AnchoredFragment (Header blk))
splitAfterImmutableTip [(peer, AnchoredFragment (Header blk))]
candidates
data DensityBounds blk =
DensityBounds {
forall blk. DensityBounds blk -> AnchoredFragment (Header blk)
clippedFragment :: AnchoredFragment (Header 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 (Header blk))]
-> AnchoredFragment (Header blk)
-> ([peer], [(peer, DensityBounds blk)])
densityDisconnect :: forall peer blk.
(Ord peer, LedgerSupportsProtocol blk) =>
GenesisWindow
-> SecurityParam
-> Map peer (ChainSyncState blk)
-> [(peer, AnchoredFragment (Header blk))]
-> AnchoredFragment (Header blk)
-> ([peer], [(peer, DensityBounds blk)])
densityDisconnect (GenesisWindow Word64
sgen) (SecurityParam Word64
k) Map peer (ChainSyncState blk)
states [(peer, AnchoredFragment (Header blk))]
candidateSuffixes AnchoredFragment (Header blk)
loeFrag =
([peer]
losingPeers, [(peer, DensityBounds blk)]
densityBounds)
where
densityBounds :: [(peer, DensityBounds blk)]
densityBounds = do
(peer
peer, AnchoredFragment (Header blk)
candidateSuffix) <- [(peer, AnchoredFragment (Header blk))]
candidateSuffixes
let (AnchoredFragment (Header blk)
clippedFragment, AnchoredFragment (Header blk)
_) =
SlotNo
-> AnchoredFragment (Header blk)
-> (AnchoredFragment (Header blk), AnchoredFragment (Header blk))
forall block.
HasHeader block =>
SlotNo
-> AnchoredFragment block
-> (AnchoredFragment block, AnchoredFragment block)
AF.splitAtSlot SlotNo
firstSlotAfterGenesisWindow AnchoredFragment (Header blk)
candidateSuffix
ChainSyncState blk
state <- Maybe (ChainSyncState blk) -> [ChainSyncState blk]
forall a. Maybe a -> [a]
maybeToList (Map peer (ChainSyncState blk)
states Map peer (ChainSyncState blk) -> peer -> Maybe (ChainSyncState blk)
forall k a. Ord k => Map k a -> k -> Maybe a
Map.!? peer
peer)
WithOrigin SlotNo
latestSlot <- StrictMaybe (WithOrigin SlotNo) -> [WithOrigin SlotNo]
forall a. StrictMaybe a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList (ChainSyncState blk -> StrictMaybe (WithOrigin SlotNo)
forall blk. ChainSyncState blk -> StrictMaybe (WithOrigin SlotNo)
csLatestSlot ChainSyncState blk
state)
let idling :: Bool
idling = ChainSyncState blk -> Bool
forall blk. ChainSyncState blk -> Bool
csIdling ChainSyncState blk
state
hasBlockAfter :: Bool
hasBlockAfter =
WithOrigin SlotNo -> WithOrigin SlotNo -> WithOrigin SlotNo
forall a. Ord a => a -> a -> a
max (AnchoredFragment (Header blk) -> WithOrigin SlotNo
forall block.
HasHeader block =>
AnchoredFragment block -> WithOrigin SlotNo
AF.headSlot AnchoredFragment (Header 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 :: Word64
potentialSlots =
if Bool
hasBlockAfter then Word64
0
else Word64
unknownTrailingSlots
unknownTrailingSlots :: Word64
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 (Header blk) -> WithOrigin SlotNo
forall block.
HasHeader block =>
AnchoredFragment block -> WithOrigin SlotNo
AF.headSlot AnchoredFragment (Header blk)
clippedFragment)
lowerBound :: Word64
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 (Header blk) -> Int
forall v a b. Anchorable v a b => AnchoredSeq v a b -> Int
AF.length AnchoredFragment (Header blk)
clippedFragment
upperBound :: Word64
upperBound = Word64
lowerBound Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
+ Word64
potentialSlots
totalBlockCount :: Word64
totalBlockCount = Int -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (AnchoredFragment (Header blk) -> Int
forall v a b. Anchorable v a b => AnchoredSeq v a b -> Int
AF.length AnchoredFragment (Header blk)
candidateSuffix)
offersMoreThanK :: Bool
offersMoreThanK = Word64
totalBlockCount Word64 -> Word64 -> Bool
forall a. Ord a => a -> a -> Bool
> Word64
k
(peer, DensityBounds blk) -> [(peer, DensityBounds blk)]
forall a. a -> [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure (peer
peer, DensityBounds {AnchoredFragment (Header blk)
clippedFragment :: AnchoredFragment (Header blk)
clippedFragment :: AnchoredFragment (Header blk)
clippedFragment, Bool
offersMoreThanK :: Bool
offersMoreThanK :: Bool
offersMoreThanK, Word64
lowerBound :: Word64
lowerBound :: Word64
lowerBound, Word64
upperBound :: Word64
upperBound :: Word64
upperBound, Bool
hasBlockAfter :: Bool
hasBlockAfter :: Bool
hasBlockAfter, WithOrigin SlotNo
latestSlot :: WithOrigin SlotNo
latestSlot :: WithOrigin SlotNo
latestSlot, Bool
idling :: Bool
idling :: Bool
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 (Header blk)
clippedFragment = AnchoredFragment (Header 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
}) ->
if Word64
ub0 Word64 -> Word64 -> Bool
forall a. Eq a => a -> a -> Bool
== Word64
0 then peer -> [peer]
forall a. a -> [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure peer
peer0 else do
(peer
_peer1, DensityBounds {clippedFragment :: forall blk. DensityBounds blk -> AnchoredFragment (Header blk)
clippedFragment = AnchoredFragment (Header blk)
frag1, Bool
offersMoreThanK :: forall blk. DensityBounds blk -> Bool
offersMoreThanK :: Bool
offersMoreThanK, lowerBound :: forall blk. DensityBounds blk -> Word64
lowerBound = Word64
lb1 }) <-
[(peer, DensityBounds blk)]
densityBounds
Bool -> [()]
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> [()]) -> Bool -> [()]
forall a b. (a -> b) -> a -> b
$ Bool
idling0 Bool -> Bool -> Bool
|| Bool -> Bool
not (AnchoredFragment (Header blk) -> Bool
forall v a b. AnchoredSeq v a b -> Bool
AF.null AnchoredFragment (Header blk)
frag0) Bool -> Bool -> Bool
|| Bool
hasBlockAfter0
Bool -> [()]
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> [()]) -> Bool -> [()]
forall a b. (a -> b) -> a -> b
$ AnchoredFragment (Header blk) -> Point (Header blk)
forall block.
HasHeader block =>
AnchoredFragment block -> Point block
AF.lastPoint AnchoredFragment (Header blk)
frag0 Point (Header blk) -> Point (Header blk) -> Bool
forall a. Eq a => a -> a -> Bool
/= AnchoredFragment (Header blk) -> Point (Header blk)
forall block.
HasHeader block =>
AnchoredFragment block -> Point block
AF.lastPoint AnchoredFragment (Header blk)
frag1
Bool -> [()]
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> [()]) -> Bool -> [()]
forall a b. (a -> b) -> a -> b
$ Bool
offersMoreThanK Bool -> Bool -> Bool
|| Word64
lb0 Word64 -> Word64 -> Bool
forall a. Eq a => a -> a -> Bool
== Word64
ub0
Bool -> [()]
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> [()]) -> Bool -> [()]
forall a b. (a -> b) -> a -> b
$ Word64
lb1 Word64 -> Word64 -> Bool
forall a. Ord a => a -> a -> Bool
>= (if Bool
idling0 then Word64
lb0 else Word64
ub0)
peer -> [peer]
forall a. a -> [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure peer
peer0
loeIntersectionSlot :: WithOrigin SlotNo
loeIntersectionSlot = AnchoredFragment (Header blk) -> WithOrigin SlotNo
forall block.
HasHeader block =>
AnchoredFragment block -> WithOrigin SlotNo
AF.headSlot AnchoredFragment (Header 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 (Header blk)
curChain :: AnchoredFragment (Header 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)