Squashed commit of the following:

commit cc3d5a357eee5c0e01f530808f8122f83b5103a2
Author: Dmitry Zuikov <dzuikov@gmail.com>
Date:   Tue Jul 4 15:29:09 2023 +0300

    fixme

commit abae50a7895fdfc70e3a9204288a1af1a00f1c77
Author: Sergey Ivanov <ivanovs-4@yandex.ru>
Date:   Mon Jul 3 20:05:08 2023 +0400

    encryption debug -> traces

commit e8cab85da295ad81896726bf41f118bc2eb6e79e
Author: Sergey Ivanov <ivanovs-4@yandex.ru>
Date:   Mon Jul 3 00:21:34 2023 +0400

    bus encryption fixed

commit cbb3e796b0d919d6d425a5d8c669cfce2ed02182
Merge: a740db8 55cdf97
Author: Sergey Ivanov <ivanovs-4@yandex.ru>
Date:   Sat Jul 1 23:17:52 2023 +0400

    Merge branch 'master' into iv/bus-crypt

commit a740db82351dcbc40604413df9af210212e1cbc1
Author: Sergey Ivanov <ivanovs-4@yandex.ru>
Date:   Wed Jun 21 16:08:05 2023 +0400

    drop one traceShowId uasge

commit 82de8d8c675cf21e732dc8db9b64139c7c2407ad
Author: Sergey Ivanov <ivanovs-4@yandex.ru>
Date:   Wed Jun 21 13:33:34 2023 +0400

    Edit README.md fix typo

commit ec4dc7733215f19009da9334b82fd568e16eb143
Author: Sergey Ivanov <ivanovs-4@yandex.ru>
Date:   Wed Jun 21 13:32:54 2023 +0400

    Rename deserialiseTrace -> deserialiseCustom

commit 863394449798d8c534c58dc2d69add3e5a807e56
Author: Sergey Ivanov <ivanovs-4@yandex.ru>
Date:   Thu Jun 15 05:37:52 2023 +0400

    PR bus-crypt

commit 78dd65959906944935f99371ee973fc6c2c659b9
Author: Sergey Ivanov <ivanovs-4@yandex.ru>
Date:   Thu Jun 15 05:33:13 2023 +0400

    Drop unused lines

commit 9736077a96061c62e928b657e7c7558f9172636c
Author: Sergey Ivanov <ivanovs-4@yandex.ru>
Date:   Thu Jun 15 05:24:33 2023 +0400

    Encryption works

commit c69aede965242281b525c088e1f27708a6741651
Author: Sergey Ivanov <ivanovs-4@yandex.ru>
Date:   Wed Jun 14 20:52:48 2023 +0400

    wip

commit 88fc2aac5b4fc1d452e74bf99213a57dad09b1c3
Author: Sergey Ivanov <ivanovs-4@yandex.ru>
Date:   Wed Jun 14 15:52:32 2023 +0400

    Test roundtrip combineNonceBS/extractNonce

commit 2d2f6945f4c917347c8f30e195764e2b0837fb25
Author: Sergey Ivanov <ivanovs-4@yandex.ru>
Date:   Tue Jun 13 14:08:56 2023 +0400

    wip

commit 31466fd036d74d8c4b769c7ffb0fa9dfda03eb26
Author: Sergey Ivanov <ivanovs-4@yandex.ru>
Date:   Tue Jun 13 10:03:15 2023 +0400

    trace locked requests

commit 85eb68a6747fb307c07fb0fcf681118250b37fab
Author: Sergey Ivanov <ivanovs-4@yandex.ru>
Date:   Mon Jun 12 20:02:32 2023 +0400

    added Show instances

commit 74383bd7db9dd6838b4d026a3997c5c5b4799fa4
Author: Sergey Ivanov <ivanovs-4@yandex.ru>
Date:   Mon Jun 12 09:56:14 2023 +0400

    DEBUG

commit d62b30dbcdae6584f78cc2b6d8a801ff46cfdfa8
Author: Sergey Ivanov <ivanovs-4@yandex.ru>
Date:   Sun Jun 11 18:28:49 2023 +0400

    wip

commit 78b3f24ae1c4b632756f3a28873f4d03bbaa1330
Author: Sergey Ivanov <ivanovs-4@yandex.ru>
Date:   Sun Jun 11 08:45:58 2023 +0400

    trace encrypted receiveing

commit 93e2b9f7a7c2b579e5e46b6329a6509b8e5119de
Author: Sergey Ivanov <ivanovs-4@yandex.ru>
Date:   Sat Jun 10 16:57:59 2023 +0400

    wip

commit 4686274d0fb401b722fca10ec0c2dbee00a4c68a
Author: Sergey Ivanov <ivanovs-4@yandex.ru>
Date:   Fri Jun 9 23:38:56 2023 +0400

    Use PeerDataExt

commit 0c24c2702b47db262fa086efb6cff108b8ce28e8
Author: Sergey Ivanov <ivanovs-4@yandex.ru>
Date:   Thu Jun 8 03:04:39 2023 +0400

    Encrypted Handshake

commit 789536f20bc4f95320d2a4779a4a5b06d52b98f2
Author: Sergey Ivanov <ivanovs-4@yandex.ru>
Date:   Wed Jun 7 00:56:34 2023 +0400

    Fixed fillPeerMeta timeout algorithm

commit d52ac19777ba1c47f1123c5452309da4391ca21f
Author: Sergey Ivanov <ivanovs-4@yandex.ru>
Date:   Fri Jun 2 01:50:17 2023 +0400

    wip

commit ea6833f812f9f137880229547622a3cf1ae55222
Author: Sergey Ivanov <ivanovs-4@yandex.ru>
Date:   Tue May 30 22:14:25 2023 +0400

    wip

commit 4ffdfc60ccc5c053da2d81ea16847f25f14c6220
Author: Sergey Ivanov <ivanovs-4@yandex.ru>
Date:   Sat May 27 21:42:01 2023 +0400

    Symmetrical encryption in ProxyMessaging

commit 7cd1214e9e00901fcd3d9e2966348dd800ab4119
Author: Sergey Ivanov <ivanovs-4@yandex.ru>
Date:   Fri May 26 15:03:43 2023 +0400

    pex monitor
This commit is contained in:
Dmitry Zuikov 2023-07-04 15:29:54 +03:00
parent 0af3056664
commit 01982d37c1
26 changed files with 758 additions and 197 deletions

View File

@ -258,7 +258,7 @@ keeyring "/path/to/new.key"
5. Add git remote and push 5. Add git remote and push
``` ```
git add mynerepo hbs2://eq5ZFnB9HQTMTeYasYC3pSZLedcP7Zp2eDkJNdehVVk git remote add mynerepo hbs2://eq5ZFnB9HQTMTeYasYC3pSZLedcP7Zp2eDkJNdehVVk
git push mynerepo git push mynerepo
``` ```

View File

@ -1295,3 +1295,11 @@ PR: implement-http-block-download-worker
PR: tcp-pex PR: tcp-pex
branch: iv/tcp-pex_3 branch: iv/tcp-pex_3
commit: f1de7c58d5dc36dec5c318a3297733791de9a3d8 commit: f1de7c58d5dc36dec5c318a3297733791de9a3d8
## 2023-06-15
PR: bus-crypt
branch: iv/bus-crypt
Шифрование протокола общения нод.
Обмен асимметричными публичными ключами выполняется на стадии хэндшейка в ping/pong.
Для шифрования данных создаётся симметричный ключ по diffie-hellman.

View File

@ -53,6 +53,7 @@ common shared-properties
, MultiParamTypeClasses , MultiParamTypeClasses
, OverloadedStrings , OverloadedStrings
, QuasiQuotes , QuasiQuotes
, RecordWildCards
, ScopedTypeVariables , ScopedTypeVariables
, StandaloneDeriving , StandaloneDeriving
, TupleSections , TupleSections
@ -69,6 +70,7 @@ library
, HBS2.Actors.Peer , HBS2.Actors.Peer
, HBS2.Base58 , HBS2.Base58
, HBS2.Clock , HBS2.Clock
, HBS2.Crypto
, HBS2.Data.Detect , HBS2.Data.Detect
, HBS2.Data.Types , HBS2.Data.Types
, HBS2.Data.Types.Crypto , HBS2.Data.Types.Crypto
@ -149,9 +151,11 @@ library
, stm , stm
, stm-chans , stm-chans
, streaming , streaming
, string-conversions
, suckless-conf , suckless-conf
, temporary , temporary
, text , text
, time
, transformers , transformers
, uniplate , uniplate
, unordered-containers , unordered-containers
@ -188,17 +192,21 @@ test-suite test
, mtl , mtl
, prettyprinter , prettyprinter
, QuickCheck , QuickCheck
, quickcheck-instances
, random , random
, safe , safe
, serialise , serialise
, stm , stm
, streaming , streaming
, tasty , tasty
, tasty-quickcheck
, tasty-hunit , tasty-hunit
, transformers , transformers
, uniplate , uniplate
, vector , vector
, saltine
, simple-logger , simple-logger
, string-conversions

View File

