basic PEX

has glitches; it's needed to determine when same
peer shows up under different address (like in case of
NAT)
This commit is contained in:
Dmitry Zuikov 2023-02-06 11:24:07 +03:00
parent a819bc82f1
commit 61a44eb544
14 changed files with 420 additions and 122 deletions

View File

@ -1,6 +1,30 @@
## 2023-02-06 ## 2023-02-06
Ну а так, базовый PEX заработал
TODO: Добавлять пиров в KnownPeers
только после того, как они
пинганулись. Т.е пинговать
пиров, если их еще нет.
Не добавлять в KnownPeers до
того, как ответили на пинг.
TODO: Научиться убирать дубликаты пиров.
Их можно распознать по PeerNonce,
но непонятно, какой из пиров
оставлять.
Иначе это будет реально большая
проблема при скачивании.
TODO: Убедиться, что subscribe на перманентное
событие НИКОГДА не вызывается в рекурсии.
Проверить ВСЕ subscribe.
Возможно, вставить проверки в рантайм.
Возможно, ограничить число таких событий
и ругаться в рантайме.
FIXME: При вычислении burst надо каким-то образом FIXME: При вычислении burst надо каким-то образом
находить плато и не лезть выше него. находить плато и не лезть выше него.

View File

@ -91,6 +91,7 @@ library
, HBS2.Net.Proto.Definition , HBS2.Net.Proto.Definition
, HBS2.Net.Proto.Peer , HBS2.Net.Proto.Peer
, HBS2.Net.Proto.PeerAnnounce , HBS2.Net.Proto.PeerAnnounce
, HBS2.Net.Proto.PeerExchange
, HBS2.Net.Proto.Sessions , HBS2.Net.Proto.Sessions
, HBS2.Net.Proto.Types , HBS2.Net.Proto.Types
, HBS2.OrDie , HBS2.OrDie

View File

@ -57,9 +57,6 @@ data AnyMessage enc e = AnyMessage !Integer !(Encoded e)
class Monad m => HasOwnPeer e m where class Monad m => HasOwnPeer e m where
ownPeer :: m (Peer e) ownPeer :: m (Peer e)
class Monad m => HasPeerLocator e m where
getPeerLocator :: m (AnyPeerLocator e)
class HasStorage m where class HasStorage m where
getStorage :: m AnyStorage getStorage :: m AnyStorage
@ -464,4 +461,6 @@ instance (Monad m, HasFabriq e m) => HasFabriq e (ResponseM e m) where
instance (Monad m, HasPeerNonce e m) => HasPeerNonce e (ResponseM e m) where instance (Monad m, HasPeerNonce e m) => HasPeerNonce e (ResponseM e m) where
peerNonce = lift $ peerNonce @e peerNonce = lift $ peerNonce @e
instance (Monad m, HasPeerLocator e m) => HasPeerLocator e (ResponseM e m) where
getPeerLocator = lift getPeerLocator

View File

@ -70,5 +70,8 @@ defSweepTimeout = 30 -- FIXME: only for debug!
defPeerAnnounceTime :: Timeout 'Seconds defPeerAnnounceTime :: Timeout 'Seconds
defPeerAnnounceTime = 120 defPeerAnnounceTime = 120
defPexMaxPeers :: Int
defPexMaxPeers = 50

View File

