{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Ouroboros.Network.Diffusion.Policies where
import Control.Concurrent.Class.MonadSTM.Strict
import Control.Monad.Class.MonadTime.SI
import Data.List (sortOn, unfoldr)
import Data.Map.Merge.Strict qualified as Map
import Data.Map.Strict (Map)
import Data.Map.Strict qualified as Map
import Data.Set qualified as Set
import Data.Word (Word32)
import System.Random
import System.Random qualified as Rnd
import Ouroboros.Network.ConnectionManager.Types (ConnectionType (..),
Provenance (..), PrunePolicy)
import Ouroboros.Network.ExitPolicy as ExitPolicy
import Ouroboros.Network.PeerSelection.Governor.Types
import Ouroboros.Network.PeerSelection.PeerMetric
deactivateTimeout :: DiffTime
deactivateTimeout :: DiffTime
deactivateTimeout = DiffTime
300
closeConnectionTimeout :: DiffTime
closeConnectionTimeout :: DiffTime
closeConnectionTimeout = DiffTime
120
minChainSyncTimeout :: DiffTime
minChainSyncTimeout :: DiffTime
minChainSyncTimeout = DiffTime
135
maxChainSyncTimeout :: DiffTime
maxChainSyncTimeout :: DiffTime
maxChainSyncTimeout = DiffTime
269
churnEstablishConnectionTimeout :: DiffTime
churnEstablishConnectionTimeout :: DiffTime
churnEstablishConnectionTimeout = DiffTime
60
peerMetricsConfiguration :: PeerMetricsConfiguration
peerMetricsConfiguration :: PeerMetricsConfiguration
peerMetricsConfiguration = PeerMetricsConfiguration {
maxEntriesToTrack :: Int
maxEntriesToTrack = Int
180
}
inboundPeersRetryDelay :: DiffTime
inboundPeersRetryDelay :: DiffTime
inboundPeersRetryDelay = DiffTime
60
maxInboundPeers :: Int
maxInboundPeers :: Int
maxInboundPeers = Int
10
optionalMerge
:: Ord k
=> Map k a
-> Map k b
-> Map k (a, Maybe b)
optionalMerge :: forall k a b. Ord k => Map k a -> Map k b -> Map k (a, Maybe b)
optionalMerge = SimpleWhenMissing k a (a, Maybe b)
-> SimpleWhenMissing k b (a, Maybe b)
-> SimpleWhenMatched k a b (a, Maybe b)
-> Map k a
-> Map k b
-> Map k (a, Maybe b)
forall k a c b.
Ord k =>
SimpleWhenMissing k a c
-> SimpleWhenMissing k b c
-> SimpleWhenMatched k a b c
-> Map k a
-> Map k b
-> Map k c
Map.merge ((k -> a -> (a, Maybe b)) -> SimpleWhenMissing k a (a, Maybe b)
forall (f :: * -> *) k x y.
Applicative f =>
(k -> x -> y) -> WhenMissing f k x y
Map.mapMissing (\k
_ a
a -> (a
a, Maybe b
forall a. Maybe a
Nothing)))
SimpleWhenMissing k b (a, Maybe b)
forall (f :: * -> *) k x y. Applicative f => WhenMissing f k x y
Map.dropMissing
((k -> a -> b -> (a, Maybe b))
-> SimpleWhenMatched k a b (a, Maybe b)
forall (f :: * -> *) k x y z.
Applicative f =>
(k -> x -> y -> z) -> WhenMatched f k x y z
Map.zipWithMatched (\k
_ a
a b
b -> (a
a, b -> Maybe b
forall a. a -> Maybe a
Just b
b)))
simplePeerSelectionPolicy :: forall m peerAddr.
( MonadSTM m
, Ord peerAddr
)
=> StrictTVar m StdGen
-> STM m ChurnMode
-> PeerMetrics m peerAddr
-> RepromoteDelay
-> PeerSelectionPolicy peerAddr m
simplePeerSelectionPolicy :: forall (m :: * -> *) peerAddr.
(MonadSTM m, Ord peerAddr) =>
StrictTVar m StdGen
-> STM m ChurnMode
-> PeerMetrics m peerAddr
-> RepromoteDelay
-> PeerSelectionPolicy peerAddr m
simplePeerSelectionPolicy StrictTVar m StdGen
rngVar STM m ChurnMode
getChurnMode PeerMetrics m peerAddr
metrics RepromoteDelay
errorDelay = PeerSelectionPolicy {
policyPickKnownPeersForPeerShare :: PickPolicy peerAddr (STM m)
policyPickKnownPeersForPeerShare = PickPolicy peerAddr (STM m)
simplePromotionPolicy,
policyPickColdPeersToPromote :: PickPolicy peerAddr (STM m)
policyPickColdPeersToPromote = PickPolicy peerAddr (STM m)
simplePromotionPolicy,
policyPickWarmPeersToPromote :: PickPolicy peerAddr (STM m)
policyPickWarmPeersToPromote = PickPolicy peerAddr (STM m)
simplePromotionPolicy,
policyPickInboundPeers :: PickPolicy peerAddr (STM m)
policyPickInboundPeers = PickPolicy peerAddr (STM m)
simplePromotionPolicy,
policyPickHotPeersToDemote :: PickPolicy peerAddr (STM m)
policyPickHotPeersToDemote = PickPolicy peerAddr (STM m)
hotDemotionPolicy,
policyPickWarmPeersToDemote :: PickPolicy peerAddr (STM m)
policyPickWarmPeersToDemote = PickPolicy peerAddr (STM m)
warmDemotionPolicy,
policyPickColdPeersToForget :: PickPolicy peerAddr (STM m)
policyPickColdPeersToForget = PickPolicy peerAddr (STM m)
coldForgetPolicy,
policyFindPublicRootTimeout :: DiffTime
policyFindPublicRootTimeout = DiffTime
5,
policyMaxInProgressPeerShareReqs :: Int
policyMaxInProgressPeerShareReqs = Int
2,
policyPeerShareRetryTime :: DiffTime
policyPeerShareRetryTime = DiffTime
900,
policyPeerShareBatchWaitTime :: DiffTime
policyPeerShareBatchWaitTime = DiffTime
3,
policyPeerShareOverallTimeout :: DiffTime
policyPeerShareOverallTimeout = DiffTime
10,
policyPeerShareActivationDelay :: DiffTime
policyPeerShareActivationDelay = DiffTime
300,
policyErrorDelay :: DiffTime
policyErrorDelay = RepromoteDelay -> DiffTime
ExitPolicy.repromoteDelay RepromoteDelay
errorDelay
}
where
addRand :: Set.Set peerAddr
-> (peerAddr -> Word32 -> (peerAddr, Word32))
-> STM m (Map.Map peerAddr Word32)
addRand :: Set peerAddr
-> (peerAddr -> Word32 -> (peerAddr, Word32))
-> STM m (Map peerAddr Word32)
addRand Set peerAddr
available peerAddr -> Word32 -> (peerAddr, Word32)
scaleFn = do
inRng <- StrictTVar m StdGen -> STM m StdGen
forall (m :: * -> *) a. MonadSTM m => StrictTVar m a -> STM m a
readTVar StrictTVar m StdGen
rngVar
let (rng, rng') = split inRng
rns = Int -> [Word32] -> [Word32]
forall a. Int -> [a] -> [a]
take (Set peerAddr -> Int
forall a. Set a -> Int
Set.size Set peerAddr
available) ([Word32] -> [Word32]) -> [Word32] -> [Word32]
forall a b. (a -> b) -> a -> b
$ (StdGen -> Maybe (Word32, StdGen)) -> StdGen -> [Word32]
forall b a. (b -> Maybe (a, b)) -> b -> [a]
unfoldr ((Word32, StdGen) -> Maybe (Word32, StdGen)
forall a. a -> Maybe a
Just ((Word32, StdGen) -> Maybe (Word32, StdGen))
-> (StdGen -> (Word32, StdGen)) -> StdGen -> Maybe (Word32, StdGen)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. StdGen -> (Word32, StdGen)
forall g. RandomGen g => g -> (Word32, g)
forall a g. (Random a, RandomGen g) => g -> (a, g)
random) StdGen
rng :: [Word32]
available' = [(peerAddr, Word32)] -> Map peerAddr Word32
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList ([(peerAddr, Word32)] -> Map peerAddr Word32)
-> [(peerAddr, Word32)] -> Map peerAddr Word32
forall a b. (a -> b) -> a -> b
$ (peerAddr -> Word32 -> (peerAddr, Word32))
-> [peerAddr] -> [Word32] -> [(peerAddr, Word32)]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith peerAddr -> Word32 -> (peerAddr, Word32)
scaleFn (Set peerAddr -> [peerAddr]
forall a. Set a -> [a]
Set.toList Set peerAddr
available) [Word32]
rns
writeTVar rngVar rng'
return available'
hotDemotionPolicy :: PickPolicy peerAddr (STM m)
hotDemotionPolicy :: PickPolicy peerAddr (STM m)
hotDemotionPolicy peerAddr -> PeerSource
_ peerAddr -> Int
_ peerAddr -> Bool
_ Set peerAddr
available Int
pickNum = do
mode <- STM m ChurnMode
getChurnMode
scores <- case mode of
ChurnMode
ChurnModeNormal -> do
jpm <- PeerMetrics m peerAddr -> STM m (Map peerAddr SlotNo)
forall p (m :: * -> *).
(MonadSTM m, Ord p) =>
PeerMetrics m p -> STM m (Map p SlotNo)
joinedPeerMetricAt PeerMetrics m peerAddr
metrics
hup <- upstreamyness metrics
bup <- fetchynessBlocks metrics
return $ Map.unionWith (+) hup bup `optionalMerge` jpm
ChurnMode
ChurnModeBulkSync -> do
jpm <- PeerMetrics m peerAddr -> STM m (Map peerAddr SlotNo)
forall p (m :: * -> *).
(MonadSTM m, Ord p) =>
PeerMetrics m p -> STM m (Map p SlotNo)
joinedPeerMetricAt PeerMetrics m peerAddr
metrics
bup <- fetchynessBytes metrics
return $ bup `optionalMerge` jpm
available' <- addRand available (,)
return $ Set.fromList
. map fst
. take pickNum
. sortOn (\(peerAddr
peer, Word32
rn) ->
((Int, Maybe SlotNo)
-> peerAddr
-> Map peerAddr (Int, Maybe SlotNo)
-> (Int, Maybe SlotNo)
forall k a. Ord k => a -> k -> Map k a -> a
Map.findWithDefault (Int
0, Maybe SlotNo
forall a. Maybe a
Nothing) peerAddr
peer Map peerAddr (Int, Maybe SlotNo)
scores, Word32
rn))
. Map.assocs
$ available'
warmDemotionPolicy :: PickPolicy peerAddr (STM m)
warmDemotionPolicy :: PickPolicy peerAddr (STM m)
warmDemotionPolicy peerAddr -> PeerSource
_ peerAddr -> Int
_ peerAddr -> Bool
isTepid Set peerAddr
available Int
pickNum = do
available' <- Set peerAddr
-> (peerAddr -> Word32 -> (peerAddr, Word32))
-> STM m (Map peerAddr Word32)
addRand Set peerAddr
available ((peerAddr -> Bool) -> peerAddr -> Word32 -> (peerAddr, Word32)
tepidWeight peerAddr -> Bool
isTepid)
return $ Set.fromList
. map fst
. take pickNum
. sortOn snd
. Map.assocs
$ available'
coldForgetPolicy :: PickPolicy peerAddr (STM m)
coldForgetPolicy :: PickPolicy peerAddr (STM m)
coldForgetPolicy peerAddr -> PeerSource
_ peerAddr -> Int
failCnt peerAddr -> Bool
_ Set peerAddr
available Int
pickNum = do
available' <- Set peerAddr
-> (peerAddr -> Word32 -> (peerAddr, Word32))
-> STM m (Map peerAddr Word32)
addRand Set peerAddr
available ((peerAddr -> Int) -> peerAddr -> Word32 -> (peerAddr, Word32)
failWeight peerAddr -> Int
failCnt)
return $ Set.fromList
. map fst
. take pickNum
. sortOn snd
. Map.assocs
$ available'
simplePromotionPolicy :: PickPolicy peerAddr (STM m)
simplePromotionPolicy :: PickPolicy peerAddr (STM m)
simplePromotionPolicy peerAddr -> PeerSource
_ peerAddr -> Int
_ peerAddr -> Bool
_ Set peerAddr
available Int
pickNum = do
available' <- Set peerAddr
-> (peerAddr -> Word32 -> (peerAddr, Word32))
-> STM m (Map peerAddr Word32)
addRand Set peerAddr
available (,)
return $ Set.fromList
. map fst
. take pickNum
. sortOn snd
. Map.assocs
$ available'
failWeight :: (peerAddr -> Int)
-> peerAddr
-> Word32
-> (peerAddr, Word32)
failWeight :: (peerAddr -> Int) -> peerAddr -> Word32 -> (peerAddr, Word32)
failWeight peerAddr -> Int
failCnt peerAddr
peer Word32
r =
(peerAddr
peer, Word32
r Word32 -> Word32 -> Word32
forall a. Integral a => a -> a -> a
`div` Int -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (peerAddr -> Int
failCnt peerAddr
peer Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1))
tepidWeight :: (peerAddr -> Bool)
-> peerAddr
-> Word32
-> (peerAddr, Word32)
tepidWeight :: (peerAddr -> Bool) -> peerAddr -> Word32 -> (peerAddr, Word32)
tepidWeight peerAddr -> Bool
isTepid peerAddr
peer Word32
r =
if peerAddr -> Bool
isTepid peerAddr
peer then (peerAddr
peer, Word32
r Word32 -> Word32 -> Word32
forall a. Integral a => a -> a -> a
`div` Word32
2)
else (peerAddr
peer, Word32
r)
prunePolicy :: Ord peerAddr
=> PrunePolicy peerAddr
prunePolicy :: forall peerAddr. Ord peerAddr => PrunePolicy peerAddr
prunePolicy StdGen
prng Map (ConnectionId peerAddr) ConnectionType
mp Int
n =
[ConnectionId peerAddr] -> Set (ConnectionId peerAddr)
forall a. Ord a => [a] -> Set a
Set.fromList
([ConnectionId peerAddr] -> Set (ConnectionId peerAddr))
-> ([Int] -> [ConnectionId peerAddr])
-> [Int]
-> Set (ConnectionId peerAddr)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> [ConnectionId peerAddr] -> [ConnectionId peerAddr]
forall a. Int -> [a] -> [a]
take Int
n
([ConnectionId peerAddr] -> [ConnectionId peerAddr])
-> ([Int] -> [ConnectionId peerAddr])
-> [Int]
-> [ConnectionId peerAddr]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (((ConnectionId peerAddr, ConnectionType), Int)
-> ConnectionId peerAddr)
-> [((ConnectionId peerAddr, ConnectionType), Int)]
-> [ConnectionId peerAddr]
forall a b. (a -> b) -> [a] -> [b]
map ((ConnectionId peerAddr, ConnectionType) -> ConnectionId peerAddr
forall a b. (a, b) -> a
fst ((ConnectionId peerAddr, ConnectionType) -> ConnectionId peerAddr)
-> (((ConnectionId peerAddr, ConnectionType), Int)
-> (ConnectionId peerAddr, ConnectionType))
-> ((ConnectionId peerAddr, ConnectionType), Int)
-> ConnectionId peerAddr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((ConnectionId peerAddr, ConnectionType), Int)
-> (ConnectionId peerAddr, ConnectionType)
forall a b. (a, b) -> a
fst)
([((ConnectionId peerAddr, ConnectionType), Int)]
-> [ConnectionId peerAddr])
-> ([Int] -> [((ConnectionId peerAddr, ConnectionType), Int)])
-> [Int]
-> [ConnectionId peerAddr]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (((ConnectionId peerAddr, ConnectionType), Int)
-> (Bool, Int, ConnectionType))
-> [((ConnectionId peerAddr, ConnectionType), Int)]
-> [((ConnectionId peerAddr, ConnectionType), Int)]
forall b a. Ord b => (a -> b) -> [a] -> [a]
sortOn (\((ConnectionId peerAddr
_, ConnectionType
connType), Int
score) -> (ConnectionType -> Bool
isUpstream ConnectionType
connType, Int
score, ConnectionType
connType))
([((ConnectionId peerAddr, ConnectionType), Int)]
-> [((ConnectionId peerAddr, ConnectionType), Int)])
-> ([Int] -> [((ConnectionId peerAddr, ConnectionType), Int)])
-> [Int]
-> [((ConnectionId peerAddr, ConnectionType), Int)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [(ConnectionId peerAddr, ConnectionType)]
-> [Int] -> [((ConnectionId peerAddr, ConnectionType), Int)]
forall a b. [a] -> [b] -> [(a, b)]
zip (Map (ConnectionId peerAddr) ConnectionType
-> [(ConnectionId peerAddr, ConnectionType)]
forall k a. Map k a -> [(k, a)]
Map.assocs Map (ConnectionId peerAddr) ConnectionType
mp)
([Int] -> Set (ConnectionId peerAddr))
-> [Int] -> Set (ConnectionId peerAddr)
forall a b. (a -> b) -> a -> b
$ (StdGen -> [Int]
forall g. RandomGen g => g -> [Int]
forall a g. (Random a, RandomGen g) => g -> [a]
Rnd.randoms StdGen
prng :: [Int])
where
isUpstream :: ConnectionType -> Bool
isUpstream :: ConnectionType -> Bool
isUpstream = \ConnectionType
connType ->
case ConnectionType
connType of
UnnegotiatedConn Provenance
Outbound -> Bool
True
UnnegotiatedConn Provenance
Inbound -> Bool
False
OutboundIdleConn DataFlow
_ -> Bool
True
InboundIdleConn DataFlow
_ -> Bool
False
NegotiatedConn Provenance
Outbound DataFlow
_ -> Bool
True
NegotiatedConn Provenance
Inbound DataFlow
_ -> Bool
False
ConnectionType
DuplexConn -> Bool
True