@ -10,6 +10,7 @@ import HBS2.Clock
import HBS2.Defaults import HBS2.Defaults
import HBS2.Events import HBS2.Events
import HBS2.Hash import HBS2.Hash
import HBS2.Net.Auth.Credentials
import HBS2.Net.Messaging import HBS2.Net.Messaging
import HBS2.Net.PeerLocator import HBS2.Net.PeerLocator
import HBS2.Net.PeerLocator.Static import HBS2.Net.PeerLocator.Static
@ -17,7 +18,9 @@ import HBS2.Net.Proto
import HBS2.Net.Proto.Sessions import HBS2.Net.Proto.Sessions
import HBS2.Prelude.Plated import HBS2.Prelude.Plated
import HBS2.Storage import HBS2.Storage
import HBS2.System.Logger.Simple
import Control.Applicative
import Control.Monad.Trans.Maybe import Control.Monad.Trans.Maybe
import Control.Concurrent.Async import Control.Concurrent.Async
import Control.Monad.Reader import Control.Monad.Reader
@ -36,10 +39,13 @@ import Data.HashMap.Strict qualified as HashMap
import Control.Concurrent.STM.TVar import Control.Concurrent.STM.TVar
import Control.Concurrent.STM import Control.Concurrent.STM
import Data.Hashable (hash) import Data.Hashable (hash)
import Crypto.Saltine.Core.SecretBox qualified as SBox -- Симметричное шифрование с nonce без подписи
import Crypto.Saltine.Core.Box qualified as Encrypt -- Асимметричное шифрование без подписи
import Codec.Serialise (serialise, deserialiseOrFail) import Codec.Serialise (serialise, deserialiseOrFail)
import Prettyprinter hiding (pipe) import Prettyprinter hiding (pipe)
-- import Debug.Trace
data AnyStorage = forall zu . ( Block ByteString ~ ByteString data AnyStorage = forall zu . ( Block ByteString ~ ByteString
@ -148,6 +154,7 @@ data PeerEnv e =
, _envSweepers :: TVar (HashMap SKey [PeerM e IO ()]) , _envSweepers :: TVar (HashMap SKey [PeerM e IO ()])
, _envReqMsgLimit :: Cache (Peer e, Integer, Encoded e) () , _envReqMsgLimit :: Cache (Peer e, Integer, Encoded e) ()
, _envReqProtoLimit :: Cache (Peer e, Integer) () , _envReqProtoLimit :: Cache (Peer e, Integer) ()
, _envAsymmetricKeyPair :: AsymmKeypair (Encryption e)
} }
newtype PeerM e m a = PeerM { fromPeerM :: ReaderT (PeerEnv e) m a } newtype PeerM e m a = PeerM { fromPeerM :: ReaderT (PeerEnv e) m a }
@ -278,14 +285,16 @@ instance (MonadIO m, HasProtocol e p, Hashable (Encoded e))
pure (not here) pure (not here)
instance ( MonadIO m instance ( MonadIO m
, HasProtocol e p , HasProtocol e msg
, HasFabriq e m -- (PeerM e m) , HasFabriq e m -- (PeerM e m)
, HasOwnPeer e m , HasOwnPeer e m
, PeerMessaging e , PeerMessaging e
, HasTimeLimits e p m , HasTimeLimits e msg m
) => Request e p m where , Show (Peer e)
request p msg = do , Show msg
let proto = protoId @e @p (Proxy @p) ) => Request e msg m where
request peer_e msg = do
let proto = protoId @e @msg (Proxy @msg)
pipe <- getFabriq @e pipe <- getFabriq @e
me <- ownPeer @e me <- ownPeer @e
@ -294,12 +303,17 @@ instance ( MonadIO m
-- --
-- TODO: where to store the timeout? -- TODO: where to store the timeout?
-- TODO: where the timeout come from? -- TODO: where the timeout come from?
-- withTimeLimit @e @p p msg $ do -- withTimeLimit @e @msg peer_e msg $ do
-- liftIO $ print "request!" -- liftIO $ print "request!"
allowed <- tryLockForPeriod p msg allowed <- tryLockForPeriod peer_e msg
when (not allowed) do
trace $ "REQUEST: not allowed to send" <+> viaShow msg
when allowed do when allowed do
sendTo pipe (To p) (From me) (AnyMessage @(Encoded e) @e proto (encode msg)) sendTo pipe (To peer_e) (From me) (AnyMessage @(Encoded e) @e proto (encode msg))
-- trace $ "REQUEST: after sendTo" <+> viaShow peer_e <+> viaShow msg
instance ( Typeable (EventHandler e p (PeerM e IO)) instance ( Typeable (EventHandler e p (PeerM e IO))
@ -383,6 +397,7 @@ newPeerEnv :: forall e m . ( MonadIO m
, Ord (Peer e) , Ord (Peer e)
, Pretty (Peer e) , Pretty (Peer e)
, HasNonces () m , HasNonces () m
, Asymm (Encryption e)
) )
=> AnyStorage => AnyStorage
-> Fabriq e -> Fabriq e
@ -390,18 +405,20 @@ newPeerEnv :: forall e m . ( MonadIO m
-> m (PeerEnv e) -> m (PeerEnv e)
newPeerEnv s bus p = do newPeerEnv s bus p = do
let _envSelf = p
pl <- AnyPeerLocator <$> newStaticPeerLocator @e mempty _envPeerNonce <- newNonce @()
let _envFab = bus
nonce <- newNonce @() let _envStorage = s
_envPeerLocator <- AnyPeerLocator <$> newStaticPeerLocator @e mempty
PeerEnv p nonce bus s pl <$> newPipeline defProtoPipelineSize _envDeferred <- newPipeline defProtoPipelineSize
<*> liftIO (Cache.newCache (Just defCookieTimeout)) _envSessions <- liftIO (Cache.newCache (Just defCookieTimeout))
<*> liftIO (newTVarIO mempty) _envEvents <- liftIO (newTVarIO mempty)
<*> liftIO (Cache.newCache (Just defCookieTimeout)) _envExpireTimes <- liftIO (Cache.newCache (Just defCookieTimeout))
<*> liftIO (newTVarIO mempty) _envSweepers <- liftIO (newTVarIO mempty)
<*> liftIO (Cache.newCache (Just defRequestLimit)) _envReqMsgLimit <- liftIO (Cache.newCache (Just defRequestLimit))
<*> liftIO (Cache.newCache (Just defRequestLimit)) _envReqProtoLimit <- liftIO (Cache.newCache (Just defRequestLimit))
_envAsymmetricKeyPair <- asymmNewKeypair @(Encryption e)
pure PeerEnv {..}
runPeerM :: forall e m . ( MonadIO m runPeerM :: forall e m . ( MonadIO m
, HasPeer e , HasPeer e

View File

@ -10,6 +10,7 @@ import Control.Monad.IO.Class
import Data.Fixed import Data.Fixed
import Data.Int (Int64) import Data.Int (Int64)
import Data.Proxy import Data.Proxy
import Data.Time
import Prettyprinter import Prettyprinter
import System.Clock import System.Clock
@ -35,6 +36,9 @@ class IsTimeout a where
toTimeSpec :: Timeout a -> TimeSpec toTimeSpec :: Timeout a -> TimeSpec
toTimeSpec x = fromNanoSecs (fromIntegral (toNanoSeconds x)) toTimeSpec x = fromNanoSecs (fromIntegral (toNanoSeconds x))
toNominalDiffTime :: IsTimeout t => Timeout t -> NominalDiffTime
toNominalDiffTime = fromRational . (/ (10^6)) . fromIntegral . toMicroSeconds
class IsTimeout a => MonadPause a m where class IsTimeout a => MonadPause a m where
pause :: Timeout a -> m () pause :: Timeout a -> m ()

View File

@ -0,0 +1,28 @@
module HBS2.Crypto where
import Control.Monad
import Crypto.Saltine.Class as SCl
import Crypto.Saltine.Core.Box qualified as Encrypt
import Crypto.Saltine.Internal.Box qualified as Encrypt
import Data.ByteString (ByteString)
import Data.ByteString qualified as BS
import Data.ByteString.Lazy qualified as LBS
import Data.String.Conversions (cs)
combineNonceBS :: Encrypt.Nonce -> ByteString -> ByteString
combineNonceBS n = (SCl.encode n <>)
extractNonce :: ByteString -> Maybe (Encrypt.Nonce, ByteString)
extractNonce bs = do
let (p,bs') = BS.splitAt Encrypt.box_noncebytes bs
guard (BS.length p == Encrypt.box_noncebytes)
nonce <- SCl.decode p
pure (nonce, bs')
boxAfterNMLazy :: Encrypt.CombinedKey -> Encrypt.Nonce -> LBS.ByteString -> LBS.ByteString
boxAfterNMLazy k n = cs . combineNonceBS n . Encrypt.boxAfterNM k n . cs
boxOpenAfterNMLazy :: Encrypt.CombinedKey -> Encrypt.Nonce -> ByteString -> Maybe LBS.ByteString
boxOpenAfterNMLazy k n = fmap cs . Encrypt.boxOpenAfterNM k n

View File

@ -38,6 +38,15 @@ class Signatures e where
makeSign :: PrivKey 'Sign e -> ByteString -> Signature e makeSign :: PrivKey 'Sign e -> ByteString -> Signature e
verifySign :: PubKey 'Sign e -> Signature e -> ByteString -> Bool verifySign :: PubKey 'Sign e -> Signature e -> ByteString -> Bool
class AsymmPubKey e ~ PubKey 'Encrypt e => Asymm e where
type family AsymmKeypair e :: Type
type family AsymmPrivKey e :: Type
type family AsymmPubKey e :: Type
type family CommonSecret e :: Type
asymmNewKeypair :: MonadIO m => m (AsymmKeypair e)
privKeyFromKeypair :: AsymmKeypair e -> AsymmPrivKey e
pubKeyFromKeypair :: AsymmKeypair e -> AsymmPubKey e
genCommonSecret :: Asymm e => AsymmPrivKey e -> AsymmPubKey e -> CommonSecret e
class HasCredentials s m where class HasCredentials s m where
getCredentials :: m (PeerCredentials s) getCredentials :: m (PeerCredentials s)

View File

@ -42,6 +42,8 @@ instance Serialise (BlockAnnounceInfo e)
data BlockAnnounce e = BlockAnnounce PeerNonce (BlockAnnounceInfo e) data BlockAnnounce e = BlockAnnounce PeerNonce (BlockAnnounceInfo e)
deriving stock (Generic) deriving stock (Generic)
deriving instance (Show (Nonce ())) => Show (BlockAnnounce e)
instance Serialise PeerNonce => Serialise (BlockAnnounce e) instance Serialise PeerNonce => Serialise (BlockAnnounce e)

View File

@ -51,14 +51,14 @@ data BlockChunksI e m =
data BlockChunks e = BlockChunks (Cookie e) (BlockChunksProto e) data BlockChunks e = BlockChunks (Cookie e) (BlockChunksProto e)
deriving stock (Generic) deriving stock (Generic, Show)
data BlockChunksProto e = BlockGetAllChunks (Hash HbSync) ChunkSize data BlockChunksProto e = BlockGetAllChunks (Hash HbSync) ChunkSize
| BlockGetChunks (Hash HbSync) ChunkSize Word32 Word32 | BlockGetChunks (Hash HbSync) ChunkSize Word32 Word32
| BlockNoChunks | BlockNoChunks
| BlockChunk ChunkNum ByteString | BlockChunk ChunkNum ByteString
| BlockLost | BlockLost
deriving stock (Generic) deriving stock (Generic, Show)
instance HasCookie e (BlockChunks e) where instance HasCookie e (BlockChunks e) where

View File

@ -21,12 +21,12 @@ import HBS2.Net.Proto.PeerMeta
import HBS2.Net.Proto.RefLog import HBS2.Net.Proto.RefLog
import HBS2.Prelude import HBS2.Prelude
import Control.Monad
import Data.Functor import Data.Functor
import Data.ByteString.Lazy (ByteString) import Data.ByteString.Lazy (ByteString)
import Data.ByteString qualified as BS import Data.ByteString qualified as BS
import Codec.Serialise (deserialiseOrFail,serialise) import Codec.Serialise (deserialiseOrFail,serialise)
import Crypto.Saltine.Core.Box qualified as Crypto
import Crypto.Saltine.Class qualified as Crypto import Crypto.Saltine.Class qualified as Crypto
import Crypto.Saltine.Core.Sign qualified as Sign import Crypto.Saltine.Core.Sign qualified as Sign
import Crypto.Saltine.Core.Box qualified as Encrypt import Crypto.Saltine.Core.Box qualified as Encrypt
@ -52,10 +52,15 @@ instance Serialise Encrypt.PublicKey
instance Serialise Sign.SecretKey instance Serialise Sign.SecretKey
instance Serialise Encrypt.SecretKey instance Serialise Encrypt.SecretKey
deserialiseCustom :: (Serialise a, MonadPlus m) => ByteString -> m a
deserialiseCustom = either (const mzero) pure . deserialiseOrFail
-- deserialiseCustom = either (\msg -> trace ("deserialiseCustom: " <> show msg) mzero) pure . deserialiseOrFail
-- deserialiseCustom = either (error . show) pure . deserialiseOrFail
instance HasProtocol L4Proto (BlockInfo L4Proto) where instance HasProtocol L4Proto (BlockInfo L4Proto) where
type instance ProtocolId (BlockInfo L4Proto) = 1 type instance ProtocolId (BlockInfo L4Proto) = 1
type instance Encoded L4Proto = ByteString type instance Encoded L4Proto = ByteString
decode = either (const Nothing) Just . deserialiseOrFail decode = deserialiseCustom
encode = serialise encode = serialise
-- FIXME: requestMinPeriod-breaks-fast-block-download -- FIXME: requestMinPeriod-breaks-fast-block-download
@ -65,7 +70,7 @@ instance HasProtocol L4Proto (BlockInfo L4Proto) where
instance HasProtocol L4Proto (BlockChunks L4Proto) where instance HasProtocol L4Proto (BlockChunks L4Proto) where
type instance ProtocolId (BlockChunks L4Proto) = 2 type instance ProtocolId (BlockChunks L4Proto) = 2
type instance Encoded L4Proto = ByteString type instance Encoded L4Proto = ByteString
decode = either (const Nothing) Just . deserialiseOrFail decode = deserialiseCustom
encode = serialise encode = serialise
instance Expires (SessionKey L4Proto (BlockChunks L4Proto)) where instance Expires (SessionKey L4Proto (BlockChunks L4Proto)) where
@ -74,13 +79,13 @@ instance Expires (SessionKey L4Proto (BlockChunks L4Proto)) where
instance HasProtocol L4Proto (BlockAnnounce L4Proto) where instance HasProtocol L4Proto (BlockAnnounce L4Proto) where
type instance ProtocolId (BlockAnnounce L4Proto) = 3 type instance ProtocolId (BlockAnnounce L4Proto) = 3
type instance Encoded L4Proto = ByteString type instance Encoded L4Proto = ByteString
decode = either (const Nothing) Just . deserialiseOrFail decode = deserialiseCustom
encode = serialise encode = serialise
instance HasProtocol L4Proto (PeerHandshake L4Proto) where instance HasProtocol L4Proto (PeerHandshake L4Proto) where
type instance ProtocolId (PeerHandshake L4Proto) = 4 type instance ProtocolId (PeerHandshake L4Proto) = 4
type instance Encoded L4Proto = ByteString type instance Encoded L4Proto = ByteString
decode = either (const Nothing) Just . deserialiseOrFail decode = deserialiseCustom
encode = serialise encode = serialise
requestPeriodLim = ReqLimPerProto 0.5 requestPeriodLim = ReqLimPerProto 0.5
@ -88,19 +93,19 @@ instance HasProtocol L4Proto (PeerHandshake L4Proto) where
instance HasProtocol L4Proto (PeerAnnounce L4Proto) where instance HasProtocol L4Proto (PeerAnnounce L4Proto) where
type instance ProtocolId (PeerAnnounce L4Proto) = 5 type instance ProtocolId (PeerAnnounce L4Proto) = 5
type instance Encoded L4Proto = ByteString type instance Encoded L4Proto = ByteString
decode = either (const Nothing) Just . deserialiseOrFail decode = deserialiseCustom
encode = serialise encode = serialise
instance HasProtocol L4Proto (PeerExchange L4Proto) where instance HasProtocol L4Proto (PeerExchange L4Proto) where
type instance ProtocolId (PeerExchange L4Proto) = 6 type instance ProtocolId (PeerExchange L4Proto) = 6
type instance Encoded L4Proto = ByteString type instance Encoded L4Proto = ByteString
decode = either (const Nothing) Just . deserialiseOrFail decode = deserialiseCustom
encode = serialise encode = serialise
instance HasProtocol L4Proto (RefLogUpdate L4Proto) where instance HasProtocol L4Proto (RefLogUpdate L4Proto) where
type instance ProtocolId (RefLogUpdate L4Proto) = 7 type instance ProtocolId (RefLogUpdate L4Proto) = 7
type instance Encoded L4Proto = ByteString type instance Encoded L4Proto = ByteString
decode = either (const Nothing) Just . deserialiseOrFail decode = deserialiseCustom
encode = serialise encode = serialise
requestPeriodLim = ReqLimPerMessage 600 requestPeriodLim = ReqLimPerMessage 600
@ -108,13 +113,13 @@ instance HasProtocol L4Proto (RefLogUpdate L4Proto) where
instance HasProtocol L4Proto (RefLogRequest L4Proto) where instance HasProtocol L4Proto (RefLogRequest L4Proto) where
type instance ProtocolId (RefLogRequest L4Proto) = 8 type instance ProtocolId (RefLogRequest L4Proto) = 8
type instance Encoded L4Proto = ByteString type instance Encoded L4Proto = ByteString
decode = either (const Nothing) Just . deserialiseOrFail decode = deserialiseCustom
encode = serialise encode = serialise
instance HasProtocol L4Proto (PeerMetaProto L4Proto) where instance HasProtocol L4Proto (PeerMetaProto L4Proto) where
type instance ProtocolId (PeerMetaProto L4Proto) = 9 type instance ProtocolId (PeerMetaProto L4Proto) = 9
type instance Encoded L4Proto = ByteString type instance Encoded L4Proto = ByteString
decode = either (const Nothing) Just . deserialiseOrFail decode = deserialiseCustom
encode = serialise encode = serialise
-- FIXME: real-period -- FIXME: real-period
@ -147,31 +152,31 @@ instance Expires (EventKey L4Proto (PeerMetaProto L4Proto)) where
-- instance MonadIO m => HasNonces () m where -- instance MonadIO m => HasNonces () m where
-- type instance Nonce (PeerHandshake L4Proto) = BS.ByteString -- type instance Nonce (PeerHandshake L4Proto) = BS.ByteString
-- newNonce = do -- newNonce = do
-- n <- liftIO ( Crypto.newNonce <&> Crypto.encode ) -- n <- liftIO ( Encrypt.newNonce <&> Crypto.encode )
-- pure $ BS.take 32 n -- pure $ BS.take 32 n
instance MonadIO m => HasNonces (PeerHandshake L4Proto) m where instance MonadIO m => HasNonces (PeerHandshake L4Proto) m where
type instance Nonce (PeerHandshake L4Proto) = BS.ByteString type instance Nonce (PeerHandshake L4Proto) = BS.ByteString
newNonce = do newNonce = do
n <- liftIO ( Crypto.newNonce <&> Crypto.encode ) n <- liftIO ( Encrypt.newNonce <&> Crypto.encode )
pure $ BS.take 32 n pure $ BS.take 32 n
instance MonadIO m => HasNonces (PeerExchange L4Proto) m where instance MonadIO m => HasNonces (PeerExchange L4Proto) m where
type instance Nonce (PeerExchange L4Proto) = BS.ByteString type instance Nonce (PeerExchange L4Proto) = BS.ByteString
newNonce = do newNonce = do
n <- liftIO ( Crypto.newNonce <&> Crypto.encode ) n <- liftIO ( Encrypt.newNonce <&> Crypto.encode )
pure $ BS.take 32 n pure $ BS.take 32 n
instance MonadIO m => HasNonces (RefLogUpdate L4Proto) m where instance MonadIO m => HasNonces (RefLogUpdate L4Proto) m where
type instance Nonce (RefLogUpdate L4Proto) = BS.ByteString type instance Nonce (RefLogUpdate L4Proto) = BS.ByteString
newNonce = do newNonce = do
n <- liftIO ( Crypto.newNonce <&> Crypto.encode ) n <- liftIO ( Encrypt.newNonce <&> Crypto.encode )
pure $ BS.take 32 n 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
n <- liftIO ( Crypto.newNonce <&> Crypto.encode ) n <- liftIO ( Encrypt.newNonce <&> Crypto.encode )
pure $ BS.take 32 n pure $ BS.take 32 n
instance Serialise Sign.Signature instance Serialise Sign.Signature
@ -181,6 +186,16 @@ instance Signatures HBS2Basic where
makeSign = Sign.signDetached makeSign = Sign.signDetached
verifySign = Sign.signVerifyDetached verifySign = Sign.signVerifyDetached
instance Asymm HBS2Basic where
type AsymmKeypair HBS2Basic = Encrypt.Keypair
type AsymmPrivKey HBS2Basic = Encrypt.SecretKey
type AsymmPubKey HBS2Basic = Encrypt.PublicKey
type CommonSecret HBS2Basic = Encrypt.CombinedKey
asymmNewKeypair = liftIO Encrypt.newKeypair
privKeyFromKeypair = Encrypt.secretKey
pubKeyFromKeypair = Encrypt.publicKey
genCommonSecret = Encrypt.beforeNM
instance Hashed HbSync Sign.PublicKey where instance Hashed HbSync Sign.PublicKey where
hashObject pk = hashObject (Crypto.encode pk) hashObject pk = hashObject (Crypto.encode pk)

View File

@ -3,6 +3,7 @@
module HBS2.Net.Proto.Peer where module HBS2.Net.Proto.Peer where
-- import HBS2.Base58 -- import HBS2.Base58
import HBS2.Actors.Peer
import HBS2.Data.Types import HBS2.Data.Types
import HBS2.Events import HBS2.Events
import HBS2.Net.Proto import HBS2.Net.Proto
@ -10,13 +11,15 @@ import HBS2.Clock
import HBS2.Net.Proto.Sessions import HBS2.Net.Proto.Sessions
import HBS2.Prelude.Plated import HBS2.Prelude.Plated
import HBS2.Net.Auth.Credentials import HBS2.Net.Auth.Credentials
import HBS2.System.Logger.Simple
-- import HBS2.System.Logger.Simple import Control.Monad
import Crypto.Saltine.Core.Box qualified as Encrypt
import Data.Maybe import Data.Maybe
import Codec.Serialise() import Codec.Serialise()
import Data.ByteString qualified as BS import Data.ByteString qualified as BS
import Data.Hashable import Data.Hashable
import Data.String.Conversions (cs)
import Lens.Micro.Platform import Lens.Micro.Platform
import Type.Reflection (someTypeRep) import Type.Reflection (someTypeRep)
@ -30,13 +33,36 @@ data PeerData e =
} }
deriving stock (Typeable,Generic) deriving stock (Typeable,Generic)
deriving instance
( Show (PubKey 'Sign (Encryption e))
, Show (Nonce ())
)
=> Show (PeerData e)
makeLenses 'PeerData makeLenses 'PeerData
data PeerDataExt e = PeerDataExt
{ _peerData :: PeerData e
, _peerEncPubKey :: Maybe (PubKey 'Encrypt (Encryption e))
}
deriving stock (Typeable,Generic)
makeLenses 'PeerDataExt
data PeerHandshake e = data PeerHandshake e =
PeerPing PingNonce PeerPing PingNonce
| PeerPong PingNonce (Signature (Encryption e)) (PeerData e) | PeerPong PingNonce (Signature (Encryption e)) (PeerData e)
| PeerPingCrypted PingNonce (PubKey 'Encrypt (Encryption e))
| PeerPongCrypted PingNonce (Signature (Encryption e)) (PubKey 'Encrypt (Encryption e)) (PeerData e)
deriving stock (Generic) deriving stock (Generic)
deriving instance
( Show (PubKey 'Encrypt (Encryption e))
, Show (Signature (Encryption e))
, Show (PeerData e)
)
=> Show (PeerHandshake e)
newtype KnownPeer e = KnownPeer (PeerData e) newtype KnownPeer e = KnownPeer (PeerData e)
deriving stock (Typeable,Generic) deriving stock (Typeable,Generic)
@ -48,12 +74,13 @@ data PeerPingData e =
PeerPingData PeerPingData
{ _peerPingNonce :: PingNonce { _peerPingNonce :: PingNonce
, _peerPingSent :: TimeSpec , _peerPingSent :: TimeSpec
, _peerPingEncPubKey :: Maybe (PubKey 'Encrypt (Encryption e))
} }
deriving stock (Generic,Typeable) deriving stock (Generic,Typeable)
makeLenses 'PeerPingData makeLenses 'PeerPingData
type instance SessionData e (KnownPeer e) = PeerData e type instance SessionData e (KnownPeer e) = PeerDataExt e
newtype instance SessionKey e (PeerHandshake e) = newtype instance SessionKey e (PeerHandshake e) =
PeerHandshakeKey (PingNonce, Peer e) PeerHandshakeKey (PingNonce, Peer e)
@ -82,10 +109,28 @@ sendPing :: forall e m . ( MonadIO m
sendPing pip = do sendPing pip = do
nonce <- newNonce @(PeerHandshake e) nonce <- newNonce @(PeerHandshake e)
tt <- liftIO $ getTimeCoarse tt <- liftIO $ getTimeCoarse
let pdd = PeerPingData nonce tt let pdd = PeerPingData nonce tt Nothing
update pdd (PeerHandshakeKey (nonce,pip)) id update pdd (PeerHandshakeKey (nonce,pip)) id
request pip (PeerPing @e nonce) request pip (PeerPing @e nonce)
sendPingCrypted :: forall e m . ( MonadIO m
, Request e (PeerHandshake e) m
, Sessions e (PeerHandshake e) m
, HasNonces (PeerHandshake e) m
, Nonce (PeerHandshake e) ~ PingNonce
, Pretty (Peer e)
, HasProtocol e (PeerHandshake e)
, e ~ L4Proto
)
=> Peer e -> PubKey 'Encrypt (Encryption e) -> m ()
sendPingCrypted pip pubkey = do
nonce <- newNonce @(PeerHandshake e)
tt <- liftIO $ getTimeCoarse
let pdd = PeerPingData nonce tt (Just pubkey)
update pdd (PeerHandshakeKey (nonce,pip)) id
request pip (PeerPingCrypted @e nonce pubkey)
newtype PeerHandshakeAdapter e m = newtype PeerHandshakeAdapter e m =
PeerHandshakeAdapter PeerHandshakeAdapter
{ onPeerRTT :: (Peer e, Integer) -> m () { onPeerRTT :: (Peer e, Integer) -> m ()
@ -103,15 +148,20 @@ peerHandShakeProto :: forall e s m . ( MonadIO m
, Pretty (Peer e) , Pretty (Peer e)
, EventEmitter e (PeerHandshake e) m , EventEmitter e (PeerHandshake e) m
, EventEmitter e (ConcretePeer e) m , EventEmitter e (ConcretePeer e) m
, EventEmitter e (PeerAsymmInfo e) m
, HasCredentials s m , HasCredentials s m
, Asymm s
, Signatures s , Signatures s
, Serialise (PubKey 'Encrypt (Encryption e))
, s ~ Encryption e , s ~ Encryption e
, e ~ L4Proto , e ~ L4Proto
) )
=> PeerHandshakeAdapter e m => PeerHandshakeAdapter e m
-> PeerHandshake e -> m () -> PeerEnv e
-> PeerHandshake e
-> m ()
peerHandShakeProto adapter = peerHandShakeProto adapter penv =
\case \case
PeerPing nonce -> do PeerPing nonce -> do
pip <- thatPeer proto pip <- thatPeer proto
@ -138,7 +188,11 @@ peerHandShakeProto adapter =
se' <- find @e (PeerHandshakeKey (nonce0,pip)) id se' <- find @e (PeerHandshakeKey (nonce0,pip)) id
maybe1 se' (pure ()) $ \(PeerPingData nonce t0) -> do maybe1 se' (pure ()) $ \(PeerPingData nonce t0 mpubkey) -> do
-- Мы отправляли ключ шифрования, но собеседник отказался
-- от шифрованной сессии
-- when (isJust mpubkey) do
let pk = view peerSignKey d let pk = view peerSignKey d
@ -155,10 +209,76 @@ peerHandShakeProto adapter =
-- FIXME: check if peer is blacklisted -- FIXME: check if peer is blacklisted
-- right here -- right here
update d (KnownPeerKey pip) id let pde = PeerDataExt d Nothing
update pde (KnownPeerKey pip) id
emit AnyKnownPeerEventKey (KnownPeerEvent pip d) emit AnyKnownPeerEventKey (KnownPeerEvent pip pde)
emit (ConcretePeerKey pip) (ConcretePeerData pip d) emit (ConcretePeerKey pip) (ConcretePeerData pip pde)
---- Crypted
PeerPingCrypted nonce theirpubkey -> do
pip <- thatPeer proto
trace $ "GOT PING CRYPTED from" <+> pretty pip
-- взять свои ключи
creds <- getCredentials @s
let ourpubkey = pubKeyFromKeypair @s $ view envAsymmetricKeyPair penv
-- подписать нонс
let sign = makeSign @s (view peerSignSk creds) (nonce <> (cs . serialise) ourpubkey)
own <- peerNonce @e
-- отправить обратно вместе с публичным ключом
response (PeerPongCrypted @e nonce sign ourpubkey (PeerData (view peerSignPk creds) own))
-- да и пингануть того самим
se <- find (KnownPeerKey pip) id <&> isJust
-- Нужно ли запомнить его theirpubkey или достаточно того, что будет
-- получено в обратном PeerPongCrypted?
-- Нужно!
emit PeerAsymmInfoKey (PeerAsymmPubKey pip theirpubkey)
unless se $ do
sendPingCrypted pip ourpubkey
PeerPongCrypted nonce0 sign theirpubkey pd -> do
pip <- thatPeer proto
trace $ "GOT PONG CRYPTED from" <+> pretty pip
se' <- find @e (PeerHandshakeKey (nonce0,pip)) id
maybe1 se' (pure ()) $ \(PeerPingData nonce t0 mpubkey) -> do
-- TODO: Мы не отправляли ключ шифрования, а собеседник ответил как будто
-- отправляли. Как тут поступать?
-- guard (isNothing mpubkey)
let pk = view peerSignKey pd
pde = PeerDataExt pd (Just theirpubkey)
let signed = verifySign @s pk sign (nonce <> (cs . serialise) theirpubkey)
when signed $ do
now <- liftIO getTimeCoarse
let rtt = toNanoSecs $ now - t0
onPeerRTT adapter (pip,rtt)
expire (PeerHandshakeKey (nonce0,pip))
-- FIXME: check if peer is blacklisted
-- right here
update pde (KnownPeerKey pip) id
emit AnyKnownPeerEventKey (KnownPeerEvent pip pde)
emit (ConcretePeerKey pip) (ConcretePeerData pip pde)
---- /Crypted
where where
proto = Proxy @(PeerHandshake e) proto = Proxy @(PeerHandshake e)
@ -173,15 +293,32 @@ deriving stock instance (Eq (Peer e)) => Eq (EventKey e (ConcretePeer e))
instance (Hashable (Peer e)) => Hashable (EventKey e (ConcretePeer e)) instance (Hashable (Peer e)) => Hashable (EventKey e (ConcretePeer e))
data instance Event e (ConcretePeer e) = data instance Event e (ConcretePeer e) =
ConcretePeerData (Peer e) (PeerData e) ConcretePeerData (Peer e) (PeerDataExt e)
deriving stock (Typeable) deriving stock (Typeable)
---
data PeerAsymmInfo e = PeerAsymmInfo
data instance EventKey e (PeerAsymmInfo e) =
PeerAsymmInfoKey
deriving stock (Generic)
deriving stock instance (Eq (Peer e)) => Eq (EventKey e (PeerAsymmInfo e))
instance (Hashable (Peer e)) => Hashable (EventKey e (PeerAsymmInfo e))
data instance Event e (PeerAsymmInfo e) =
PeerAsymmPubKey (Peer e) (AsymmPubKey (Encryption e))
deriving stock (Typeable)
---
data instance EventKey e (PeerHandshake e) = data instance EventKey e (PeerHandshake e) =
AnyKnownPeerEventKey AnyKnownPeerEventKey
deriving stock (Typeable, Eq,Generic) deriving stock (Typeable, Eq,Generic)
data instance Event e (PeerHandshake e) = data instance Event e (PeerHandshake e) =
KnownPeerEvent (Peer e) (PeerData e) KnownPeerEvent (Peer e) (PeerDataExt e)
deriving stock (Typeable) deriving stock (Typeable)
instance ( Typeable (KnownPeer e) instance ( Typeable (KnownPeer e)
@ -197,6 +334,9 @@ instance EventType ( Event e ( PeerHandshake e) ) where
instance Expires (EventKey e (PeerHandshake e)) where instance Expires (EventKey e (PeerHandshake e)) where
expiresIn _ = Nothing expiresIn _ = Nothing
instance Expires (EventKey e (PeerAsymmInfo e)) where
expiresIn _ = Nothing
instance Expires (EventKey e (ConcretePeer e)) where instance Expires (EventKey e (ConcretePeer e)) where
expiresIn _ = Just 60 expiresIn _ = Just 60
@ -209,6 +349,7 @@ deriving instance Eq (Peer e) => Eq (SessionKey e (PeerHandshake e))
instance Hashable (Peer e) => Hashable (SessionKey e (PeerHandshake e)) instance Hashable (Peer e) => Hashable (SessionKey e (PeerHandshake e))
instance ( Serialise (PubKey 'Sign (Encryption e)) instance ( Serialise (PubKey 'Sign (Encryption e))
, Serialise (PubKey 'Encrypt (Encryption e))
, Serialise (Signature (Encryption e)) , Serialise (Signature (Encryption e))
, Serialise PeerNonce , Serialise PeerNonce
) )
@ -216,6 +357,7 @@ instance ( Serialise (PubKey 'Sign (Encryption e))
=> Serialise (PeerData e) => Serialise (PeerData e)
instance ( Serialise (PubKey 'Sign (Encryption e)) instance ( Serialise (PubKey 'Sign (Encryption e))
, Serialise (PubKey 'Encrypt (Encryption e))
, Serialise (Signature (Encryption e)) , Serialise (Signature (Encryption e))
, Serialise PeerNonce , Serialise PeerNonce
) )

View File

@ -30,6 +30,8 @@ newtype PeerAnnounce e =
PeerAnnounce PeerNonce PeerAnnounce PeerNonce
deriving stock (Typeable, Generic) deriving stock (Typeable, Generic)
deriving instance Show (Nonce ()) => Show (PeerAnnounce e)
peerAnnounceProto :: forall e m . ( MonadIO m peerAnnounceProto :: forall e m . ( MonadIO m
, EventEmitter e (PeerAnnounce e) m , EventEmitter e (PeerAnnounce e) m

View File

@ -31,6 +31,11 @@ data PeerExchange e =
| PeerExchangePeers2 (Nonce (PeerExchange e)) [PeerAddr e] | PeerExchangePeers2 (Nonce (PeerExchange e)) [PeerAddr e]
deriving stock (Generic, Typeable) deriving stock (Generic, Typeable)
deriving instance
( Show (Nonce (PeerExchange e))
, Show (PeerAddr e)
) => Show (PeerExchange e)
data PeerExchangePeersEv e data PeerExchangePeersEv e
@ -110,30 +115,47 @@ peerExchangeProto pexFilt msg = do
case pex of case pex of
PEX1 -> do PEX1 -> do
pa <- take defPexMaxPeers <$> getAllPex1Peers
-- TODO: tcp-peer-support-in-pex
pa' <- forM pips $ \p -> do
auth <- find (KnownPeerKey p) id <&> isJust
pa <- toPeerAddr p
case pa of
(L4Address UDP x) | auth -> pure [x]
_ -> pure mempty
let pa = take defPexMaxPeers $ mconcat pa'
response (PeerExchangePeers @e n pa) response (PeerExchangePeers @e n pa)
PEX2 -> do PEX2 -> do
pa <- take defPexMaxPeers <$> getAllPex2Peers
pa' <- forM pips $ \p -> do
auth <- find (KnownPeerKey p) id
maybe1 auth (pure mempty) ( const $ fmap L.singleton (toPeerAddr p) )
-- FIXME: asap-random-shuffle-peers
let pa = take defPexMaxPeers $ mconcat pa'
response (PeerExchangePeers2 @e n pa) response (PeerExchangePeers2 @e n pa)
getAllPex1Peers :: forall e m .
( MonadIO m
, Sessions e (KnownPeer e) m
, HasPeerLocator L4Proto m
, e ~ L4Proto
)
=> m [IPAddrPort L4Proto]
getAllPex1Peers = do
pl <- getPeerLocator @e
pips <- knownPeers @e pl
-- TODO: tcp-peer-support-in-pex
pa' <- forM pips $ \p -> do
auth <- find (KnownPeerKey p) id <&> isJust
pa <- toPeerAddr p
case pa of
(L4Address UDP x) | auth -> pure [x]
_ -> pure mempty
pure $ mconcat pa'
getAllPex2Peers :: forall e m .
( MonadIO m
, Sessions e (KnownPeer e) m
, HasPeerLocator L4Proto m
, e ~ L4Proto
)
=> m [PeerAddr L4Proto]
getAllPex2Peers = do
pl <- getPeerLocator @e
pips <- knownPeers @e pl
pa' <- forM pips $ \p -> do
auth <- find (KnownPeerKey p) id
maybe1 auth (pure mempty) ( const $ fmap L.singleton (toPeerAddr p) )
-- FIXME: asap-random-shuffle-peers
pure $ mconcat pa'
newtype instance SessionKey e (PeerExchange e) = newtype instance SessionKey e (PeerExchange e) =
PeerExchangeKey (Nonce (PeerExchange e)) PeerExchangeKey (Nonce (PeerExchange e))

View File

@ -27,6 +27,10 @@ data RefLogRequest e =
| RefLogResponse (PubKey 'Sign (Encryption e)) (Hash HbSync) | RefLogResponse (PubKey 'Sign (Encryption e)) (Hash HbSync)
deriving stock (Generic) deriving stock (Generic)
deriving instance
( Show (PubKey 'Sign (Encryption e))
) => Show (RefLogRequest e)
data RefLogUpdate e = data RefLogUpdate e =
RefLogUpdate RefLogUpdate
{ _refLogId :: PubKey 'Sign (Encryption e) { _refLogId :: PubKey 'Sign (Encryption e)
@ -36,6 +40,12 @@ data RefLogUpdate e =
} }
deriving stock (Generic) deriving stock (Generic)
deriving instance
( Show (PubKey 'Sign (Encryption e))
, Show (Signature (Encryption e))
, Show (Nonce (RefLogUpdate e))
) => Show (RefLogUpdate e)
makeLenses 'RefLogUpdate makeLenses 'RefLogUpdate
newtype RefLogUpdateI e m = newtype RefLogUpdateI e m =

View File

@ -107,7 +107,8 @@ data ReqLimPeriod = NoLimit
| ReqLimPerProto (Timeout 'Seconds) | ReqLimPerProto (Timeout 'Seconds)
| ReqLimPerMessage (Timeout 'Seconds) | ReqLimPerMessage (Timeout 'Seconds)
class (KnownNat (ProtocolId p), HasPeer e) => HasProtocol e p | p -> e where class (KnownNat (ProtocolId p), HasPeer e, Show (Encoded e)
) => HasProtocol e p | p -> e where
type family ProtocolId p = (id :: Nat) | id -> p type family ProtocolId p = (id :: Nat) | id -> p
type family Encoded e :: Type type family Encoded e :: Type

View File

@ -3,6 +3,7 @@ module Main where
import TestFakeMessaging import TestFakeMessaging
import TestActors import TestActors
-- import TestUniqProtoId -- import TestUniqProtoId
import TestCrypto
import Test.Tasty import Test.Tasty
import Test.Tasty.HUnit import Test.Tasty.HUnit
@ -15,6 +16,7 @@ main =
testCase "testFakeMessaging1" testFakeMessaging1 testCase "testFakeMessaging1" testFakeMessaging1
, testCase "testActorsBasic" testActorsBasic , testCase "testActorsBasic" testActorsBasic
-- , testCase "testUniqProtoId" testUniqProtoId -- , testCase "testUniqProtoId" testUniqProtoId
, testCrypto
] ]

View File

@ -0,0 +1,53 @@
{-# OPTIONS_GHC -fno-warn-orphans #-}
module TestCrypto where
import Test.QuickCheck.Instances.ByteString
import Test.Tasty
import Test.Tasty.QuickCheck as QC
-- import Control.Monad.Trans.Maybe
import Control.Monad
import Crypto.Saltine.Class qualified as Saltine
import Crypto.Saltine.Core.Box qualified as Encrypt
import Crypto.Saltine.Internal.Box qualified as Encrypt
import Data.ByteString (ByteString)
import Data.ByteString qualified as BS
import Data.Maybe
import Data.String.Conversions (cs)
import HBS2.Crypto
testCrypto :: TestTree
testCrypto = testGroup "testCrypto"
[ QC.testProperty "roundtripCombineExtractNonce" prop_roundtripCombineExtractNonce
, QC.testProperty "roundtripEncodingAfterNM" prop_roundtripEncodingAfterNM
]
instance Arbitrary Encrypt.Nonce where
arbitrary = Encrypt.Nonce . BS.pack <$> vectorOf Encrypt.box_noncebytes arbitrary
instance Arbitrary Encrypt.SecretKey where
arbitrary = (fromMaybe (error "Should be Just value") . Saltine.decode)
. BS.pack <$> vectorOf Encrypt.box_beforenmbytes arbitrary
instance Arbitrary Encrypt.PublicKey where
arbitrary = (fromMaybe (error "Should be Just value") . Saltine.decode)
. BS.pack <$> vectorOf Encrypt.box_beforenmbytes arbitrary
prop_roundtripCombineExtractNonce :: (Encrypt.Nonce, ByteString) -> Bool
prop_roundtripCombineExtractNonce (n, b) =
extractNonce (combineNonceBS n b) == Just (n, b)
prop_roundtripEncodingAfterNM :: (Encrypt.SecretKey, Encrypt.PublicKey, Encrypt.Nonce, ByteString) -> Bool
prop_roundtripEncodingAfterNM (sk, pk, n, b) = fromMaybe False do
let
ck = Encrypt.beforeNM sk pk
let box = boxAfterNMLazy ck n (cs b)
(n', x) <- extractNonce (cs box)
guard (n' == n)
b'' <- boxOpenAfterNMLazy ck n' x
pure (cs b'' == b)

View File

@ -5,6 +5,7 @@ import HBS2.Actors.Peer
import HBS2.Net.Proto.PeerMeta import HBS2.Net.Proto.PeerMeta
import HBS2.Storage import HBS2.Storage
import HBS2.Data.Types.Refs import HBS2.Data.Types.Refs
import HBS2.Merkle (AnnMetaData)
import HBS2.Net.Proto.Types import HBS2.Net.Proto.Types
import HBS2.System.Logger.Simple import HBS2.System.Logger.Simple
@ -31,9 +32,10 @@ httpWorker :: forall e s m . ( MyPeer e
, HasStorage m , HasStorage m
, IsRefPubKey s , IsRefPubKey s
, s ~ Encryption e , s ~ Encryption e
) => PeerConfig -> DownloadEnv e -> m () )
=> PeerConfig -> AnnMetaData -> DownloadEnv e -> m ()
httpWorker conf e = do httpWorker conf pmeta e = do
sto <- getStorage sto <- getStorage
let port' = cfgValue @PeerHttpPortKey conf <&> fromIntegral let port' = cfgValue @PeerHttpPortKey conf <&> fromIntegral
@ -71,7 +73,7 @@ httpWorker conf e = do
text [qc|{pretty val}|] text [qc|{pretty val}|]
get "/metadata" do get "/metadata" do
raw $ serialise $ mkPeerMeta conf raw $ serialise $ pmeta
put "/" do put "/" do
-- FIXME: optional-header-based-authorization -- FIXME: optional-header-based-authorization

View File

@ -5,6 +5,7 @@ module PeerInfo where
import HBS2.Actors.Peer import HBS2.Actors.Peer
import HBS2.Clock import HBS2.Clock
import HBS2.Events import HBS2.Events
import HBS2.Net.Auth.Credentials
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.PeerExchange
@ -145,8 +146,8 @@ peerPingLoop :: forall e m . ( HasPeerLocator e m
, m ~ PeerM e IO , m ~ PeerM e IO
, e ~ L4Proto , e ~ L4Proto
) )
=> PeerConfig -> m () => PeerConfig -> PeerEnv e -> m ()
peerPingLoop cfg = do peerPingLoop cfg penv = do
e <- ask e <- ask
@ -240,7 +241,18 @@ peerPingLoop cfg = do
pips <- knownPeers @e pl <&> (<> sas) <&> List.nub pips <- knownPeers @e pl <&> (<> sas) <&> List.nub
for_ pips $ \p -> do for_ pips $ \p -> do
trace $ "SEND PING TO" <+> pretty p -- trace $ "SEND PING TO" <+> pretty p
sendPing @e p sendPing @e p
-- trace $ "SENT PING TO" <+> pretty p
pause dt
sendPingCrypted @e p
(pubKeyFromKeypair @(Encryption e) (view envAsymmetricKeyPair penv))
-- trace $ "SENT PING CRYPTED TO" <+> pretty p
where
dt = case (requestPeriodLim @e @(PeerHandshake e)) of
NoLimit -> 0
ReqLimPerProto t -> t + 0.1
ReqLimPerMessage t -> t + 0.1

View File

@ -15,10 +15,11 @@ import HBS2.Data.Types.Refs (RefLogKey(..))
import HBS2.Merkle import HBS2.Merkle
import HBS2.Net.Auth.Credentials import HBS2.Net.Auth.Credentials
import HBS2.Net.IP.Addr import HBS2.Net.IP.Addr
import HBS2.Net.Messaging
import HBS2.Net.Messaging.UDP import HBS2.Net.Messaging.UDP
import HBS2.Net.Messaging.TCP import HBS2.Net.Messaging.TCP
import HBS2.Net.PeerLocator import HBS2.Net.PeerLocator
import HBS2.Net.Proto import HBS2.Net.Proto as 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
@ -49,7 +50,7 @@ import HttpWorker
import ProxyMessaging import ProxyMessaging
import PeerMeta import PeerMeta
import Codec.Serialise import Codec.Serialise as Serialise
-- import Control.Concurrent.Async -- import Control.Concurrent.Async
import Control.Concurrent.STM import Control.Concurrent.STM
import Control.Exception as Exception import Control.Exception as Exception
@ -62,7 +63,8 @@ import Data.ByteString.Lazy qualified as LBS
import Data.ByteString qualified as BS import Data.ByteString qualified as BS
import Data.Cache qualified as Cache import Data.Cache qualified as Cache
import Data.Function import Data.Function
import Data.List qualified as L import Data.List qualified as L
import Data.Map (Map)
import Data.Map qualified as Map import Data.Map qualified as Map
import Data.Maybe import Data.Maybe
import Data.Set qualified as Set import Data.Set qualified as Set
@ -73,7 +75,7 @@ import Data.Text (Text)
import Data.HashSet qualified as HashSet import Data.HashSet qualified as HashSet
import GHC.Stats import GHC.Stats
import GHC.TypeLits import GHC.TypeLits
import Lens.Micro.Platform import Lens.Micro.Platform as Lens
import Network.Socket import Network.Socket
import Options.Applicative import Options.Applicative
import System.Directory import System.Directory
@ -83,6 +85,7 @@ import System.Mem
import System.Metrics import System.Metrics
import System.Posix.Process import System.Posix.Process
import System.Environment import System.Environment
import Text.InterpolatedString.Perl6 (qc)
import UnliftIO.Exception qualified as U import UnliftIO.Exception qualified as U
-- import UnliftIO.STM -- import UnliftIO.STM
@ -177,6 +180,7 @@ data RPCCommand =
| CHECK PeerNonce (PeerAddr L4Proto) (Hash HbSync) | CHECK PeerNonce (PeerAddr L4Proto) (Hash HbSync)
| FETCH (Hash HbSync) | FETCH (Hash HbSync)
| PEERS | PEERS
| PEXINFO
| SETLOG SetLogging | SETLOG SetLogging
| REFLOGUPDATE ByteString | REFLOGUPDATE ByteString
| REFLOGFETCH (PubKey 'Sign (Encryption L4Proto)) | REFLOGFETCH (PubKey 'Sign (Encryption L4Proto))
@ -245,6 +249,7 @@ runCLI = join . customExecParser (prefs showHelpOnError) $
<> command "fetch" (info pFetch (progDesc "fetch block")) <> command "fetch" (info pFetch (progDesc "fetch block"))
<> command "reflog" (info pRefLog (progDesc "reflog commands")) <> command "reflog" (info pRefLog (progDesc "reflog commands"))
<> command "peers" (info pPeers (progDesc "show known peers")) <> command "peers" (info pPeers (progDesc "show known peers"))
<> command "pexinfo" (info pPexInfo (progDesc "show pex"))
<> command "log" (info pLog (progDesc "set logging level")) <> command "log" (info pLog (progDesc "set logging level"))
) )
@ -306,6 +311,10 @@ runCLI = join . customExecParser (prefs showHelpOnError) $
rpc <- pRpcCommon rpc <- pRpcCommon
pure $ runRpcCommand rpc PEERS pure $ runRpcCommand rpc PEERS
pPexInfo = do
rpc <- pRpcCommon
pure $ runRpcCommand rpc PEXINFO
onOff l = onOff l =
hsubparser ( command "on" (info (pure (l True) ) (progDesc "on") ) ) hsubparser ( command "on" (info (pure (l True) ) (progDesc "on") ) )
<|> hsubparser ( command "off" (info (pure (l False) ) (progDesc "off") ) ) <|> hsubparser ( command "off" (info (pure (l False) ) (progDesc "off") ) )
@ -496,16 +505,16 @@ runPeer opts = U.handle (\e -> myException e
liftIO $ print $ pretty accptAnn liftIO $ print $ pretty accptAnn
-- FIXME: move-peerBanned-somewhere -- FIXME: move-peerBanned-somewhere
let peerBanned p d = do let peerBanned p pd = do
let k = view peerSignKey d let k = view peerSignKey pd
let blacklisted = k `Set.member` blkeys let blacklisted = k `Set.member` blkeys
let whitelisted = Set.null wlkeys || (k `Set.member` wlkeys) let whitelisted = Set.null wlkeys || (k `Set.member` wlkeys)
pure $ blacklisted || not whitelisted pure $ blacklisted || not whitelisted
let acceptAnnounce p d = do let acceptAnnounce p pd = do
case accptAnn of case accptAnn of
AcceptAnnounceAll -> pure True AcceptAnnounceAll -> pure True
AcceptAnnounceFrom s -> pure $ view peerSignKey d `Set.member` s AcceptAnnounceFrom s -> pure $ view peerSignKey pd `Set.member` s
rpcQ <- liftIO $ newTQueueIO @RPCCommand rpcQ <- liftIO $ newTQueueIO @RPCCommand
@ -571,6 +580,8 @@ runPeer opts = U.handle (\e -> myException e
penv <- newPeerEnv (AnyStorage s) (Fabriq proxy) (getOwnPeer mess) penv <- newPeerEnv (AnyStorage s) (Fabriq proxy) (getOwnPeer mess)
let peerMeta = mkPeerMeta conf penv
nbcache <- liftIO $ Cache.newCache (Just $ toTimeSpec ( 600 :: Timeout 'Seconds)) nbcache <- liftIO $ Cache.newCache (Just $ toTimeSpec ( 600 :: Timeout 'Seconds))
void $ async $ forever do void $ async $ forever do
@ -590,8 +601,8 @@ runPeer opts = U.handle (\e -> myException e
let onNoBlock (p, h) = do let onNoBlock (p, h) = do
already <- liftIO $ Cache.lookup nbcache (p,h) <&> isJust already <- liftIO $ Cache.lookup nbcache (p,h) <&> isJust
unless already do unless already do
pd' <- find (KnownPeerKey p) id mpde <- find (KnownPeerKey p) id
maybe1 pd' none $ \pd -> do maybe1 mpde none $ \pde@(PeerDataExt {_peerData = pd}) -> do
let pk = view peerSignKey pd let pk = view peerSignKey pd
when (Set.member pk helpFetchKeys) do when (Set.member pk helpFetchKeys) do
liftIO $ Cache.insert nbcache (p,h) () liftIO $ Cache.insert nbcache (p,h) ()
@ -644,26 +655,40 @@ runPeer opts = U.handle (\e -> myException e
subscribe @e PeerAnnounceEventKey $ \(PeerAnnounceEvent pip nonce) -> do subscribe @e PeerAnnounceEventKey $ \(PeerAnnounceEvent pip nonce) -> do
unless (nonce == pnonce) $ do unless (nonce == pnonce) $ do
debug $ "Got peer announce!" <+> pretty pip debug $ "Got peer announce!" <+> pretty pip
pd <- find (KnownPeerKey pip) id -- <&> isJust mpde :: Maybe (PeerDataExt e) <- find (KnownPeerKey pip) id
banned <- maybe (pure False) (peerBanned pip) pd banned <- maybe (pure False) (peerBanned pip . view peerData) mpde
let known = isJust pd && not banned let known = isJust mpde && not banned
sendPing pip sendPing pip
subscribe @e BlockAnnounceInfoKey $ \(BlockAnnounceEvent p bi no) -> do subscribe @e BlockAnnounceInfoKey $ \(BlockAnnounceEvent p bi no) -> do
pa <- toPeerAddr p pa <- toPeerAddr p
liftIO $ atomically $ writeTQueue rpcQ (CHECK no pa (view biHash bi)) liftIO $ atomically $ writeTQueue rpcQ (CHECK no pa (view biHash bi))
subscribe @e AnyKnownPeerEventKey $ \(KnownPeerEvent p d) -> do subscribe @e PeerAsymmInfoKey $ \(PeerAsymmPubKey p peerpubkey) -> do
defPeerInfo <- newPeerInfo
fetch True defPeerInfo (PeerInfoKey p) id >>= \pinfo -> do
let updj = genCommonSecret @s (privKeyFromKeypair @s (view envAsymmetricKeyPair penv))
$ peerpubkey
liftIO $ atomically $ modifyTVar' (view proxyEncryptionKeys proxy) $ Lens.at p .~ Just updj
liftIO $ trace [qc| UPDJust from PeerAsymmInfoKey at {p} {updj} |]
let thatNonce = view peerOwnNonce d subscribe @e AnyKnownPeerEventKey $ \(KnownPeerEvent p pde@(PeerDataExt{_peerData = pd})) -> do
let thatNonce = view peerOwnNonce pd
now <- liftIO getTimeCoarse now <- liftIO getTimeCoarse
pinfo' <- find (PeerInfoKey p) id -- (view peerPingFailed)
maybe1 pinfo' none $ \pinfo -> do
liftIO $ atomically $ writeTVar (view peerPingFailed pinfo) 0
liftIO $ atomically $ writeTVar (view peerLastWatched pinfo) now
banned <- peerBanned p d defPeerInfo <- newPeerInfo
fetch True defPeerInfo (PeerInfoKey p) id >>= \pinfo -> do
liftIO $ atomically $ writeTVar (view peerPingFailed pinfo) 0
liftIO $ atomically $ writeTVar (view peerLastWatched pinfo) now
let mupd = genCommonSecret @s (privKeyFromKeypair @s (view envAsymmetricKeyPair penv))
<$> view peerEncPubKey pde
forM_ mupd \upd -> do
liftIO $ atomically $ modifyTVar' (view proxyEncryptionKeys proxy) $ Lens.at p .~ Just upd
liftIO $ trace [qc| UPDJust from AnyKnownPeerEventKey at {p} {upd} |]
banned <- peerBanned p pd
let doAddPeer p = do let doAddPeer p = do
addPeers pl [p] addPeers pl [p]
@ -675,7 +700,7 @@ runPeer opts = U.handle (\e -> myException e
unless here do unless here do
debug $ "Got authorized peer!" <+> pretty p debug $ "Got authorized peer!" <+> pretty p
<+> pretty (AsBase58 (view peerSignKey d)) <+> pretty (AsBase58 (view peerSignKey pd))
request @e p (GetPeerMeta @e) request @e p (GetPeerMeta @e)
@ -691,14 +716,11 @@ runPeer opts = U.handle (\e -> myException e
| otherwise -> do | otherwise -> do
update d (KnownPeerKey p) id update pde (KnownPeerKey p) id
pd' <- knownPeers @e pl >>= pd :: Map BS.ByteString (Peer L4Proto) <- fmap (Map.fromList . catMaybes)
\peers -> forM peers $ \pip -> do $ knownPeers @e pl >>= mapM \pip ->
pd <- find (KnownPeerKey pip) (view peerOwnNonce) fmap (, pip) <$> find (KnownPeerKey pip) (view (peerData . peerOwnNonce))
pure $ (,pip) <$> pd
let pd = Map.fromList $ catMaybes pd'
let proto1 = view sockType p let proto1 = view sockType p
@ -767,11 +789,11 @@ runPeer opts = U.handle (\e -> myException e
-- peerThread "tcpWorker" (tcpWorker conf) -- peerThread "tcpWorker" (tcpWorker conf)
peerThread "httpWorker" (httpWorker conf denv) peerThread "httpWorker" (httpWorker conf peerMeta denv)
peerThread "checkMetrics" (checkMetrics metrics) peerThread "checkMetrics" (checkMetrics metrics)
peerThread "peerPingLoop" (peerPingLoop @e conf) peerThread "peerPingLoop" (peerPingLoop @e conf penv)
peerThread "knownPeersPingLoop" (knownPeersPingLoop @e conf) peerThread "knownPeersPingLoop" (knownPeersPingLoop @e conf)
@ -805,13 +827,64 @@ runPeer opts = U.handle (\e -> myException e
PING pa r -> do PING pa r -> do
debug $ "ping" <+> pretty pa debug $ "ping" <+> pretty pa
pip <- fromPeerAddr @e pa pip <- fromPeerAddr @e pa
subscribe (ConcretePeerKey pip) $ \(ConcretePeerData{}) -> do subscribe (ConcretePeerKey pip) $ \(ConcretePeerData _ pde) -> do
maybe1 r (pure ()) $ \rpcPeer -> do maybe1 r (pure ()) $ \rpcPeer -> do
pinged <- toPeerAddr pip pinged <- toPeerAddr pip
request rpcPeer (RPCPong @e pinged) request rpcPeer (RPCPong @e pinged)
-- case (view peerEncPubKey pde) of
-- Nothing -> unencrypted ping
-- Just pubkey -> encryptengd
sendPing pip let
requestPlain :: forall m msg .
( MonadIO m
-- , HasProtocol L4Proto msg
, msg ~ PeerHandshake L4Proto
, HasOwnPeer L4Proto m
-- , Messaging MessagingTCP L4Proto (AnyMessage ByteString L4Proto)
-- , Messaging MessagingUDP L4Proto (AnyMessage ByteString L4Proto)
, HasTimeLimits L4Proto (PeerHandshake L4Proto) m
) => Peer e -> msg -> m ()
requestPlain peer_e msg = do
let protoN = protoId @e @msg (Proxy @msg)
me <- ownPeer @e
allowed <- tryLockForPeriod peer_e msg
when (not allowed) do
trace $ "REQUEST: not allowed to send" <+> viaShow msg
-- when allowed do
-- sendTo proxy (To peer_e) (From me) (AnyMessage @(Encoded e) @e protoN (encode msg))
when allowed do
sendToPlainProxyMessaging (PlainProxyMessaging proxy) (To peer_e) (From me)
-- (AnyMessage @(Encoded e) @e protoN (Proto.encode msg))
(serialise (protoN, (Proto.encode msg)))
let
sendPingCrypted' pip pubkey = do
nonce <- newNonce @(PeerHandshake e)
tt <- liftIO $ getTimeCoarse
let pdd = PeerPingData nonce tt (Just pubkey)
update pdd (PeerHandshakeKey (nonce,pip)) id
requestPlain pip (PeerPingCrypted @e nonce pubkey)
let
sendPing' pip = do
nonce <- newNonce @(PeerHandshake e)
tt <- liftIO $ getTimeCoarse
let pdd = PeerPingData nonce tt Nothing
update pdd (PeerHandshakeKey (nonce,pip)) id
requestPlain pip (PeerPing @e nonce)
sendPingCrypted' pip (pubKeyFromKeypair @s (view envAsymmetricKeyPair penv))
pause $ case (requestPeriodLim @e @(PeerHandshake e)) of
NoLimit -> 0
ReqLimPerProto t -> t + 0.1
ReqLimPerMessage t -> t + 0.1
sendPing' pip
ANNOUNCE h -> do ANNOUNCE h -> do
debug $ "got announce rpc" <+> pretty h debug $ "got announce rpc" <+> pretty h
@ -839,18 +912,18 @@ runPeer opts = U.handle (\e -> myException e
unless (nonce == n1) do unless (nonce == n1) do
peer <- find @e (KnownPeerKey pip) id mpde <- find @e (KnownPeerKey pip) id
debug $ "received announce from" debug $ "received announce from"
<+> pretty pip <+> pretty pip
<+> pretty h <+> pretty h
case peer of case mpde of
Nothing -> do Nothing -> do
sendPing @e pip sendPing @e pip
-- TODO: enqueue-announce-from-unknown-peer? -- TODO: enqueue-announce-from-unknown-peer?
Just pd -> do Just (pde@(PeerDataExt {_peerData = pd})) -> do
banned <- peerBanned pip pd banned <- peerBanned pip pd
@ -893,11 +966,11 @@ runPeer opts = U.handle (\e -> myException e
[ makeResponse (blockSizeProto blk dontHandle onNoBlock) [ makeResponse (blockSizeProto blk dontHandle onNoBlock)
, makeResponse (blockChunksProto adapter) , makeResponse (blockChunksProto adapter)
, makeResponse blockAnnounceProto , makeResponse blockAnnounceProto
, makeResponse (withCredentials @e pc . peerHandShakeProto hshakeAdapter) , makeResponse (withCredentials @e pc . peerHandShakeProto hshakeAdapter penv)
, makeResponse (peerExchangeProto pexFilt) , makeResponse (peerExchangeProto pexFilt)
, makeResponse (refLogUpdateProto reflogAdapter) , makeResponse (refLogUpdateProto reflogAdapter)
, makeResponse (refLogRequestProto reflogReqAdapter) , makeResponse (refLogRequestProto reflogReqAdapter)
, makeResponse (peerMetaProto (mkPeerMeta conf)) , makeResponse (peerMetaProto peerMeta)
] ]
void $ liftIO $ waitAnyCancel workers void $ liftIO $ waitAnyCancel workers
@ -941,11 +1014,19 @@ runPeer opts = U.handle (\e -> myException e
let peersAction _ = do let peersAction _ = do
who <- thatPeer (Proxy @(RPC e)) who <- thatPeer (Proxy @(RPC e))
void $ liftIO $ async $ withPeerM penv $ do void $ liftIO $ async $ withPeerM penv $ do
forKnownPeers @e $ \p pd -> do forKnownPeers @e $ \p pde -> do
pa <- toPeerAddr p pa <- toPeerAddr p
let k = view peerSignKey pd let k = view (peerData . peerSignKey) pde
request who (RPCPeersAnswer @e pa k) request who (RPCPeersAnswer @e pa k)
let pexInfoAction :: RPC L4Proto -> ResponseM L4Proto (RpcM (ResourceT IO)) ()
pexInfoAction _ = do
who <- thatPeer (Proxy @(RPC e))
void $ liftIO $ async $ withPeerM penv $ do
-- FIXME: filter-pexinfo-entries
ps <- getAllPex2Peers
request who (RPCPexInfoAnswer @e ps)
let logLevelAction = \case let logLevelAction = \case
DebugOn True -> do DebugOn True -> do
setLogging @DEBUG debugPrefix setLogging @DEBUG debugPrefix
@ -981,21 +1062,25 @@ runPeer opts = U.handle (\e -> myException e
h <- liftIO $ getRef sto (RefLogKey @(Encryption e) puk) h <- liftIO $ getRef sto (RefLogKey @(Encryption e) puk)
request who (RPCRefLogGetAnswer @e h) request who (RPCRefLogGetAnswer @e h)
let arpc = RpcAdapter pokeAction let arpc = RpcAdapter
dieAction { rpcOnPoke = pokeAction
dontHandle , rpcOnDie = dieAction
dontHandle , rpcOnPokeAnswer = dontHandle
annAction , rpcOnPokeAnswerFull = dontHandle
pingAction , rpcOnAnnounce = annAction
dontHandle , rpcOnPing = pingAction
fetchAction , rpcOnPong = dontHandle
peersAction , rpcOnFetch = fetchAction
dontHandle , rpcOnPeers = peersAction
logLevelAction , rpcOnPeersAnswer = dontHandle
reflogUpdateAction , rpcOnPexInfo = pexInfoAction
reflogFetchAction , rpcOnPexInfoAnswer = dontHandle
reflogGetAction , rpcOnLogLevel = logLevelAction
dontHandle , rpcOnRefLogUpdate = reflogUpdateAction
, rpcOnRefLogFetch = reflogFetchAction
, rpcOnRefLogGet = reflogGetAction
, rpcOnRefLogGetAnsw = dontHandle
}
rpc <- async $ runRPC udp1 do rpc <- async $ runRPC udp1 do
runProto @e runProto @e
@ -1071,26 +1156,25 @@ withRPC o cmd = rpcClientMain o $ runResourceT do
refQ <- liftIO newTQueueIO refQ <- liftIO newTQueueIO
let adapter = let adapter = RpcAdapter
RpcAdapter dontHandle { rpcOnPoke = dontHandle
dontHandle , rpcOnDie = dontHandle
(liftIO . atomically . writeTQueue pokeQ) , rpcOnPokeAnswer = (liftIO . atomically . writeTQueue pokeQ)
(liftIO . atomically . writeTQueue pokeFQ) , rpcOnPokeAnswerFull = (liftIO . atomically . writeTQueue pokeFQ)
(const $ liftIO exitSuccess) , rpcOnAnnounce = (const $ liftIO exitSuccess)
(const $ notice "ping?") , rpcOnPing = (const $ notice "ping?")
(liftIO . atomically . writeTQueue pingQ) , rpcOnPong = (liftIO . atomically . writeTQueue pingQ)
dontHandle , rpcOnFetch = dontHandle
dontHandle , rpcOnPeers = dontHandle
, rpcOnPeersAnswer = (\(pa, k) -> Log.info $ pretty (AsBase58 k) <+> pretty pa)
(\(pa, k) -> Log.info $ pretty (AsBase58 k) <+> pretty pa , rpcOnPexInfo = dontHandle
) , rpcOnPexInfoAnswer = (\ps -> mapM_ (Log.info . pretty) ps)
, rpcOnLogLevel = dontHandle
dontHandle , rpcOnRefLogUpdate = dontHandle
dontHandle , rpcOnRefLogFetch = dontHandle
dontHandle , rpcOnRefLogGet = dontHandle
dontHandle , rpcOnRefLogGetAnsw = ( liftIO . atomically . writeTQueue refQ )
}
( liftIO . atomically . writeTQueue refQ )
prpc <- async $ runRPC udp1 do prpc <- async $ runRPC udp1 do
env <- ask env <- ask
@ -1132,6 +1216,10 @@ withRPC o cmd = rpcClientMain o $ runResourceT do
pause @'Seconds 1 pause @'Seconds 1
exitSuccess exitSuccess
RPCPexInfo{} -> liftIO do
pause @'Seconds 1
exitSuccess
RPCLogLevel{} -> liftIO exitSuccess RPCLogLevel{} -> liftIO exitSuccess
RPCRefLogUpdate{} -> liftIO do RPCRefLogUpdate{} -> liftIO do
@ -1166,6 +1254,7 @@ runRpcCommand opt = \case
ANNOUNCE h -> withRPC opt (RPCAnnounce h) ANNOUNCE h -> withRPC opt (RPCAnnounce h)
FETCH h -> withRPC opt (RPCFetch h) FETCH h -> withRPC opt (RPCFetch h)
PEERS -> withRPC opt RPCPeers PEERS -> withRPC opt RPCPeers
PEXINFO -> withRPC opt RPCPexInfo
SETLOG s -> withRPC opt (RPCLogLevel s) SETLOG s -> withRPC opt (RPCLogLevel s)
REFLOGUPDATE bs -> withRPC opt (RPCRefLogUpdate bs) REFLOGUPDATE bs -> withRPC opt (RPCRefLogUpdate bs)
REFLOGFETCH k -> withRPC opt (RPCRefLogFetch k) REFLOGFETCH k -> withRPC opt (RPCRefLogFetch k)

View File

@ -21,12 +21,16 @@ 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.Monad.Trans.State.Strict qualified as State
import Data.ByteString (ByteString) import Data.ByteString (ByteString)
import Data.Foldable hiding (find) import Data.Foldable hiding (find)
import Data.HashMap.Strict qualified as HashMap import Data.HashMap.Strict qualified as HashMap
import Data.Map.Strict qualified as Map
import Data.Maybe import Data.Maybe
import Data.Set qualified as Set
import Data.Text qualified as Text import Data.Text qualified as Text
import Data.Text.Encoding qualified as TE import Data.Text.Encoding qualified as TE
import Data.Time
import Data.Word import Data.Word
import Lens.Micro.Platform import Lens.Micro.Platform
import Network.HTTP.Simple (getResponseBody, httpLbs, parseRequest, getResponseStatus) import Network.HTTP.Simple (getResponseBody, httpLbs, parseRequest, getResponseStatus)
@ -53,14 +57,24 @@ fillPeerMeta mtcp probePeriod = do
debug "I'm fillPeerMeta" debug "I'm fillPeerMeta"
pl <- getPeerLocator @e pl <- getPeerLocator @e
pause @'Seconds 10 -- wait 'till everything calm down pause @'Seconds 5 -- wait 'till everything calm down
flip State.evalStateT Map.empty $ forever do
pause @'Seconds 12
forever $ (>> pause probePeriod) $ do ps <- knownPeers pl
now <- liftIO getCurrentTime
let pss = Set.fromList ps
psActual <- Map.filterWithKey (\k _ -> k `Set.member` pss) <$> State.get
let psNew = pss Set.\\ (Map.keysSet psActual)
let psReady = Map.keysSet . Map.filter (\t -> t < now) $ psActual
let ps' = Set.toList (psNew <> psReady)
(State.put . (<> psActual) . Map.fromList) $
(, now & addUTCTime (toNominalDiffTime probePeriod)) <$> ps'
ps <- knownPeers @e pl when ((not . null) ps') $ lift do
debug $ "fillPeerMeta peers:" <+> pretty ps debug $ "fillPeerMeta peers:" <+> pretty ps'
npi <- newPeerInfo for_ ps' $ \p -> do
for_ ps $ \p -> do npi <- newPeerInfo
pinfo <- fetch True npi (PeerInfoKey p) id pinfo <- fetch True npi (PeerInfoKey p) id
mmApiAddr <- liftIO $ readTVarIO (_peerHttpApiAddress pinfo) mmApiAddr <- liftIO $ readTVarIO (_peerHttpApiAddress pinfo)

View File

@ -9,6 +9,8 @@ import HBS2.Clock
import HBS2.Defaults import HBS2.Defaults
import HBS2.Events import HBS2.Events
import HBS2.Hash import HBS2.Hash
import HBS2.Merkle (AnnMetaData)
import HBS2.Net.Auth.Credentials
import HBS2.Net.IP.Addr import HBS2.Net.IP.Addr
import HBS2.Net.Proto import HBS2.Net.Proto
import HBS2.Net.Proto.Peer import HBS2.Net.Proto.Peer
@ -29,12 +31,15 @@ import Data.Foldable (for_)
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.Writer qualified as W
import Crypto.Saltine.Core.Box qualified as Encrypt
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.HashSet (HashSet) import Data.HashSet (HashSet)
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.List qualified as L
import Data.Maybe import Data.Maybe
import Lens.Micro.Platform import Lens.Micro.Platform
import Data.Hashable import Data.Hashable
@ -43,6 +48,7 @@ import Data.IntMap (IntMap)
import Data.IntSet (IntSet) import Data.IntSet (IntSet)
import Data.Text qualified as Text import Data.Text qualified as Text
import Data.Text.Encoding qualified as TE import Data.Text.Encoding qualified as TE
import Data.Word
data PeerInfo e = data PeerInfo e =
@ -72,23 +78,25 @@ makeLenses 'PeerInfo
newPeerInfo :: MonadIO m => m (PeerInfo e) newPeerInfo :: MonadIO m => m (PeerInfo e)
newPeerInfo = liftIO do newPeerInfo = liftIO do
PeerInfo <$> newTVarIO defBurst _peerBurst <- newTVarIO defBurst
<*> newTVarIO Nothing _peerBurstMax <- newTVarIO Nothing
<*> newTVarIO mempty _peerBurstSet <- newTVarIO mempty
<*> newTVarIO 0 _peerErrors <- newTVarIO 0
<*> newTVarIO 0 _peerErrorsLast <- newTVarIO 0
<*> newTVarIO 0 _peerErrorsPerSec <- newTVarIO 0
<*> newTVarIO 0 _peerLastWatched <- newTVarIO 0
<*> newTVarIO 0 _peerDownloaded <- newTVarIO 0
<*> newTVarIO 0 _peerDownloadedLast <- newTVarIO 0
<*> newTVarIO 0 _peerPingFailed <- newTVarIO 0
<*> newTVarIO 0 _peerDownloadedBlk <- newTVarIO 0
<*> newTVarIO 0 _peerDownloadFail <- newTVarIO 0
<*> newTVarIO 0 _peerDownloadMiss <- newTVarIO 0
<*> newTVarIO [] _peerRTTBuffer <- newTVarIO []
<*> newTVarIO (Left 0) -- Acts like a circular buffer.
<*> newTVarIO 0 _peerHttpApiAddress <- newTVarIO (Left 0)
<*> newTVarIO Nothing _peerHttpDownloaded <- newTVarIO 0
_peerMeta <- newTVarIO Nothing
pure PeerInfo {..}
type instance SessionData e (PeerInfo e) = PeerInfo e type instance SessionData e (PeerInfo e) = PeerInfo e
@ -351,13 +359,13 @@ forKnownPeers :: forall e m . ( MonadIO m
, Sessions e (KnownPeer e) m , Sessions e (KnownPeer e) m
, HasPeer e , HasPeer e
) )
=> ( Peer e -> PeerData e -> m () ) -> m () => ( Peer e -> PeerDataExt e -> m () ) -> m ()
forKnownPeers m = do forKnownPeers m = do
pl <- getPeerLocator @e pl <- getPeerLocator @e
pips <- knownPeers @e pl pips <- knownPeers @e pl
for_ pips $ \p -> do for_ pips $ \p -> do
pd' <- find (KnownPeerKey p) id mpde <- find (KnownPeerKey p) id
maybe1 pd' (pure ()) (m p) maybe1 mpde (pure ()) (m p)
getKnownPeers :: forall e m . ( MonadIO m getKnownPeers :: forall e m . ( MonadIO m
, HasPeerLocator e m , HasPeerLocator e m
@ -374,16 +382,27 @@ getKnownPeers = do
maybe1 pd' (pure mempty) (const $ pure [p]) maybe1 pd' (pure mempty) (const $ pure [p])
pure $ mconcat r pure $ mconcat r
mkPeerMeta conf = do mkPeerMeta :: PeerConfig -> PeerEnv e -> AnnMetaData
let mHttpPort = cfgValue @PeerHttpPortKey conf <&> fromIntegral mkPeerMeta conf penv = do
let mTcpPort = let mHttpPort :: Maybe Integer
mHttpPort = cfgValue @PeerHttpPortKey conf <&> fromIntegral
let mTcpPort :: Maybe Word16
mTcpPort =
( (
fmap (\(L4Address _ (IPAddrPort (_, p))) -> p) fmap (\(L4Address _ (IPAddrPort (_, p))) -> p)
. fromStringMay @(PeerAddr L4Proto) . fromStringMay @(PeerAddr L4Proto)
) )
=<< cfgValue @PeerListenTCPKey conf =<< cfgValue @PeerListenTCPKey conf
annMetaFromPeerMeta . PeerMeta . catMaybes $ -- let useEncryption = True -- move to config
[ mHttpPort <&> \p -> ("http-port", TE.encodeUtf8 . Text.pack . show $ p) annMetaFromPeerMeta . PeerMeta $ W.execWriter do
, mTcpPort <&> \p -> ("listen-tcp", TE.encodeUtf8 . Text.pack . show $ p) mHttpPort `forM` \p -> elem "http-port" (TE.encodeUtf8 . Text.pack . show $ p)
] mTcpPort `forM` \p -> elem "listen-tcp" (TE.encodeUtf8 . Text.pack . show $ p)
-- when useEncryption do
-- elem "ekey" (TE.encodeUtf8 . Text.pack . show $
-- (Encrypt.publicKey . _envAsymmetricKeyPair) penv
-- -- mayby sign this pubkey by node key ?
-- )
where
elem k = W.tell . L.singleton . (k ,)

View File

@ -1,37 +1,64 @@
{-# Language TemplateHaskell #-} {-# Language TemplateHaskell #-}
module ProxyMessaging module ProxyMessaging
( ProxyMessaging ( ProxyMessaging
, PlainProxyMessaging(..)
, newProxyMessaging , newProxyMessaging
, runProxyMessaging , runProxyMessaging
, proxyEncryptionKeys
, sendToPlainProxyMessaging
) where ) where
import HBS2.Prelude.Plated import HBS2.Prelude.Plated
import HBS2.Net.Messaging import HBS2.Net.Messaging
import HBS2.Clock import HBS2.Clock
import HBS2.Crypto
import HBS2.Net.Auth.Credentials
import HBS2.Net.Proto.Definition ()
import HBS2.Net.Proto.Peer
import HBS2.Net.Proto.Types import HBS2.Net.Proto.Types
import HBS2.Net.Messaging.UDP import HBS2.Net.Messaging.UDP
import HBS2.Net.Messaging.TCP import HBS2.Net.Messaging.TCP
import HBS2.System.Logger.Simple import HBS2.System.Logger.Simple
import Crypto.Saltine.Class as SCl
import Crypto.Saltine.Core.Box qualified as Encrypt
import Codec.Serialise
import Control.Applicative
import Control.Arrow hiding ((<+>))
import Control.Concurrent.Async import Control.Concurrent.Async
import Control.Concurrent.STM import Control.Concurrent.STM
import Control.Concurrent.STM.TQueue import Control.Concurrent.STM.TQueue
import Data.ByteString.Lazy (ByteString) import Control.Monad.Trans.Maybe
import Data.ByteString (ByteString)
import Data.ByteString qualified as BS
import Data.ByteString.Lazy qualified as LBS import Data.ByteString.Lazy qualified as LBS
import Data.Maybe
import Data.String.Conversions (cs)
import Data.List qualified as L import Data.List qualified as L
import Data.Map (Map)
import Data.Map qualified as Map
import Lens.Micro.Platform import Lens.Micro.Platform
import Control.Monad import Control.Monad
-- TODO: protocol-encryption-goes-here -- TODO: protocol-encryption-goes-here
data ProxyMessaging = data ProxyMessaging =
ProxyMessaging ProxyMessaging
{ _proxyUDP :: MessagingUDP { _proxyUDP :: MessagingUDP
, _proxyTCP :: Maybe MessagingTCP , _proxyTCP :: Maybe MessagingTCP
, _proxyAnswers :: TQueue (From L4Proto, ByteString) , _proxyAnswers :: TQueue (From L4Proto, LBS.ByteString)
, _proxyEncryptionKeys :: TVar (Map (Peer L4Proto) (CommonSecret (Encryption L4Proto)))
} }
newtype PlainProxyMessaging = PlainProxyMessaging ProxyMessaging
-- 1 нода X создаёт себе Encrypt.Keypair
-- 2 подписывает из него публичный ключ ключом подписи ноды X и отправляет ноде Y
-- 3 нода Y получила Публичный ключ ноды X, создала симметричный Key,
-- зашифровала его для полученного Публичного ключа ноды X и отравила ей
makeLenses 'ProxyMessaging makeLenses 'ProxyMessaging
newProxyMessaging :: forall m . MonadIO m newProxyMessaging :: forall m . MonadIO m
@ -42,6 +69,7 @@ newProxyMessaging :: forall m . MonadIO m
newProxyMessaging u t = liftIO do newProxyMessaging u t = liftIO do
ProxyMessaging u t ProxyMessaging u t
<$> newTQueueIO <$> newTQueueIO
<*> newTVarIO mempty
runProxyMessaging :: forall m . MonadIO m runProxyMessaging :: forall m . MonadIO m
=> ProxyMessaging => ProxyMessaging
@ -66,23 +94,82 @@ runProxyMessaging env = liftIO do
liftIO $ mapM_ waitCatch [u,t] liftIO $ mapM_ waitCatch [u,t]
instance Messaging ProxyMessaging L4Proto ByteString where instance Messaging PlainProxyMessaging L4Proto LBS.ByteString where
sendTo = sendToPlainProxyMessaging
receive (PlainProxyMessaging bus) = receive bus
sendTo bus t@(To whom) f m = do sendToPlainProxyMessaging :: (MonadIO m)
-- sendTo (view proxyUDP bus) t f m => PlainProxyMessaging
-- trace $ "PROXY: SEND" <+> pretty whom -> To L4Proto
-> From L4Proto
-> LBS.ByteString
-- -> AnyMessage LBS.ByteString L4Proto
-> m ()
sendToPlainProxyMessaging (PlainProxyMessaging bus) t@(To whom) proto msg = do
let udp = view proxyUDP bus let udp = view proxyUDP bus
case view sockType whom of case view sockType whom of
UDP -> sendTo udp t f m UDP -> sendTo udp t proto msg
TCP -> maybe1 (view proxyTCP bus) none $ \tcp -> do TCP -> maybe1 (view proxyTCP bus) none $ \tcp -> do
sendTo tcp t f m sendTo tcp t proto msg
receive bus _ = liftIO do instance Messaging ProxyMessaging L4Proto LBS.ByteString where
sendTo = sendToProxyMessaging
receive = receiveFromProxyMessaging
sendToProxyMessaging bus t@(To whom) proto msg = do
-- sendTo (view proxyUDP bus) t proto msg
-- trace $ "PROXY: SEND" <+> pretty whom
encKey <- Map.lookup whom <$> (liftIO . readTVarIO) (view proxyEncryptionKeys bus)
cf <- case encKey of
Nothing -> do
trace $ "ENCRYPTION SEND: sending plain message to" <+> pretty whom
pure id
Just k -> do
trace $ "ENCRYPTION SEND: sending encrypted message to" <+> pretty whom <+> "with key" <+> viaShow k
boxAfterNMLazy k <$> liftIO Encrypt.newNonce
sendTo (PlainProxyMessaging bus) t proto (cf msg)
receiveFromProxyMessaging :: MonadIO m
=> ProxyMessaging -> To L4Proto -> m [(From L4Proto, LBS.ByteString)]
receiveFromProxyMessaging bus _ = liftIO do
-- trace "PROXY: RECEIVE" -- trace "PROXY: RECEIVE"
-- receive (view proxyUDP bus) w -- receive (view proxyUDP bus) w
let answ = view proxyAnswers bus let answ = view proxyAnswers bus
atomically $ do rs <- atomically $ liftM2 (:) (readTQueue answ) (flushTQueue answ)
r <- readTQueue answ fmap catMaybes $ forM rs \(w@(From whom), msg) -> do
rs <- flushTQueue answ encKeys <- (liftIO . readTVarIO) (view proxyEncryptionKeys bus)
pure (r:rs) fmap (w, ) <$> dfm whom (Map.lookup whom encKeys) msg
where
dfm :: Peer L4Proto -> Maybe Encrypt.CombinedKey -> LBS.ByteString -> IO (Maybe LBS.ByteString)
dfm = \whom mk msg -> case mk of
Nothing -> do
trace $ "ENCRYPTION RECEIVE: we do not have a key to decode" <+> pretty whom
pure (Just msg)
Just k -> runMaybeT $ (<|> pure msg) $ do
trace $ "ENCRYPTION RECEIVE: we have a key to decode from" <+> pretty whom <+> ":" <+> viaShow k
case ((extractNonce . cs) msg) of
Nothing -> do
trace $ "ENCRYPTION RECEIVE: can not extract nonce from" <+> pretty whom <+> "message" <+> viaShow msg
pure msg
Just (nonce, msg') ->
((MaybeT . pure) (boxOpenAfterNMLazy k nonce msg')
<* (trace $ "ENCRYPTION RECEIVE: message successfully decoded from" <+> pretty whom)
)
<|>
(do
(trace $ "ENCRYPTION RECEIVE: can not decode message from" <+> pretty whom)
-- А будем-ка мы просто передавать сообщение дальше как есть, если не смогли расшифровать
pure msg
-- -- Попытаться десериализовать сообщение как PeerPing или PeerPingCrypted
-- case deserialiseOrFail msg of
-- Right (_ :: PeerHandshake L4Proto) -> do
-- trace $ "ENCRYPTION RECEIVE: plain message decoded as PeerHandshake" <+> pretty whom
-- pure msg
-- Left _ -> do
-- trace $ "ENCRYPTION RECEIVE: failed" <+> pretty whom
-- mzero
)

View File

@ -33,6 +33,8 @@ data RPC e =
| RPCFetch (Hash HbSync) | RPCFetch (Hash HbSync)
| RPCPeers | RPCPeers
| RPCPeersAnswer (PeerAddr e) (PubKey 'Sign (Encryption e)) | RPCPeersAnswer (PeerAddr e) (PubKey 'Sign (Encryption e))
| RPCPexInfo
| RPCPexInfoAnswer [PeerAddr L4Proto]
| RPCLogLevel SetLogging | RPCLogLevel SetLogging
| RPCRefLogUpdate ByteString | RPCRefLogUpdate ByteString
| RPCRefLogFetch (PubKey 'Sign (Encryption e)) | RPCRefLogFetch (PubKey 'Sign (Encryption e))
@ -40,6 +42,11 @@ data RPC e =
| RPCRefLogGetAnswer (Maybe (Hash HbSync)) | RPCRefLogGetAnswer (Maybe (Hash HbSync))
deriving stock (Generic) deriving stock (Generic)
deriving instance
( Show (PubKey 'Sign (Encryption e))
, Show (PeerAddr e)
) => Show (RPC e)
instance (Serialise (PeerAddr e), Serialise (PubKey 'Sign (Encryption e))) => Serialise (RPC e) instance (Serialise (PeerAddr e), Serialise (PubKey 'Sign (Encryption e))) => Serialise (RPC e)
instance HasProtocol L4Proto (RPC L4Proto) where instance HasProtocol L4Proto (RPC L4Proto) where
@ -69,6 +76,8 @@ data RpcAdapter e m =
, rpcOnFetch :: Hash HbSync -> m () , rpcOnFetch :: Hash HbSync -> m ()
, rpcOnPeers :: RPC e -> m () , rpcOnPeers :: RPC e -> m ()
, rpcOnPeersAnswer :: (PeerAddr e, PubKey 'Sign (Encryption e)) -> m () , rpcOnPeersAnswer :: (PeerAddr e, PubKey 'Sign (Encryption e)) -> m ()
, rpcOnPexInfo :: RPC e -> m ()
, rpcOnPexInfoAnswer :: [PeerAddr L4Proto] -> m ()
, rpcOnLogLevel :: SetLogging -> m () , rpcOnLogLevel :: SetLogging -> m ()
, rpcOnRefLogUpdate :: ByteString -> m () , rpcOnRefLogUpdate :: ByteString -> m ()
, rpcOnRefLogFetch :: PubKey 'Sign (Encryption e) -> m () , rpcOnRefLogFetch :: PubKey 'Sign (Encryption e) -> m ()
@ -124,6 +133,8 @@ rpcHandler adapter = \case
(RPCFetch h) -> rpcOnFetch adapter h (RPCFetch h) -> rpcOnFetch adapter h
p@RPCPeers{} -> rpcOnPeers adapter p p@RPCPeers{} -> rpcOnPeers adapter p
(RPCPeersAnswer pa k) -> rpcOnPeersAnswer adapter (pa,k) (RPCPeersAnswer pa k) -> rpcOnPeersAnswer adapter (pa,k)
p@RPCPexInfo{} -> rpcOnPexInfo adapter p
(RPCPexInfoAnswer pa) -> rpcOnPexInfoAnswer adapter pa
(RPCLogLevel l) -> rpcOnLogLevel adapter l (RPCLogLevel l) -> rpcOnLogLevel adapter l
(RPCRefLogUpdate bs) -> rpcOnRefLogUpdate adapter bs (RPCRefLogUpdate bs) -> rpcOnRefLogUpdate adapter bs
(RPCRefLogFetch e) -> rpcOnRefLogFetch adapter e (RPCRefLogFetch e) -> rpcOnRefLogFetch adapter e

View File

@ -48,6 +48,7 @@ common common-deps
, stm , stm
, streaming , streaming
, sqlite-simple , sqlite-simple
, time
, temporary , temporary
, text , text
, timeit , timeit
@ -59,6 +60,7 @@ common common-deps
, filelock , filelock
, ekg-core , ekg-core
, scotty , scotty
, string-conversions
, warp , warp
, http-conduit , http-conduit
, http-types , http-types
@ -103,6 +105,7 @@ common shared-properties
, MultiParamTypeClasses , MultiParamTypeClasses
, OverloadedStrings , OverloadedStrings
, QuasiQuotes , QuasiQuotes
, RecordWildCards
, ScopedTypeVariables , ScopedTypeVariables
, StandaloneDeriving , StandaloneDeriving
, TupleSections , TupleSections

View File

@ -568,6 +568,7 @@ main = join . customExecParser (prefs showHelpOnError) $
<> command "lref-update" (info pUpdateLRef (progDesc "updates a linear ref")) <> command "lref-update" (info pUpdateLRef (progDesc "updates a linear ref"))
<> command "reflog" (info pReflog (progDesc "reflog commands")) <> command "reflog" (info pReflog (progDesc "reflog commands"))
-- <> command "lref-del" (info pDelLRef (progDesc "removes a linear ref from node linear ref list")) -- <> command "lref-del" (info pDelLRef (progDesc "removes a linear ref from node linear ref list"))
<> command "showpex" (info pReflog (progDesc "reflog commands"))
) )
common = do common = do