@ -4,10 +4,14 @@ module HBS2.Net.PeerLocator where
import HBS2.Prelude import HBS2.Prelude
import HBS2.Net.Proto.Types import HBS2.Net.Proto.Types
import System.Random.Shuffle (shuffleM)
class PeerLocator e l where class PeerLocator e l where
knownPeers :: forall m . (HasPeer e, MonadIO m) => l -> m [Peer e] knownPeers :: forall m . (HasPeer e, MonadIO m) => l -> m [Peer e]
addPeers :: forall m . (HasPeer e, MonadIO m) => l -> [Peer e] -> m () addPeers :: forall m . (HasPeer e, MonadIO m) => l -> [Peer e] -> m ()
delPeers :: forall m . (HasPeer e, MonadIO m) => l -> [Peer e] -> m () delPeers :: forall m . (HasPeer e, MonadIO m) => l -> [Peer e] -> m ()
bestPeers :: forall m . (HasPeer e, MonadIO m) => l -> m [Peer e]
addExcluded :: forall m . (HasPeer e, MonadIO m) => l -> [Peer e] -> m ()
data AnyPeerLocator e = forall a . PeerLocator e a => AnyPeerLocator a data AnyPeerLocator e = forall a . PeerLocator e a => AnyPeerLocator a
@ -15,5 +19,10 @@ instance HasPeer e => PeerLocator e (AnyPeerLocator e) where
knownPeers (AnyPeerLocator l) = knownPeers l knownPeers (AnyPeerLocator l) = knownPeers l
addPeers (AnyPeerLocator l) = addPeers l addPeers (AnyPeerLocator l) = addPeers l
delPeers (AnyPeerLocator l) = delPeers l delPeers (AnyPeerLocator l) = delPeers l
addExcluded (AnyPeerLocator l) = addExcluded l
-- FIXME: a better algorithm of choice
bestPeers (AnyPeerLocator l) = liftIO $ knownPeers l >>= shuffleM
class Monad m => HasPeerLocator e m where
getPeerLocator :: m (AnyPeerLocator e)

View File

@ -1,4 +1,8 @@
module HBS2.Net.PeerLocator.Static where module HBS2.Net.PeerLocator.Static
( StaticPeerLocator
, newStaticPeerLocator
, PeerLocator()
) where
import HBS2.Prelude import HBS2.Prelude
import HBS2.Net.Proto import HBS2.Net.Proto
@ -8,27 +12,36 @@ import Control.Concurrent.STM
import Data.Set (Set) import Data.Set (Set)
import Data.Set qualified as Set import Data.Set qualified as Set
import Prettyprinter
newtype StaticPeerLocator e = data StaticPeerLocator e =
StaticPeerLocator (TVar (Set (Peer e))) StaticPeerLocator
{ include :: TVar (Set (Peer e))
, exclude :: TVar (Set (Peer e))
}
newStaticPeerLocator :: (Ord (Peer p), HasPeer p, MonadIO m) => [Peer p] -> m (StaticPeerLocator p) newStaticPeerLocator :: (Ord (Peer p), HasPeer p, MonadIO m) => [Peer p] -> m (StaticPeerLocator p)
newStaticPeerLocator seeds = do newStaticPeerLocator seeds = do
tv <- liftIO $ newTVarIO (Set.fromList seeds) tv <- liftIO $ newTVarIO (Set.fromList seeds)
pure $ StaticPeerLocator tv tv2 <- liftIO $ newTVarIO mempty
pure $ StaticPeerLocator tv tv2
instance (Ord (Peer e), Pretty (Peer e)) => PeerLocator e (StaticPeerLocator e) where instance (Ord (Peer e), Pretty (Peer e)) => PeerLocator e (StaticPeerLocator e) where
knownPeers (StaticPeerLocator peers) = do knownPeers (StaticPeerLocator peers e) = do
ps <- liftIO $ readTVarIO peers ps <- liftIO $ readTVarIO peers
pure $ Set.toList ps excl <- liftIO $ readTVarIO e
pure $ Set.toList (ps `Set.difference` excl)
addPeers (StaticPeerLocator peers) new = do addPeers (StaticPeerLocator peers te) new = do
liftIO $ atomically $ modifyTVar' peers (<> Set.fromList new) excl <- liftIO $ readTVarIO te
liftIO $ atomically $ modifyTVar' peers ((`Set.difference` excl) . (<> Set.fromList new))
delPeers (StaticPeerLocator peers) del = do delPeers (StaticPeerLocator peers _) del = do
liftIO $ atomically $ modifyTVar' peers (`Set.difference` Set.fromList del) liftIO $ atomically $ modifyTVar' peers (`Set.difference` Set.fromList del)
addExcluded p excl = do
liftIO $ atomically $ modifyTVar' (exclude p) (<> Set.fromList excl)
bestPeers = knownPeers

View File

