{-# LANGUAGE NamedFieldPuns      #-}
{-# LANGUAGE RecordWildCards     #-}
{-# LANGUAGE ScopedTypeVariables #-}

module Ouroboros.Network.PeerSelection.KnownPeers
  ( -- * Types
    KnownPeers
  , invariant
    -- * Basic container operations
  , empty
  , size
  , insert
  , delete
  , toSet
  , member
    -- * Special operations
  , setCurrentTime
  , incrementFailCount
  , resetFailCount
  , lookupFailCount
  , lookupTepidFlag
  , setTepidFlag
  , clearTepidFlag
    -- ** Tracking when we can gossip
  , minGossipTime
  , setGossipTime
  , availableForGossip
    -- ** Tracking when we can (re)connect
  , minConnectTime
  , setConnectTime
  , availableToConnect
  ) where

import qualified Data.List as List
import           Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
import           Data.OrdPSQ (OrdPSQ)
import qualified Data.OrdPSQ as PSQ
import           Data.Semigroup (Min (..))
import           Data.Set (Set)
import qualified Data.Set as Set
--import           System.Random (RandomGen(..))

import           Control.Exception (assert)
import           Control.Monad.Class.MonadTime


-------------------------------
-- Known peer set representation
--

-- | The set of known peers. To a first approximation it can be thought of as
-- a 'Set' of @peeraddr@.
--
-- It has two special features:
--
--  * It tracks which peers we are permitted to gossip with now, or for peers
--    we cannot gossip with now the time at which we would next be allowed to
--    do so.
--
--  * It tracks the subset of peers that we are happy to publish in reply to
--    gossip requests to our node. It supports random sampling from this set.
--
data KnownPeers peeraddr = KnownPeers {

       -- | All the known peers.
       --
       KnownPeers peeraddr -> Map peeraddr KnownPeerInfo
allPeers           :: !(Map peeraddr KnownPeerInfo),

       -- | The subset of known peers that we would be allowed to gossip with
       -- now. This is because we have not gossiped with them recently.
       --
       KnownPeers peeraddr -> Set peeraddr
availableForGossip :: !(Set peeraddr),

       -- | The subset of known peers that we cannot gossip with now. It keeps
       -- track of the next time we are allowed to gossip with them.
       --
       KnownPeers peeraddr -> OrdPSQ peeraddr Time ()
nextGossipTimes    :: !(OrdPSQ peeraddr Time ()),

       -- | The subset of known peers that we would be allowed to try to
       -- establish a connection to now. This is because we have not connected
       -- with them before or because any failure backoff time has expired.
       --
       KnownPeers peeraddr -> Set peeraddr
availableToConnect :: !(Set peeraddr),

       -- | The subset of known peers that we cannot connect to for the moment.
       -- It keeps track of the next time we are allowed to make the next
       -- connection attempt.
       KnownPeers peeraddr -> OrdPSQ peeraddr Time ()
nextConnectTimes   :: !(OrdPSQ peeraddr Time ())
     }
  deriving Int -> KnownPeers peeraddr -> ShowS
[KnownPeers peeraddr] -> ShowS
KnownPeers peeraddr -> String
(Int -> KnownPeers peeraddr -> ShowS)
-> (KnownPeers peeraddr -> String)
-> ([KnownPeers peeraddr] -> ShowS)
-> Show (KnownPeers peeraddr)
forall peeraddr.
Show peeraddr =>
Int -> KnownPeers peeraddr -> ShowS
forall peeraddr. Show peeraddr => [KnownPeers peeraddr] -> ShowS
forall peeraddr. Show peeraddr => KnownPeers peeraddr -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [KnownPeers peeraddr] -> ShowS
$cshowList :: forall peeraddr. Show peeraddr => [KnownPeers peeraddr] -> ShowS
show :: KnownPeers peeraddr -> String
$cshow :: forall peeraddr. Show peeraddr => KnownPeers peeraddr -> String
showsPrec :: Int -> KnownPeers peeraddr -> ShowS
$cshowsPrec :: forall peeraddr.
Show peeraddr =>
Int -> KnownPeers peeraddr -> ShowS
Show

data KnownPeerInfo = KnownPeerInfo {
       -- | The current number of consecutive connection attempt failures. This
       -- is reset as soon as there is a successful connection.
       --
       -- It is used to implement the exponential backoff strategy and may also
       -- be used by policies to select peers to forget.
       --
       KnownPeerInfo -> Int
knownPeerFailCount :: !Int,

       -- | Indicates if the peer was hot but then got demoted.
       --
       -- It is set on the hot to warm promotion and reset on cold to warm,
       -- thus it can be present for warm or cold peers.  It's purpose is to
       -- provide information to demotion policies.
       --
       KnownPeerInfo -> Bool
knownPeerTepid     :: !Bool
     }
  deriving (KnownPeerInfo -> KnownPeerInfo -> Bool
(KnownPeerInfo -> KnownPeerInfo -> Bool)
-> (KnownPeerInfo -> KnownPeerInfo -> Bool) -> Eq KnownPeerInfo
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: KnownPeerInfo -> KnownPeerInfo -> Bool
$c/= :: KnownPeerInfo -> KnownPeerInfo -> Bool
== :: KnownPeerInfo -> KnownPeerInfo -> Bool
$c== :: KnownPeerInfo -> KnownPeerInfo -> Bool
Eq, Int -> KnownPeerInfo -> ShowS
[KnownPeerInfo] -> ShowS
KnownPeerInfo -> String
(Int -> KnownPeerInfo -> ShowS)
-> (KnownPeerInfo -> String)
-> ([KnownPeerInfo] -> ShowS)
-> Show KnownPeerInfo
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [KnownPeerInfo] -> ShowS
$cshowList :: [KnownPeerInfo] -> ShowS
show :: KnownPeerInfo -> String
$cshow :: KnownPeerInfo -> String
showsPrec :: Int -> KnownPeerInfo -> ShowS
$cshowsPrec :: Int -> KnownPeerInfo -> ShowS
Show)


invariant :: Ord peeraddr => KnownPeers peeraddr -> Bool
invariant :: KnownPeers peeraddr -> Bool
invariant KnownPeers{Map peeraddr KnownPeerInfo
Set peeraddr
OrdPSQ peeraddr Time ()
nextConnectTimes :: OrdPSQ peeraddr Time ()
availableToConnect :: Set peeraddr
nextGossipTimes :: OrdPSQ peeraddr Time ()
availableForGossip :: Set peeraddr
allPeers :: Map peeraddr KnownPeerInfo
nextConnectTimes :: forall peeraddr. KnownPeers peeraddr -> OrdPSQ peeraddr Time ()
nextGossipTimes :: forall peeraddr. KnownPeers peeraddr -> OrdPSQ peeraddr Time ()
allPeers :: forall peeraddr. KnownPeers peeraddr -> Map peeraddr KnownPeerInfo
availableToConnect :: forall peeraddr. KnownPeers peeraddr -> Set peeraddr
availableForGossip :: forall peeraddr. KnownPeers peeraddr -> Set peeraddr
..} =
       -- The combo of the gossip set + psq = the whole set of peers
       Set peeraddr
availableForGossip
    Set peeraddr -> Set peeraddr -> Set peeraddr
forall a. Semigroup a => a -> a -> a
<> [peeraddr] -> Set peeraddr
forall a. Ord a => [a] -> Set a
Set.fromList (OrdPSQ peeraddr Time () -> [peeraddr]
forall k p v. OrdPSQ k p v -> [k]
PSQ.keys OrdPSQ peeraddr Time ()
nextGossipTimes)
    Set peeraddr -> Set peeraddr -> Bool
forall a. Eq a => a -> a -> Bool
== Map peeraddr KnownPeerInfo -> Set peeraddr
forall k a. Map k a -> Set k
Map.keysSet Map peeraddr KnownPeerInfo
allPeers

       -- The gossip set and psq do not overlap
 Bool -> Bool -> Bool
&& Set peeraddr -> Bool
forall a. Set a -> Bool
Set.null
      (Set peeraddr -> Set peeraddr -> Set peeraddr
forall a. Ord a => Set a -> Set a -> Set a
Set.intersection
         Set peeraddr
availableForGossip
        ([peeraddr] -> Set peeraddr
forall a. Ord a => [a] -> Set a
Set.fromList (OrdPSQ peeraddr Time () -> [peeraddr]
forall k p v. OrdPSQ k p v -> [k]
PSQ.keys OrdPSQ peeraddr Time ()
nextGossipTimes)))

       -- The combo of the connect set + psq = the whole set of peers
 Bool -> Bool -> Bool
&&    Set peeraddr
availableToConnect
    Set peeraddr -> Set peeraddr -> Set peeraddr
forall a. Semigroup a => a -> a -> a
<> [peeraddr] -> Set peeraddr
forall a. Ord a => [a] -> Set a
Set.fromList (OrdPSQ peeraddr Time () -> [peeraddr]
forall k p v. OrdPSQ k p v -> [k]
PSQ.keys OrdPSQ peeraddr Time ()
nextConnectTimes)
    Set peeraddr -> Set peeraddr -> Bool
forall a. Eq a => a -> a -> Bool
== Map peeraddr KnownPeerInfo -> Set peeraddr
forall k a. Map k a -> Set k
Map.keysSet Map peeraddr KnownPeerInfo
allPeers

       -- The connect set and psq do not overlap
 Bool -> Bool -> Bool
&& Set peeraddr -> Bool
forall a. Set a -> Bool
Set.null
      (Set peeraddr -> Set peeraddr -> Set peeraddr
forall a. Ord a => Set a -> Set a -> Set a
Set.intersection
         Set peeraddr
availableToConnect
        ([peeraddr] -> Set peeraddr
forall a. Ord a => [a] -> Set a
Set.fromList (OrdPSQ peeraddr Time () -> [peeraddr]
forall k p v. OrdPSQ k p v -> [k]
PSQ.keys OrdPSQ peeraddr Time ()
nextConnectTimes)))


-------------------------------
-- Basic container operations
--

empty :: KnownPeers peeraddr
empty :: KnownPeers peeraddr
empty =
    KnownPeers :: forall peeraddr.
Map peeraddr KnownPeerInfo
-> Set peeraddr
-> OrdPSQ peeraddr Time ()
-> Set peeraddr
-> OrdPSQ peeraddr Time ()
-> KnownPeers peeraddr
KnownPeers {
      allPeers :: Map peeraddr KnownPeerInfo
allPeers           = Map peeraddr KnownPeerInfo
forall k a. Map k a
Map.empty,
      availableForGossip :: Set peeraddr
availableForGossip = Set peeraddr
forall a. Set a
Set.empty,
      nextGossipTimes :: OrdPSQ peeraddr Time ()
nextGossipTimes    = OrdPSQ peeraddr Time ()
forall k p v. OrdPSQ k p v
PSQ.empty,
      availableToConnect :: Set peeraddr
availableToConnect = Set peeraddr
forall a. Set a
Set.empty,
      nextConnectTimes :: OrdPSQ peeraddr Time ()
nextConnectTimes   = OrdPSQ peeraddr Time ()
forall k p v. OrdPSQ k p v
PSQ.empty
    }

size :: KnownPeers peeraddr -> Int
size :: KnownPeers peeraddr -> Int
size = Map peeraddr KnownPeerInfo -> Int
forall k a. Map k a -> Int
Map.size (Map peeraddr KnownPeerInfo -> Int)
-> (KnownPeers peeraddr -> Map peeraddr KnownPeerInfo)
-> KnownPeers peeraddr
-> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. KnownPeers peeraddr -> Map peeraddr KnownPeerInfo
forall peeraddr. KnownPeers peeraddr -> Map peeraddr KnownPeerInfo
allPeers

-- | /O(n)/
toSet :: KnownPeers peeraddr -> Set peeraddr
toSet :: KnownPeers peeraddr -> Set peeraddr
toSet = Map peeraddr KnownPeerInfo -> Set peeraddr
forall k a. Map k a -> Set k
Map.keysSet (Map peeraddr KnownPeerInfo -> Set peeraddr)
-> (KnownPeers peeraddr -> Map peeraddr KnownPeerInfo)
-> KnownPeers peeraddr
-> Set peeraddr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. KnownPeers peeraddr -> Map peeraddr KnownPeerInfo
forall peeraddr. KnownPeers peeraddr -> Map peeraddr KnownPeerInfo
allPeers

member :: Ord peeraddr
       => peeraddr
       -> KnownPeers peeraddr
       -> Bool
member :: peeraddr -> KnownPeers peeraddr -> Bool
member peeraddr
peeraddr KnownPeers {Map peeraddr KnownPeerInfo
allPeers :: Map peeraddr KnownPeerInfo
allPeers :: forall peeraddr. KnownPeers peeraddr -> Map peeraddr KnownPeerInfo
allPeers} =
    peeraddr
peeraddr peeraddr -> Map peeraddr KnownPeerInfo -> Bool
forall k a. Ord k => k -> Map k a -> Bool
`Map.member` Map peeraddr KnownPeerInfo
allPeers

insert :: Ord peeraddr
       => Set peeraddr
       -> KnownPeers peeraddr
       -> KnownPeers peeraddr
insert :: Set peeraddr -> KnownPeers peeraddr -> KnownPeers peeraddr
insert Set peeraddr
peeraddrs
       knownPeers :: KnownPeers peeraddr
knownPeers@KnownPeers {
         Map peeraddr KnownPeerInfo
allPeers :: Map peeraddr KnownPeerInfo
allPeers :: forall peeraddr. KnownPeers peeraddr -> Map peeraddr KnownPeerInfo
allPeers,
         Set peeraddr
availableForGossip :: Set peeraddr
availableForGossip :: forall peeraddr. KnownPeers peeraddr -> Set peeraddr
availableForGossip,
         Set peeraddr
availableToConnect :: Set peeraddr
availableToConnect :: forall peeraddr. KnownPeers peeraddr -> Set peeraddr
availableToConnect
       } =
    let knownPeers' :: KnownPeers peeraddr
knownPeers' = KnownPeers peeraddr
knownPeers {
          allPeers :: Map peeraddr KnownPeerInfo
allPeers =
              let <+> :: Map peeraddr KnownPeerInfo
-> Map peeraddr KnownPeerInfo -> Map peeraddr KnownPeerInfo
(<+>) = (KnownPeerInfo -> KnownPeerInfo -> KnownPeerInfo)
-> Map peeraddr KnownPeerInfo
-> Map peeraddr KnownPeerInfo
-> Map peeraddr KnownPeerInfo
forall k a. Ord k => (a -> a -> a) -> Map k a -> Map k a -> Map k a
Map.unionWith KnownPeerInfo -> KnownPeerInfo -> KnownPeerInfo
forall p. KnownPeerInfo -> p -> KnownPeerInfo
mergePeerInfo in
              Map peeraddr KnownPeerInfo
allPeers
          Map peeraddr KnownPeerInfo
-> Map peeraddr KnownPeerInfo -> Map peeraddr KnownPeerInfo
<+> (peeraddr -> KnownPeerInfo)
-> Set peeraddr -> Map peeraddr KnownPeerInfo
forall k a. (k -> a) -> Set k -> Map k a
Map.fromSet peeraddr -> KnownPeerInfo
forall p. p -> KnownPeerInfo
newPeerInfo Set peeraddr
peeraddrs,

          -- The sets tracking peers ready for gossip or to connect to need to
          -- be updated with any /fresh/ peers, but any already present are
          -- ignored since they are either already in these sets or they are in
          -- the corresponding PSQs, for which we also preserve existing info.
          availableForGossip :: Set peeraddr
availableForGossip =
              Set peeraddr
availableForGossip
           Set peeraddr -> Set peeraddr -> Set peeraddr
forall a. Semigroup a => a -> a -> a
<> (peeraddr -> Bool) -> Set peeraddr -> Set peeraddr
forall a. (a -> Bool) -> Set a -> Set a
Set.filter (peeraddr -> Map peeraddr KnownPeerInfo -> Bool
forall k a. Ord k => k -> Map k a -> Bool
`Map.notMember` Map peeraddr KnownPeerInfo
allPeers) Set peeraddr
peeraddrs,

          availableToConnect :: Set peeraddr
availableToConnect =
              Set peeraddr
availableToConnect
           Set peeraddr -> Set peeraddr -> Set peeraddr
forall a. Semigroup a => a -> a -> a
<> (peeraddr -> Bool) -> Set peeraddr -> Set peeraddr
forall a. (a -> Bool) -> Set a -> Set a
Set.filter (peeraddr -> Map peeraddr KnownPeerInfo -> Bool
forall k a. Ord k => k -> Map k a -> Bool
`Map.notMember` Map peeraddr KnownPeerInfo
allPeers) Set peeraddr
peeraddrs
        }
    in Bool -> KnownPeers peeraddr -> KnownPeers peeraddr
forall a. (?callStack::CallStack) => Bool -> a -> a
assert (KnownPeers peeraddr -> Bool
forall peeraddr. Ord peeraddr => KnownPeers peeraddr -> Bool
invariant KnownPeers peeraddr
knownPeers') KnownPeers peeraddr
knownPeers'
  where
    newPeerInfo :: p -> KnownPeerInfo
newPeerInfo p
_peeraddr =
      KnownPeerInfo :: Int -> Bool -> KnownPeerInfo
KnownPeerInfo {
        knownPeerFailCount :: Int
knownPeerFailCount = Int
0
      , knownPeerTepid :: Bool
knownPeerTepid     = Bool
False
      }
    mergePeerInfo :: KnownPeerInfo -> p -> KnownPeerInfo
mergePeerInfo KnownPeerInfo
old p
_new =
      KnownPeerInfo :: Int -> Bool -> KnownPeerInfo
KnownPeerInfo {
        knownPeerFailCount :: Int
knownPeerFailCount = KnownPeerInfo -> Int
knownPeerFailCount KnownPeerInfo
old
      , knownPeerTepid :: Bool
knownPeerTepid     = KnownPeerInfo -> Bool
knownPeerTepid KnownPeerInfo
old
      }

delete :: Ord peeraddr
       => Set peeraddr
       -> KnownPeers peeraddr
       -> KnownPeers peeraddr
delete :: Set peeraddr -> KnownPeers peeraddr -> KnownPeers peeraddr
delete Set peeraddr
peeraddrs
       knownPeers :: KnownPeers peeraddr
knownPeers@KnownPeers {
         Map peeraddr KnownPeerInfo
allPeers :: Map peeraddr KnownPeerInfo
allPeers :: forall peeraddr. KnownPeers peeraddr -> Map peeraddr KnownPeerInfo
allPeers,
         Set peeraddr
availableForGossip :: Set peeraddr
availableForGossip :: forall peeraddr. KnownPeers peeraddr -> Set peeraddr
availableForGossip,
         OrdPSQ peeraddr Time ()
nextGossipTimes :: OrdPSQ peeraddr Time ()
nextGossipTimes :: forall peeraddr. KnownPeers peeraddr -> OrdPSQ peeraddr Time ()
nextGossipTimes,
         Set peeraddr
availableToConnect :: Set peeraddr
availableToConnect :: forall peeraddr. KnownPeers peeraddr -> Set peeraddr
availableToConnect,
         OrdPSQ peeraddr Time ()
nextConnectTimes :: OrdPSQ peeraddr Time ()
nextConnectTimes :: forall peeraddr. KnownPeers peeraddr -> OrdPSQ peeraddr Time ()
nextConnectTimes
       } =
    KnownPeers peeraddr
knownPeers {
      allPeers :: Map peeraddr KnownPeerInfo
allPeers =
        Map peeraddr KnownPeerInfo
-> Set peeraddr -> Map peeraddr KnownPeerInfo
forall k a. Ord k => Map k a -> Set k -> Map k a
Map.withoutKeys Map peeraddr KnownPeerInfo
allPeers Set peeraddr
peeraddrs,

      availableForGossip :: Set peeraddr
availableForGossip =
        Set peeraddr -> Set peeraddr -> Set peeraddr
forall a. Ord a => Set a -> Set a -> Set a
Set.difference Set peeraddr
availableForGossip Set peeraddr
peeraddrs,

      nextGossipTimes :: OrdPSQ peeraddr Time ()
nextGossipTimes =
        (OrdPSQ peeraddr Time () -> peeraddr -> OrdPSQ peeraddr Time ())
-> OrdPSQ peeraddr Time ()
-> Set peeraddr
-> OrdPSQ peeraddr Time ()
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
List.foldl' ((peeraddr -> OrdPSQ peeraddr Time () -> OrdPSQ peeraddr Time ())
-> OrdPSQ peeraddr Time () -> peeraddr -> OrdPSQ peeraddr Time ()
forall a b c. (a -> b -> c) -> b -> a -> c
flip peeraddr -> OrdPSQ peeraddr Time () -> OrdPSQ peeraddr Time ()
forall k p v. (Ord k, Ord p) => k -> OrdPSQ k p v -> OrdPSQ k p v
PSQ.delete) OrdPSQ peeraddr Time ()
nextGossipTimes Set peeraddr
peeraddrs,

      availableToConnect :: Set peeraddr
availableToConnect =
        Set peeraddr -> Set peeraddr -> Set peeraddr
forall a. Ord a => Set a -> Set a -> Set a
Set.difference Set peeraddr
availableToConnect Set peeraddr
peeraddrs,

      nextConnectTimes :: OrdPSQ peeraddr Time ()
nextConnectTimes =
        (OrdPSQ peeraddr Time () -> peeraddr -> OrdPSQ peeraddr Time ())
-> OrdPSQ peeraddr Time ()
-> Set peeraddr
-> OrdPSQ peeraddr Time ()
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
List.foldl' ((peeraddr -> OrdPSQ peeraddr Time () -> OrdPSQ peeraddr Time ())
-> OrdPSQ peeraddr Time () -> peeraddr -> OrdPSQ peeraddr Time ()
forall a b c. (a -> b -> c) -> b -> a -> c
flip peeraddr -> OrdPSQ peeraddr Time () -> OrdPSQ peeraddr Time ()
forall k p v. (Ord k, Ord p) => k -> OrdPSQ k p v -> OrdPSQ k p v
PSQ.delete) OrdPSQ peeraddr Time ()
nextConnectTimes Set peeraddr
peeraddrs
    }


-------------------------------
-- Special operations
--

setCurrentTime :: Ord peeraddr
               => Time
               -> KnownPeers peeraddr
               -> KnownPeers peeraddr
setCurrentTime :: Time -> KnownPeers peeraddr -> KnownPeers peeraddr
setCurrentTime Time
now knownPeers :: KnownPeers peeraddr
knownPeers@KnownPeers { OrdPSQ peeraddr Time ()
nextGossipTimes :: OrdPSQ peeraddr Time ()
nextGossipTimes :: forall peeraddr. KnownPeers peeraddr -> OrdPSQ peeraddr Time ()
nextGossipTimes, OrdPSQ peeraddr Time ()
nextConnectTimes :: OrdPSQ peeraddr Time ()
nextConnectTimes :: forall peeraddr. KnownPeers peeraddr -> OrdPSQ peeraddr Time ()
nextConnectTimes }
 -- Efficient check for the common case of there being nothing to do:
  | Just (Min Time
t) <- ((peeraddr, Time, (), OrdPSQ peeraddr Time ()) -> Min Time
forall a a c d. (a, a, c, d) -> Min a
f ((peeraddr, Time, (), OrdPSQ peeraddr Time ()) -> Min Time)
-> Maybe (peeraddr, Time, (), OrdPSQ peeraddr Time ())
-> Maybe (Min Time)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> OrdPSQ peeraddr Time ()
-> Maybe (peeraddr, Time, (), OrdPSQ peeraddr Time ())
forall k p v.
(Ord k, Ord p) =>
OrdPSQ k p v -> Maybe (k, p, v, OrdPSQ k p v)
PSQ.minView OrdPSQ peeraddr Time ()
nextGossipTimes)
                 Maybe (Min Time) -> Maybe (Min Time) -> Maybe (Min Time)
forall a. Semigroup a => a -> a -> a
<> ((peeraddr, Time, (), OrdPSQ peeraddr Time ()) -> Min Time
forall a a c d. (a, a, c, d) -> Min a
f ((peeraddr, Time, (), OrdPSQ peeraddr Time ()) -> Min Time)
-> Maybe (peeraddr, Time, (), OrdPSQ peeraddr Time ())
-> Maybe (Min Time)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> OrdPSQ peeraddr Time ()
-> Maybe (peeraddr, Time, (), OrdPSQ peeraddr Time ())
forall k p v.
(Ord k, Ord p) =>
OrdPSQ k p v -> Maybe (k, p, v, OrdPSQ k p v)
PSQ.minView OrdPSQ peeraddr Time ()
nextConnectTimes)
  , Time
t Time -> Time -> Bool
forall a. Ord a => a -> a -> Bool
> Time
now
  = KnownPeers peeraddr
knownPeers
  where
    f :: (a, a, c, d) -> Min a
f (a
_,a
t,c
_,d
_) = a -> Min a
forall a. a -> Min a
Min a
t

setCurrentTime Time
now knownPeers :: KnownPeers peeraddr
knownPeers@KnownPeers {
                     Set peeraddr
availableForGossip :: Set peeraddr
availableForGossip :: forall peeraddr. KnownPeers peeraddr -> Set peeraddr
availableForGossip,
                     OrdPSQ peeraddr Time ()
nextGossipTimes :: OrdPSQ peeraddr Time ()
nextGossipTimes :: forall peeraddr. KnownPeers peeraddr -> OrdPSQ peeraddr Time ()
nextGossipTimes,
                     Set peeraddr
availableToConnect :: Set peeraddr
availableToConnect :: forall peeraddr. KnownPeers peeraddr -> Set peeraddr
availableToConnect,
                     OrdPSQ peeraddr Time ()
nextConnectTimes :: OrdPSQ peeraddr Time ()
nextConnectTimes :: forall peeraddr. KnownPeers peeraddr -> OrdPSQ peeraddr Time ()
nextConnectTimes
                   } =
  let knownPeers' :: KnownPeers peeraddr
knownPeers' =
        KnownPeers peeraddr
knownPeers {
          availableForGossip :: Set peeraddr
availableForGossip = Set peeraddr
availableForGossip',
          nextGossipTimes :: OrdPSQ peeraddr Time ()
nextGossipTimes    = OrdPSQ peeraddr Time ()
nextGossipTimes',
          availableToConnect :: Set peeraddr
availableToConnect = Set peeraddr
availableToConnect',
          nextConnectTimes :: OrdPSQ peeraddr Time ()
nextConnectTimes   = OrdPSQ peeraddr Time ()
nextConnectTimes'
        }
   in Bool -> KnownPeers peeraddr -> KnownPeers peeraddr
forall a. (?callStack::CallStack) => Bool -> a -> a
assert (KnownPeers peeraddr -> Bool
forall peeraddr. Ord peeraddr => KnownPeers peeraddr -> Bool
invariant KnownPeers peeraddr
knownPeers') KnownPeers peeraddr
knownPeers'
  where
    ([(peeraddr, Time, ())]
nowAvailableForGossip, OrdPSQ peeraddr Time ()
nextGossipTimes') =
      Time
-> OrdPSQ peeraddr Time ()
-> ([(peeraddr, Time, ())], OrdPSQ peeraddr Time ())
forall k p v.
(Ord k, Ord p) =>
p -> OrdPSQ k p v -> ([(k, p, v)], OrdPSQ k p v)
PSQ.atMostView Time
now OrdPSQ peeraddr Time ()
nextGossipTimes

    availableForGossip' :: Set peeraddr
availableForGossip' =
         Set peeraddr
availableForGossip
      Set peeraddr -> Set peeraddr -> Set peeraddr
forall a. Semigroup a => a -> a -> a
<> [peeraddr] -> Set peeraddr
forall a. Ord a => [a] -> Set a
Set.fromList [ peeraddr
peeraddr | (peeraddr
peeraddr, Time
_, ()
_) <- [(peeraddr, Time, ())]
nowAvailableForGossip ]

    ([(peeraddr, Time, ())]
nowAvailableToConnect, OrdPSQ peeraddr Time ()
nextConnectTimes') =
      Time
-> OrdPSQ peeraddr Time ()
-> ([(peeraddr, Time, ())], OrdPSQ peeraddr Time ())
forall k p v.
(Ord k, Ord p) =>
p -> OrdPSQ k p v -> ([(k, p, v)], OrdPSQ k p v)
PSQ.atMostView Time
now OrdPSQ peeraddr Time ()
nextConnectTimes

    availableToConnect' :: Set peeraddr
availableToConnect' =
         Set peeraddr
availableToConnect
      Set peeraddr -> Set peeraddr -> Set peeraddr
forall a. Semigroup a => a -> a -> a
<> [peeraddr] -> Set peeraddr
forall a. Ord a => [a] -> Set a
Set.fromList [ peeraddr
peeraddr | (peeraddr
peeraddr, Time
_, ()
_) <- [(peeraddr, Time, ())]
nowAvailableToConnect ]


incrementFailCount :: Ord peeraddr
                   => peeraddr
                   -> KnownPeers peeraddr
                   -> (Int, KnownPeers peeraddr)
incrementFailCount :: peeraddr -> KnownPeers peeraddr -> (Int, KnownPeers peeraddr)
incrementFailCount peeraddr
peeraddr knownPeers :: KnownPeers peeraddr
knownPeers@KnownPeers{Map peeraddr KnownPeerInfo
allPeers :: Map peeraddr KnownPeerInfo
allPeers :: forall peeraddr. KnownPeers peeraddr -> Map peeraddr KnownPeerInfo
allPeers} =
    Bool -> (Int, KnownPeers peeraddr) -> (Int, KnownPeers peeraddr)
forall a. (?callStack::CallStack) => Bool -> a -> a
assert (peeraddr
peeraddr peeraddr -> Map peeraddr KnownPeerInfo -> Bool
forall k a. Ord k => k -> Map k a -> Bool
`Map.member` Map peeraddr KnownPeerInfo
allPeers) ((Int, KnownPeers peeraddr) -> (Int, KnownPeers peeraddr))
-> (Int, KnownPeers peeraddr) -> (Int, KnownPeers peeraddr)
forall a b. (a -> b) -> a -> b
$
    let allPeers' :: Map peeraddr KnownPeerInfo
allPeers' = (KnownPeerInfo -> Maybe KnownPeerInfo)
-> peeraddr
-> Map peeraddr KnownPeerInfo
-> Map peeraddr KnownPeerInfo
forall k a. Ord k => (a -> Maybe a) -> k -> Map k a -> Map k a
Map.update (KnownPeerInfo -> Maybe KnownPeerInfo
forall a. a -> Maybe a
Just (KnownPeerInfo -> Maybe KnownPeerInfo)
-> (KnownPeerInfo -> KnownPeerInfo)
-> KnownPeerInfo
-> Maybe KnownPeerInfo
forall b c a. (b -> c) -> (a -> b) -> a -> c
. KnownPeerInfo -> KnownPeerInfo
incr) peeraddr
peeraddr Map peeraddr KnownPeerInfo
allPeers
    in ( -- since the `peeraddr` is assumed to be part of `allPeers` the `Map.!`
         -- is safe
         KnownPeerInfo -> Int
knownPeerFailCount (Map peeraddr KnownPeerInfo
allPeers' Map peeraddr KnownPeerInfo -> peeraddr -> KnownPeerInfo
forall k a. Ord k => Map k a -> k -> a
Map.! peeraddr
peeraddr)
       , KnownPeers peeraddr
knownPeers { allPeers :: Map peeraddr KnownPeerInfo
allPeers = Map peeraddr KnownPeerInfo
allPeers' }
       )
  where
    incr :: KnownPeerInfo -> KnownPeerInfo
incr KnownPeerInfo
kpi = KnownPeerInfo
kpi { knownPeerFailCount :: Int
knownPeerFailCount = KnownPeerInfo -> Int
knownPeerFailCount KnownPeerInfo
kpi Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1 }


resetFailCount :: Ord peeraddr
               => peeraddr
               -> KnownPeers peeraddr
               -> KnownPeers peeraddr
resetFailCount :: peeraddr -> KnownPeers peeraddr -> KnownPeers peeraddr
resetFailCount peeraddr
peeraddr knownPeers :: KnownPeers peeraddr
knownPeers@KnownPeers{Map peeraddr KnownPeerInfo
allPeers :: Map peeraddr KnownPeerInfo
allPeers :: forall peeraddr. KnownPeers peeraddr -> Map peeraddr KnownPeerInfo
allPeers} =
    Bool -> KnownPeers peeraddr -> KnownPeers peeraddr
forall a. (?callStack::CallStack) => Bool -> a -> a
assert (peeraddr
peeraddr peeraddr -> Map peeraddr KnownPeerInfo -> Bool
forall k a. Ord k => k -> Map k a -> Bool
`Map.member` Map peeraddr KnownPeerInfo
allPeers) (KnownPeers peeraddr -> KnownPeers peeraddr)
-> KnownPeers peeraddr -> KnownPeers peeraddr
forall a b. (a -> b) -> a -> b
$
    KnownPeers peeraddr
knownPeers { allPeers :: Map peeraddr KnownPeerInfo
allPeers = (KnownPeerInfo -> Maybe KnownPeerInfo)
-> peeraddr
-> Map peeraddr KnownPeerInfo
-> Map peeraddr KnownPeerInfo
forall k a. Ord k => (a -> Maybe a) -> k -> Map k a -> Map k a
Map.update (\KnownPeerInfo
kpi  -> KnownPeerInfo -> Maybe KnownPeerInfo
forall a. a -> Maybe a
Just KnownPeerInfo
kpi { knownPeerFailCount :: Int
knownPeerFailCount = Int
0 })
                              peeraddr
peeraddr Map peeraddr KnownPeerInfo
allPeers
               }

lookupFailCount :: Ord peeraddr
                => peeraddr
                -> KnownPeers peeraddr
                -> Maybe Int
lookupFailCount :: peeraddr -> KnownPeers peeraddr -> Maybe Int
lookupFailCount peeraddr
peeraddr KnownPeers{Map peeraddr KnownPeerInfo
allPeers :: Map peeraddr KnownPeerInfo
allPeers :: forall peeraddr. KnownPeers peeraddr -> Map peeraddr KnownPeerInfo
allPeers} =
    KnownPeerInfo -> Int
knownPeerFailCount (KnownPeerInfo -> Int) -> Maybe KnownPeerInfo -> Maybe Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> peeraddr -> Map peeraddr KnownPeerInfo -> Maybe KnownPeerInfo
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup peeraddr
peeraddr Map peeraddr KnownPeerInfo
allPeers


lookupTepidFlag :: Ord peeraddr
                => peeraddr
                -> KnownPeers peeraddr
                -> Maybe Bool
lookupTepidFlag :: peeraddr -> KnownPeers peeraddr -> Maybe Bool
lookupTepidFlag peeraddr
peeraddr KnownPeers{Map peeraddr KnownPeerInfo
allPeers :: Map peeraddr KnownPeerInfo
allPeers :: forall peeraddr. KnownPeers peeraddr -> Map peeraddr KnownPeerInfo
allPeers} =
    KnownPeerInfo -> Bool
knownPeerTepid (KnownPeerInfo -> Bool) -> Maybe KnownPeerInfo -> Maybe Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> peeraddr -> Map peeraddr KnownPeerInfo -> Maybe KnownPeerInfo
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup peeraddr
peeraddr Map peeraddr KnownPeerInfo
allPeers

setTepidFlag' :: Ord peeraddr
             => Bool
             -> peeraddr
             -> KnownPeers peeraddr
             -> KnownPeers peeraddr
setTepidFlag' :: Bool -> peeraddr -> KnownPeers peeraddr -> KnownPeers peeraddr
setTepidFlag' Bool
val peeraddr
peeraddr knownPeers :: KnownPeers peeraddr
knownPeers@KnownPeers{Map peeraddr KnownPeerInfo
allPeers :: Map peeraddr KnownPeerInfo
allPeers :: forall peeraddr. KnownPeers peeraddr -> Map peeraddr KnownPeerInfo
allPeers} =
    Bool -> KnownPeers peeraddr -> KnownPeers peeraddr
forall a. (?callStack::CallStack) => Bool -> a -> a
assert (peeraddr
peeraddr peeraddr -> Map peeraddr KnownPeerInfo -> Bool
forall k a. Ord k => k -> Map k a -> Bool
`Map.member` Map peeraddr KnownPeerInfo
allPeers) (KnownPeers peeraddr -> KnownPeers peeraddr)
-> KnownPeers peeraddr -> KnownPeers peeraddr
forall a b. (a -> b) -> a -> b
$
    KnownPeers peeraddr
knownPeers { allPeers :: Map peeraddr KnownPeerInfo
allPeers = (KnownPeerInfo -> Maybe KnownPeerInfo)
-> peeraddr
-> Map peeraddr KnownPeerInfo
-> Map peeraddr KnownPeerInfo
forall k a. Ord k => (a -> Maybe a) -> k -> Map k a -> Map k a
Map.update (\KnownPeerInfo
kpi  -> KnownPeerInfo -> Maybe KnownPeerInfo
forall a. a -> Maybe a
Just KnownPeerInfo
kpi { knownPeerTepid :: Bool
knownPeerTepid = Bool
val })
                              peeraddr
peeraddr Map peeraddr KnownPeerInfo
allPeers
               }

clearTepidFlag :: Ord peeraddr
             => peeraddr
             -> KnownPeers peeraddr
             -> KnownPeers peeraddr
clearTepidFlag :: peeraddr -> KnownPeers peeraddr -> KnownPeers peeraddr
clearTepidFlag = Bool -> peeraddr -> KnownPeers peeraddr -> KnownPeers peeraddr
forall peeraddr.
Ord peeraddr =>
Bool -> peeraddr -> KnownPeers peeraddr -> KnownPeers peeraddr
setTepidFlag' Bool
False

setTepidFlag :: Ord peeraddr
             => peeraddr
             -> KnownPeers peeraddr
             -> KnownPeers peeraddr
setTepidFlag :: peeraddr -> KnownPeers peeraddr -> KnownPeers peeraddr
setTepidFlag = Bool -> peeraddr -> KnownPeers peeraddr -> KnownPeers peeraddr
forall peeraddr.
Ord peeraddr =>
Bool -> peeraddr -> KnownPeers peeraddr -> KnownPeers peeraddr
setTepidFlag' Bool
True

-------------------------------
-- Tracking when we can gossip
--

-- | The first time that a peer will become available for gossip. If peers are
-- already available for gossip, or there are no known peers at all then the
-- result is @Nothing@.
--
minGossipTime :: Ord peeraddr => KnownPeers peeraddr -> Maybe Time
minGossipTime :: KnownPeers peeraddr -> Maybe Time
minGossipTime KnownPeers {
                Set peeraddr
availableForGossip :: Set peeraddr
availableForGossip :: forall peeraddr. KnownPeers peeraddr -> Set peeraddr
availableForGossip,
                OrdPSQ peeraddr Time ()
nextGossipTimes :: OrdPSQ peeraddr Time ()
nextGossipTimes :: forall peeraddr. KnownPeers peeraddr -> OrdPSQ peeraddr Time ()
nextGossipTimes
              }
  | Set peeraddr -> Bool
forall a. Set a -> Bool
Set.null Set peeraddr
availableForGossip
  , Just (peeraddr
_k, Time
t, ()
_, OrdPSQ peeraddr Time ()
_psq) <- OrdPSQ peeraddr Time ()
-> Maybe (peeraddr, Time, (), OrdPSQ peeraddr Time ())
forall k p v.
(Ord k, Ord p) =>
OrdPSQ k p v -> Maybe (k, p, v, OrdPSQ k p v)
PSQ.minView OrdPSQ peeraddr Time ()
nextGossipTimes
  = Time -> Maybe Time
forall a. a -> Maybe a
Just Time
t

  | Bool
otherwise
  = Maybe Time
forall a. Maybe a
Nothing

setGossipTime :: Ord peeraddr
              => Set peeraddr
              -> Time
              -> KnownPeers peeraddr
              -> KnownPeers peeraddr
setGossipTime :: Set peeraddr -> Time -> KnownPeers peeraddr -> KnownPeers peeraddr
setGossipTime Set peeraddr
peeraddrs Time
time
              knownPeers :: KnownPeers peeraddr
knownPeers@KnownPeers {
                Map peeraddr KnownPeerInfo
allPeers :: Map peeraddr KnownPeerInfo
allPeers :: forall peeraddr. KnownPeers peeraddr -> Map peeraddr KnownPeerInfo
allPeers,
                Set peeraddr
availableForGossip :: Set peeraddr
availableForGossip :: forall peeraddr. KnownPeers peeraddr -> Set peeraddr
availableForGossip,
                OrdPSQ peeraddr Time ()
nextGossipTimes :: OrdPSQ peeraddr Time ()
nextGossipTimes :: forall peeraddr. KnownPeers peeraddr -> OrdPSQ peeraddr Time ()
nextGossipTimes
              } =
    Bool -> KnownPeers peeraddr -> KnownPeers peeraddr
forall a. (?callStack::CallStack) => Bool -> a -> a
assert ((peeraddr -> Bool) -> Set peeraddr -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (peeraddr -> Map peeraddr KnownPeerInfo -> Bool
forall k a. Ord k => k -> Map k a -> Bool
`Map.member` Map peeraddr KnownPeerInfo
allPeers) Set peeraddr
peeraddrs) (KnownPeers peeraddr -> KnownPeers peeraddr)
-> KnownPeers peeraddr -> KnownPeers peeraddr
forall a b. (a -> b) -> a -> b
$
    let knownPeers' :: KnownPeers peeraddr
knownPeers' = KnownPeers peeraddr
knownPeers {
          availableForGossip :: Set peeraddr
availableForGossip =
                   Set peeraddr
availableForGossip
            Set peeraddr -> Set peeraddr -> Set peeraddr
forall a. Ord a => Set a -> Set a -> Set a
Set.\\ Set peeraddr
peeraddrs,

          nextGossipTimes :: OrdPSQ peeraddr Time ()
nextGossipTimes =
            (OrdPSQ peeraddr Time () -> peeraddr -> OrdPSQ peeraddr Time ())
-> OrdPSQ peeraddr Time ()
-> Set peeraddr
-> OrdPSQ peeraddr Time ()
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
List.foldl' (\OrdPSQ peeraddr Time ()
psq peeraddr
peeraddr -> peeraddr
-> Time -> () -> OrdPSQ peeraddr Time () -> OrdPSQ peeraddr Time ()
forall k p v.
(Ord k, Ord p) =>
k -> p -> v -> OrdPSQ k p v -> OrdPSQ k p v
PSQ.insert peeraddr
peeraddr Time
time () OrdPSQ peeraddr Time ()
psq)
                        OrdPSQ peeraddr Time ()
nextGossipTimes
                        Set peeraddr
peeraddrs
        }
    in Bool -> KnownPeers peeraddr -> KnownPeers peeraddr
forall a. (?callStack::CallStack) => Bool -> a -> a
assert (KnownPeers peeraddr -> Bool
forall peeraddr. Ord peeraddr => KnownPeers peeraddr -> Bool
invariant KnownPeers peeraddr
knownPeers') KnownPeers peeraddr
knownPeers'


-----------------------------------
-- Tracking when we can (re)connect
--

minConnectTime :: Ord peeraddr
               => KnownPeers peeraddr
               -> Maybe Time
minConnectTime :: KnownPeers peeraddr -> Maybe Time
minConnectTime KnownPeers { OrdPSQ peeraddr Time ()
nextConnectTimes :: OrdPSQ peeraddr Time ()
nextConnectTimes :: forall peeraddr. KnownPeers peeraddr -> OrdPSQ peeraddr Time ()
nextConnectTimes }
  | Just (peeraddr
_k, Time
t, ()
_, OrdPSQ peeraddr Time ()
_psq) <- OrdPSQ peeraddr Time ()
-> Maybe (peeraddr, Time, (), OrdPSQ peeraddr Time ())
forall k p v.
(Ord k, Ord p) =>
OrdPSQ k p v -> Maybe (k, p, v, OrdPSQ k p v)
PSQ.minView OrdPSQ peeraddr Time ()
nextConnectTimes
  = Time -> Maybe Time
forall a. a -> Maybe a
Just Time
t

  | Bool
otherwise
  = Maybe Time
forall a. Maybe a
Nothing


setConnectTime :: Ord peeraddr
               => Set peeraddr --TODO: make this a single entry
               -> Time
               -> KnownPeers peeraddr
               -> KnownPeers peeraddr
setConnectTime :: Set peeraddr -> Time -> KnownPeers peeraddr -> KnownPeers peeraddr
setConnectTime Set peeraddr
peeraddrs Time
time
                 knownPeers :: KnownPeers peeraddr
knownPeers@KnownPeers {
                   Map peeraddr KnownPeerInfo
allPeers :: Map peeraddr KnownPeerInfo
allPeers :: forall peeraddr. KnownPeers peeraddr -> Map peeraddr KnownPeerInfo
allPeers,
                   Set peeraddr
availableToConnect :: Set peeraddr
availableToConnect :: forall peeraddr. KnownPeers peeraddr -> Set peeraddr
availableToConnect,
                   OrdPSQ peeraddr Time ()
nextConnectTimes :: OrdPSQ peeraddr Time ()
nextConnectTimes :: forall peeraddr. KnownPeers peeraddr -> OrdPSQ peeraddr Time ()
nextConnectTimes
                 } =
    Bool -> KnownPeers peeraddr -> KnownPeers peeraddr
forall a. (?callStack::CallStack) => Bool -> a -> a
assert ((peeraddr -> Bool) -> Set peeraddr -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (peeraddr -> Map peeraddr KnownPeerInfo -> Bool
forall k a. Ord k => k -> Map k a -> Bool
`Map.member` Map peeraddr KnownPeerInfo
allPeers) Set peeraddr
peeraddrs) (KnownPeers peeraddr -> KnownPeers peeraddr)
-> KnownPeers peeraddr -> KnownPeers peeraddr
forall a b. (a -> b) -> a -> b
$
    let knownPeers' :: KnownPeers peeraddr
knownPeers' = KnownPeers peeraddr
knownPeers {
          availableToConnect :: Set peeraddr
availableToConnect =
                   Set peeraddr
availableToConnect
            Set peeraddr -> Set peeraddr -> Set peeraddr
forall a. Ord a => Set a -> Set a -> Set a
Set.\\ Set peeraddr
peeraddrs,

          nextConnectTimes :: OrdPSQ peeraddr Time ()
nextConnectTimes =
            (OrdPSQ peeraddr Time () -> peeraddr -> OrdPSQ peeraddr Time ())
-> OrdPSQ peeraddr Time ()
-> Set peeraddr
-> OrdPSQ peeraddr Time ()
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
List.foldl' (\OrdPSQ peeraddr Time ()
psq peeraddr
peeraddr -> peeraddr
-> Time -> () -> OrdPSQ peeraddr Time () -> OrdPSQ peeraddr Time ()
forall k p v.
(Ord k, Ord p) =>
k -> p -> v -> OrdPSQ k p v -> OrdPSQ k p v
PSQ.insert peeraddr
peeraddr Time
time () OrdPSQ peeraddr Time ()
psq)
                        OrdPSQ peeraddr Time ()
nextConnectTimes
                        Set peeraddr
peeraddrs
        }
    in Bool -> KnownPeers peeraddr -> KnownPeers peeraddr
forall a. (?callStack::CallStack) => Bool -> a -> a
assert (KnownPeers peeraddr -> Bool
forall peeraddr. Ord peeraddr => KnownPeers peeraddr -> Bool
invariant KnownPeers peeraddr
knownPeers') KnownPeers peeraddr
knownPeers'


---------------------------------
-- Selecting peers to advertise
--

-- | Select a random subset of the known peers that are available to publish.
--
-- The selection is done in such a way that when the same initial PRNG state is
-- used, the selected set does not significantly vary with small perturbations
-- in the set of published peers.
--
-- The intention of this selection method is that the selection should give
-- approximately the same replies to the same peers over the course of multiple
-- requests from the same peer. This is to deliberately slow the rate at which
-- peers can discover and map out the entire network.
--
{-
sampleAdvertisedPeers :: RandomGen prng
                      => KnownPeers peeraddr
                      -> prng
                      -> Int
                      -> [peeraddr]
sampleAdvertisedPeers _ _ _ = []
-- idea is to generate a sequence of random numbers and map them to locations
-- in a relatively stable way, that's mostly insensitive to additions or
-- deletions
-}