@ -15,6 +15,7 @@ import HBS2.Net.Proto.BlockChunks
import HBS2.Net.Proto.BlockInfo import HBS2.Net.Proto.BlockInfo
import HBS2.Net.Proto.Peer import HBS2.Net.Proto.Peer
import HBS2.Net.Proto.PeerAnnounce import HBS2.Net.Proto.PeerAnnounce
import HBS2.Net.Proto.PeerExchange
import HBS2.Defaults import HBS2.Defaults
import Data.Functor import Data.Functor
@ -65,6 +66,12 @@ instance HasProtocol UDP (PeerAnnounce UDP) where
decode = either (const Nothing) Just . deserialiseOrFail decode = either (const Nothing) Just . deserialiseOrFail
encode = serialise encode = serialise
instance HasProtocol UDP (PeerExchange UDP) where
type instance ProtocolId (PeerExchange UDP) = 6
type instance Encoded UDP = ByteString
decode = either (const Nothing) Just . deserialiseOrFail
encode = serialise
instance Expires (SessionKey UDP (BlockInfo UDP)) where instance Expires (SessionKey UDP (BlockInfo UDP)) where
expiresIn _ = Just defCookieTimeoutSec expiresIn _ = Just defCookieTimeoutSec
@ -94,6 +101,12 @@ instance MonadIO m => HasNonces (PeerHandshake UDP) m where
n <- liftIO ( Crypto.newNonce <&> Crypto.encode ) n <- liftIO ( Crypto.newNonce <&> Crypto.encode )
pure $ BS.take 32 n pure $ BS.take 32 n
instance MonadIO m => HasNonces (PeerExchange UDP) m where
type instance Nonce (PeerExchange UDP) = BS.ByteString
newNonce = do
n <- liftIO ( Crypto.newNonce <&> Crypto.encode )
pure $ BS.take 32 n
instance MonadIO m => HasNonces () m where instance MonadIO m => HasNonces () m where
type instance Nonce () = BS.ByteString type instance Nonce () = BS.ByteString
newNonce = do newNonce = do

View File

@ -10,6 +10,8 @@ import HBS2.Clock
import HBS2.Net.Proto.Sessions import HBS2.Net.Proto.Sessions
import HBS2.Prelude.Plated import HBS2.Prelude.Plated
import HBS2.System.Logger.Simple
import Data.Maybe import Data.Maybe
import Codec.Serialise() import Codec.Serialise()
import Data.ByteString qualified as BS import Data.ByteString qualified as BS
@ -31,7 +33,7 @@ makeLenses 'PeerData
data PeerHandshake e = data PeerHandshake e =
PeerPing PingNonce PeerPing PingNonce
| PeerPong (Signature e) (PeerData e) | PeerPong PingNonce (Signature e) (PeerData e)
deriving stock (Generic) deriving stock (Generic)
newtype KnownPeer e = KnownPeer (PeerData e) newtype KnownPeer e = KnownPeer (PeerData e)
@ -41,10 +43,10 @@ newtype instance SessionKey e (KnownPeer e) =
KnownPeerKey (Peer e) KnownPeerKey (Peer e)
deriving stock (Generic,Typeable) deriving stock (Generic,Typeable)
type instance SessionData e (KnownPeer e) = KnownPeer e type instance SessionData e (KnownPeer e) = PeerData e
newtype instance SessionKey e (PeerHandshake e) = newtype instance SessionKey e (PeerHandshake e) =
PeerHandshakeKey (Peer e) PeerHandshakeKey (PingNonce, Peer e)
deriving stock (Generic, Typeable) deriving stock (Generic, Typeable)
type instance SessionData e (PeerHandshake e) = PingNonce type instance SessionData e (PeerHandshake e) = PingNonce
@ -61,7 +63,7 @@ sendPing :: forall e m . ( MonadIO m
sendPing pip = do sendPing pip = do
nonce <- newNonce @(PeerHandshake e) nonce <- newNonce @(PeerHandshake e)
update nonce (PeerHandshakeKey pip) id update nonce (PeerHandshakeKey (nonce,pip)) id
request pip (PeerPing @e nonce) request pip (PeerPing @e nonce)
peerHandShakeProto :: forall e m . ( MonadIO m peerHandShakeProto :: forall e m . ( MonadIO m
@ -93,7 +95,7 @@ peerHandShakeProto =
own <- peerNonce @e own <- peerNonce @e
-- TODO: отправить обратно вместе с публичным ключом -- TODO: отправить обратно вместе с публичным ключом
response (PeerPong @e sign (PeerData (view peerSignPk creds) own)) response (PeerPong @e nonce sign (PeerData (view peerSignPk creds) own))
-- TODO: да и пингануть того самим -- TODO: да и пингануть того самим
@ -102,10 +104,10 @@ peerHandShakeProto =
unless se $ do unless se $ do
sendPing pip sendPing pip
PeerPong sign d -> do PeerPong nonce0 sign d -> do
pip <- thatPeer proto pip <- thatPeer proto
se' <- find @e (PeerHandshakeKey pip) id se' <- find @e (PeerHandshakeKey (nonce0,pip)) id
maybe1 se' (pure ()) $ \nonce -> do maybe1 se' (pure ()) $ \nonce -> do
@ -113,11 +115,13 @@ peerHandShakeProto =
let signed = verifySign @e pk sign nonce let signed = verifySign @e pk sign nonce
expire (PeerHandshakeKey pip) when signed $ do
expire (PeerHandshakeKey (nonce0,pip))
-- FIXME: check if peer is blacklisted -- FIXME: check if peer is blacklisted
-- right here -- right here
update (KnownPeer d) (KnownPeerKey pip) id update d (KnownPeerKey pip) id
emit AnyKnownPeerEventKey (KnownPeerEvent pip d) emit AnyKnownPeerEventKey (KnownPeerEvent pip d)
emit (ConcretePeerKey pip) (ConcretePeerData pip d) emit (ConcretePeerKey pip) (ConcretePeerData pip d)

View File

@ -0,0 +1,137 @@
{-# Language UndecidableInstances #-}
module HBS2.Net.Proto.PeerExchange where
import HBS2.Prelude.Plated
import HBS2.Net.Proto
import HBS2.Net.Proto.Peer
import HBS2.Net.PeerLocator
import HBS2.Net.Proto.Sessions
import HBS2.Events
import HBS2.Clock
import HBS2.Defaults
import Data.ByteString qualified as BS
import Data.Traversable
import Data.Functor
import Data.Maybe
import Codec.Serialise
import Data.Hashable
import Type.Reflection
import HBS2.System.Logger.Simple
import Prettyprinter
data PeerExchange e =
PeerExchangeGet (Nonce (PeerExchange e))
| PeerExchangePeers (Nonce (PeerExchange e)) [PeerAddr e]
deriving stock (Generic, Typeable)
data PeerExchangePeersEv e
sendPeerExchangeGet :: forall e m . ( MonadIO m
, HasNonces (PeerExchange e) m
, Request e (PeerExchange e) m
, Sessions e (PeerExchange e) m
)
=> Peer e -> m ()
sendPeerExchangeGet pip = do
nonce <- newNonce @(PeerExchange e)
update nonce (PeerExchangeKey @e nonce) id
request pip (PeerExchangeGet @e nonce)
peerExchangeProto :: forall e m . ( MonadIO m
, Response e (PeerExchange e) m
, HasPeerLocator e m
, HasDeferred e (PeerExchange e) m
, HasNonces (PeerExchange e) m
, IsPeerAddr e m
, Sessions e (KnownPeer e) m
, Sessions e (PeerExchange e) m
, EventEmitter e (PeerExchangePeersEv e) m
, Eq (Nonce (PeerExchange e))
, Pretty (Peer e)
)
=> PeerExchange e -> m ()
peerExchangeProto =
\case
PeerExchangeGet n -> deferred proto do
-- TODO: sort peers by their usefulness
that <- thatPeer proto
debug $ "PeerExchangeGet" <+> "from" <+> pretty that
pl <- getPeerLocator @e
pips <- knownPeers @e pl
pa' <- forM pips $ \p -> do
auth <- find (KnownPeerKey p) id <&> isJust
if auth then do
a <- toPeerAddr p
pure [a]
else
pure mempty
let pa = take defPexMaxPeers $ mconcat pa'
response (PeerExchangePeers @e n pa)
PeerExchangePeers nonce pips -> do
pip <- thatPeer proto
ok <- find (PeerExchangeKey @e nonce) id <&> isJust
when ok do
sa <- mapM (fromPeerAddr @e) pips
debug $ "got pex" <+> "from" <+> pretty pip <+> pretty sa
expire @e (PeerExchangeKey nonce)
emit @e PeerExchangePeersKey (PeerExchangePeersData sa)
where
proto = Proxy @(PeerExchange e)
newtype instance SessionKey e (PeerExchange e) =
PeerExchangeKey (Nonce (PeerExchange e))
deriving stock (Generic, Typeable)
type instance SessionData e (PeerExchange e) = Nonce (PeerExchange e)
data instance EventKey e (PeerExchangePeersEv e) =
PeerExchangePeersKey
deriving stock (Typeable, Eq,Generic)
deriving instance Eq (Nonce (PeerExchange e)) => Eq (SessionKey e (PeerExchange e))
instance Hashable (Nonce (PeerExchange e)) => Hashable (SessionKey e (PeerExchange e))
instance Expires (SessionKey e (PeerExchange e)) where
expiresIn _ = Just 10
instance Typeable (PeerExchangePeersEv e)
=> Hashable (EventKey e (PeerExchangePeersEv e)) where
hashWithSalt salt _ = hashWithSalt salt (someTypeRep p)
where
p = Proxy @(PeerExchangePeersEv e)
instance EventType ( Event e ( PeerExchangePeersEv e) ) where
isPersistent = True
instance Expires (EventKey e (PeerExchangePeersEv e)) where
expiresIn _ = Nothing
newtype instance Event e (PeerExchangePeersEv e) =
PeerExchangePeersData [Peer e]
deriving stock (Typeable)
instance ( Serialise (PeerAddr e)
, Serialise (Nonce (PeerExchange e)))
=> Serialise (PeerExchange e)

View File

@ -22,15 +22,16 @@ import HBS2.System.Logger.Simple
import PeerInfo import PeerInfo
import Numeric ( showGFloat )
import Control.Concurrent.Async import Control.Concurrent.Async
import Control.Concurrent.STM import Control.Concurrent.STM
import Control.Monad.Reader import Control.Monad.Reader
import Control.Monad.Trans.Maybe import Control.Monad.Trans.Maybe
import Control.Concurrent.STM.TSem as Sem
import Data.ByteString.Lazy (ByteString) import Data.ByteString.Lazy (ByteString)
import Data.Cache (Cache) import Data.Cache (Cache)
import Data.Cache qualified as Cache import Data.Cache qualified as Cache
import Data.Foldable hiding (find) import Data.Foldable hiding (find)
import Data.Hashable
import Data.HashMap.Strict (HashMap) import Data.HashMap.Strict (HashMap)
import Data.HashMap.Strict qualified as HashMap import Data.HashMap.Strict qualified as HashMap
import Data.IntMap (IntMap) import Data.IntMap (IntMap)
@ -40,8 +41,10 @@ import Data.Maybe
import Data.Set qualified as Set import Data.Set qualified as Set
import Data.Set (Set) import Data.Set (Set)
import Lens.Micro.Platform import Lens.Micro.Platform
import Numeric ( showGFloat )
import Prettyprinter import Prettyprinter
import System.Random.Shuffle import System.Random.Shuffle
import Type.Reflection
calcBursts :: forall a . Integral a => a -> [a] -> [(a,a)] calcBursts :: forall a . Integral a => a -> [a] -> [(a,a)]
@ -648,12 +651,11 @@ blockDownloadLoop env0 = do
withDownload env (addBlockInfo p1 hx s) withDownload env (addBlockInfo p1 hx s)
pips <- knownPeers @e pl pips <- knownPeers @e pl
for_ pips $ \pip -> request pip (GetBlockSize @e h) for_ pips $ \pip -> do
auth <- find (KnownPeerKey pip) id <&> isJust
p <- knownPeers @e pl >>= liftIO . shuffleM when auth $ request pip (GetBlockSize @e h) -- FIXME: request only known peers
-- move this to peer locator
-- debug $ "known peers" <+> pretty p
-- debug $ "peers/blocks" <+> pretty peers
p0 <- headMay <$> liftIO (shuffleM peers) -- FIXME: random choice to work faster p0 <- headMay <$> liftIO (shuffleM peers) -- FIXME: random choice to work faster
@ -687,15 +689,30 @@ tossPostponed penv = do
env <- ask env <- ask
waitQ <- liftIO newTQueueIO waitQ <- liftIO $ newTBQueueIO 1
busy <- liftIO $ newTVarIO False
cache <- asks (view blockPostponed) cache <- asks (view blockPostponed)
lift $ subscribe @e AnyKnownPeerEventKey $ \(KnownPeerEvent{}) -> do lift $ subscribe @e AnyKnownPeerEventKey $ \(KnownPeerEvent{}) -> do
liftIO $ atomically $ writeTQueue waitQ () cant <- liftIO $ readTVarIO busy
unless cant $ do
debug "AnyKnownPeerEventKey"
mt <- liftIO $ atomically $ isEmptyTBQueue waitQ
when mt do
liftIO $ atomically $ writeTBQueue waitQ ()
forever do forever do
r <- liftIO $ race ( pause @'Seconds 20 ) ( atomically $ readTQueue waitQ ) r <- liftIO $ race ( pause @'Seconds 20 ) ( atomically $ readTBQueue waitQ )
void $ liftIO $ atomically $ flushTBQueue waitQ
liftIO $ atomically $ writeTVar busy True
void $ liftIO $ async $ do
pause @'Seconds 5
atomically $ writeTVar busy False
let allBack = either (const False) (const True) r let allBack = either (const False) (const True) r

View File

@ -5,19 +5,26 @@ module PeerInfo where
import HBS2.Actors.Peer import HBS2.Actors.Peer
import HBS2.Clock import HBS2.Clock
import HBS2.Defaults import HBS2.Defaults
import HBS2.Events
import HBS2.Net.Messaging.UDP import HBS2.Net.Messaging.UDP
import HBS2.Net.PeerLocator import HBS2.Net.PeerLocator
import HBS2.Net.Proto.Peer import HBS2.Net.Proto.Peer
import HBS2.Net.Proto.PeerExchange
import HBS2.Net.Proto.Sessions import HBS2.Net.Proto.Sessions
import HBS2.Net.Proto.Types import HBS2.Net.Proto.Types
import HBS2.Prelude.Plated import HBS2.Prelude.Plated
import HBS2.System.Logger.Simple import HBS2.System.Logger.Simple
import Data.Foldable import Data.Maybe
import Data.Set qualified as Set
import Data.List qualified as List
import Data.Foldable hiding (find)
import Lens.Micro.Platform import Lens.Micro.Platform
import Control.Concurrent.STM.TVar import Control.Concurrent.STM.TVar
import Control.Concurrent.STM import Control.Concurrent.STM
import Control.Monad import Control.Monad
import Control.Concurrent.Async
import System.Random.Shuffle
import Prettyprinter import Prettyprinter
data PeerInfo e = data PeerInfo e =
@ -59,6 +66,35 @@ instance Expires (SessionKey UDP (PeerInfo UDP)) where
expiresIn = const (Just 600) expiresIn = const (Just 600)
pexLoop :: forall e m . ( HasPeerLocator e m
, HasPeer e
, Sessions e (KnownPeer e) m
, HasNonces (PeerExchange e) m
, Request e (PeerExchange e) m
, Sessions e (PeerExchange e) m
, MonadIO m
) => m ()
pexLoop = do
pause @'Seconds 5
pl <- getPeerLocator @e
forever do
pips <- knownPeers @e pl
peers' <- forM pips $ \p -> do
au <- find @e (KnownPeerKey p) id
pure $ maybe1 au mempty (const [p])
peers <- liftIO (shuffleM (mconcat peers')) <&> take 10 -- FIXME: defaults
for_ peers sendPeerExchangeGet
pause @'Seconds 60 -- FIXME: defaults
peerPingLoop :: forall e m . ( HasPeerLocator e m peerPingLoop :: forall e m . ( HasPeerLocator e m
, HasPeer e , HasPeer e
, HasNonces (PeerHandshake e) m , HasNonces (PeerHandshake e) m
@ -67,23 +103,41 @@ peerPingLoop :: forall e m . ( HasPeerLocator e m
, Sessions e (PeerHandshake e) m , Sessions e (PeerHandshake e) m
, Sessions e (PeerInfo e) m , Sessions e (PeerInfo e) m
, Sessions e (KnownPeer e) m , Sessions e (KnownPeer e) m
, EventListener e (PeerExchangePeersEv e) m
, Pretty (Peer e) , Pretty (Peer e)
, MonadIO m , MonadIO m
) )
=> m () => m ()
peerPingLoop = forever do peerPingLoop = do
pause @'Seconds 120 -- FIXME: defaults
wake <- liftIO newTQueueIO
subscribe @e PeerExchangePeersKey $ \(PeerExchangePeersData sas) -> do
liftIO $ atomically $ writeTQueue wake sas
forever do
-- FIXME: defaults
r <- liftIO $ race (pause @'Seconds 60)
(atomically $ readTQueue wake)
sas' <- liftIO $ atomically $ flushTQueue wake <&> mconcat
let sas = case r of
Left{} -> sas'
Right sa -> sa <> sas'
debug "peerPingLoop" debug "peerPingLoop"
pl <- getPeerLocator @e pl <- getPeerLocator @e
pips <- knownPeers @e pl pips <- knownPeers @e pl <&> (<> sas) <&> List.nub
for_ pips $ \p -> do for_ pips $ \p -> do
npi <- newPeerInfo npi <- newPeerInfo
pfails <- fetch True npi (PeerInfoKey p) (view peerPingFailed) pfails <- fetch True npi (PeerInfoKey p) (view peerPingFailed)
liftIO $ atomically $ modifyTVar pfails succ liftIO $ atomically $ modifyTVar pfails succ
sendPing @e p sendPing @e p
pause @'Seconds 2 -- NOTE: it's okay? pause @'Seconds 1 -- NOTE: it's okay?
fnum <- liftIO $ readTVarIO pfails fnum <- liftIO $ readTVarIO pfails

View File

@ -18,6 +18,7 @@ import HBS2.Net.Proto
import HBS2.Net.Proto.Definition import HBS2.Net.Proto.Definition
import HBS2.Net.Proto.Peer import HBS2.Net.Proto.Peer
import HBS2.Net.Proto.PeerAnnounce import HBS2.Net.Proto.PeerAnnounce
import HBS2.Net.Proto.PeerExchange
import HBS2.Net.Proto.Sessions import HBS2.Net.Proto.Sessions
import HBS2.OrDie import HBS2.OrDie
import HBS2.Prelude.Plated import HBS2.Prelude.Plated
@ -294,7 +295,22 @@ runPeer opts = Exception.handle myException $ do
unless known $ sendPing pip unless known $ sendPing pip
subscribe @UDP AnyKnownPeerEventKey $ \(KnownPeerEvent p d) -> do subscribe @UDP AnyKnownPeerEventKey $ \(KnownPeerEvent p d) -> do
unless (pnonce == view peerOwnNonce d) $ do
-- FIXME: check if we've got a reference to ourselves
if pnonce == view peerOwnNonce d then do
delPeers pl [p]
addExcluded pl [p]
expire (KnownPeerKey p)
else do
prev <- find (KnownPeerKey p) (view peerOwnNonce)
case prev of
Just nonce0 | nonce0 /= view peerOwnNonce d -> do
debug "old peer, new address. ignoring"
_ -> do
addPeers pl [p] addPeers pl [p]
npi <- newPeerInfo npi <- newPeerInfo
@ -309,16 +325,22 @@ runPeer opts = Exception.handle myException $ do
debug "sending first peer announce" debug "sending first peer announce"
request localMulticast (PeerAnnounce @UDP pnonce) request localMulticast (PeerAnnounce @UDP pnonce)
void $ liftIO $ async $ withPeerM env $ forever $ do let wo = fmap L.singleton
workers <- do
wo $ liftIO $ async $ withPeerM env $ forever $ do
pause defPeerAnnounceTime -- FIXME: setting! pause defPeerAnnounceTime -- FIXME: setting!
debug "sending local peer announce" debug "sending local peer announce"
request localMulticast (PeerAnnounce @UDP pnonce) request localMulticast (PeerAnnounce @UDP pnonce)
as <- liftIO $ async $ withPeerM env (peerPingLoop @UDP) wo $ liftIO $ async $ withPeerM env (peerPingLoop @UDP)
as <- liftIO $ async $ withPeerM env (blockDownloadLoop denv) wo $ liftIO $ async $ withPeerM env (pexLoop @UDP)
rpc <- liftIO $ async $ withPeerM env $ forever $ do wo $ liftIO $ async $ withPeerM env (blockDownloadLoop denv)
wo $ liftIO $ async $ withPeerM env $ forever $ do
cmd <- liftIO $ atomically $ readTQueue rpcQ cmd <- liftIO $ atomically $ readTQueue rpcQ
case cmd of case cmd of
POKE -> debug "on poke: alive and kicking!" POKE -> debug "on poke: alive and kicking!"
@ -370,15 +392,16 @@ runPeer opts = Exception.handle myException $ do
_ -> pure () _ -> pure ()
me <- liftIO $ async $ withPeerM env $ do wo $ liftIO $ async $ withPeerM env $ do
runProto @UDP runProto @UDP
[ makeResponse (blockSizeProto blk dontHandle) [ makeResponse (blockSizeProto blk dontHandle)
, makeResponse (blockChunksProto adapter) , makeResponse (blockChunksProto adapter)
, makeResponse blockAnnounceProto , makeResponse blockAnnounceProto
, makeResponse (withCredentials pc . peerHandShakeProto) , makeResponse (withCredentials pc . peerHandShakeProto)
, makeResponse peerExchangeProto
] ]
void $ liftIO $ waitAnyCatchCancel [me,as] void $ liftIO $ waitAnyCatchCancel workers
let pokeAction _ = do let pokeAction _ = do
liftIO $ atomically $ writeTQueue rpcQ POKE liftIO $ atomically $ writeTQueue rpcQ POKE

View File

@ -112,15 +112,16 @@
"saltine": "saltine" "saltine": "saltine"
}, },
"locked": { "locked": {
"lastModified": 1675599025, "lastModified": 1675665762,
"narHash": "sha256-ZVOkBwFMpUHyhsdBg8ubv/h43N7phoLqR1lYbgZEeH0=", "narHash": "sha256-zVfyDqVyPgMXMsj/od1xmOCQz5gkHzi3pTyf83qaqF0=",
"owner": "voidlizard", "owner": "voidlizard",
"repo": "hbs2", "repo": "hbs2",
"rev": "4ab83f0517c0ab465634a15607d3f0dddeaba3e7", "rev": "85d34209e10016fc243e37e221dca8217af3f7bb",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "voidlizard", "owner": "voidlizard",
"ref": "wip",
"repo": "hbs2", "repo": "hbs2",
"type": "github" "type": "github"
} }
@ -165,11 +166,11 @@
}, },
"nixpkgs_2": { "nixpkgs_2": {
"locked": { "locked": {
"lastModified": 1675512093, "lastModified": 1675600654,
"narHash": "sha256-u1CY4feK14B57E6T+0Bhkuoj8dpBxCPrWO+SP87UVP8=", "narHash": "sha256-ipsDTkzRq1CAl2g5tYd7ugjVMSKF6KLh9F+5Kso0lT0=",
"owner": "nixos", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "8e8240194eda25b61449f29bb5131e02b28a5486", "rev": "cff83d5032a21aad4f69bf284e95b5f564f4a54e",
"type": "github" "type": "github"
}, },
"original": { "original": {

View File

@ -5,7 +5,7 @@
inputs = { inputs = {
extra-container.url = "github:erikarvstedt/extra-container"; extra-container.url = "github:erikarvstedt/extra-container";
nixpkgs.url = "github:nixos/nixpkgs/nixos-22.11"; nixpkgs.url = "github:nixos/nixpkgs/nixos-22.11";
hbs2.url = "github:voidlizard/hbs2"; hbs2.url = "github:voidlizard/hbs2/wip";
hbs2.inputs.nixpkgs.follows = "nixpkgs"; hbs2.inputs.nixpkgs.follows = "nixpkgs";
}; };