Skip to content

Commit 6d04e79

Browse files
authored
feat(simulation): add infrastructure for generic channel creation (#185)
1 parent 8f6a8aa commit 6d04e79

24 files changed

+237
-168
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# yaml-language-server: $schema=./config.schema.json
2+
3+
################################################################################
4+
# Configuration for least realistic simulation
5+
################################################################################
6+
7+
relay-strategy: "request-from-first"
8+
tcp-congestion-control: false
9+
multiplex-mini-protocols: false

simulation/src/Chan.hs

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,75 @@
1+
{-# LANGUAGE FlexibleContexts #-}
2+
{-# LANGUAGE LambdaCase #-}
3+
{-# LANGUAGE RecordWildCards #-}
4+
15
module Chan (
6+
ConnectionConfig (..),
7+
newConnectionBundle,
8+
mkConnectionConfig,
29
module Chan.Core,
310
module Chan.Driver,
4-
module Chan.Mux,
5-
module Chan.TCP,
11+
-- Chan.Mux
12+
Bytes,
13+
ConnectionBundle (..),
14+
TcpConnProps (..),
15+
TcpEvent (..),
16+
LabelTcpDir (..),
17+
MessageSize (..),
18+
ToFromBundleMsg (..),
619
) where
720

821
import Chan.Core
922
import Chan.Driver
1023
import Chan.Mux
1124
import Chan.TCP
25+
import Control.Concurrent.Class.MonadMVar (MonadMVar (..))
26+
import Control.Monad.Class.MonadAsync (MonadAsync)
27+
import Control.Monad.Class.MonadFork (MonadFork)
28+
import Control.Tracer (Contravariant (contramap), Tracer)
29+
import Data.Maybe (fromMaybe)
30+
import ModelTCP (kilobytes, mkTcpConnProps)
31+
import TimeCompat (DiffTime, MonadDelay, MonadMonotonicTimeNSec, MonadTime)
32+
33+
data ConnectionConfig = ConnectionConfig
34+
{ transportConfig :: !TransportConfig
35+
, mux :: !Bool
36+
}
37+
38+
mkConnectionConfig :: Bool -> Bool -> DiffTime -> Maybe Bytes -> ConnectionConfig
39+
mkConnectionConfig tcp mux tcpLatency maybeTcpBandwidth = ConnectionConfig{..}
40+
where
41+
transportConfig
42+
| tcp = TransportTcp (mkTcpConnProps tcpLatency (fromMaybe defaultTcpBandwidth maybeTcpBandwidth))
43+
| otherwise = TransportBasic
44+
defaultTcpBandwidth = (kilobytes 1000)
45+
46+
data TransportConfig
47+
= TransportBasic
48+
| TransportTcp !TcpConnProps
49+
50+
newConnectionBundle ::
51+
forall bundle m.
52+
(ConnectionBundle bundle, MonadTime m, MonadMonotonicTimeNSec m, MonadDelay m, MonadAsync m, MessageSize (BundleMsg bundle), MonadMVar m, MonadFork m) =>
53+
Tracer m (LabelTcpDir (TcpEvent (BundleMsg bundle))) ->
54+
ConnectionConfig ->
55+
m (bundle (Chan m), bundle (Chan m))
56+
newConnectionBundle tracer = \case
57+
ConnectionConfig TransportBasic _mux@False ->
58+
error "Unsupported configuration (no TCP, no mux)"
59+
ConnectionConfig TransportBasic _mux@True ->
60+
error "Unsupported configuration (no TCP)"
61+
ConnectionConfig (TransportTcp _tcpConnProps) _mux@False ->
62+
error "Unsupported configuration (no mux)"
63+
ConnectionConfig (TransportTcp tcpConnProps) _mux@True ->
64+
newConnectionBundleTCPMux tracer tcpConnProps
65+
66+
newConnectionBundleTCPMux ::
67+
forall bundle m.
68+
(ConnectionBundle bundle, MonadTime m, MonadMonotonicTimeNSec m, MonadDelay m, MonadAsync m, MessageSize (BundleMsg bundle), MonadMVar m, MonadFork m) =>
69+
Tracer m (LabelTcpDir (TcpEvent (BundleMsg bundle))) ->
70+
TcpConnProps ->
71+
m (bundle (Chan m), bundle (Chan m))
72+
newConnectionBundleTCPMux tracer tcpprops = do
73+
let tracer' = contramap ((fmap . fmap) fromBearerMsg) tracer
74+
(mA, mB) <- newConnectionTCP tracer' tcpprops
75+
(,) <$> newMuxChan mA <*> newMuxChan mB

simulation/src/Chan/Mux.hs

Lines changed: 42 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -10,38 +10,26 @@
1010
{-# LANGUAGE TypeFamilies #-}
1111

1212
module Chan.Mux (
13-
ToFromMuxMsg (..),
14-
MuxBundle (..),
15-
newConnectionBundleTCP,
13+
ToFromBundleMsg (..),
14+
ConnectionBundle (..),
15+
fromBearerMsg,
16+
newMuxChan,
1617
) where
1718

1819
import Chan.Core (Chan (..))
19-
import Chan.TCP (
20-
LabelTcpDir,
21-
MessageSize (..),
22-
TcpConnProps,
23-
TcpEvent,
24-
newConnectionTCP,
25-
)
20+
import Chan.TCP (MessageSize (..))
2621
import qualified Control.Category as Cat
27-
import Control.Concurrent.Class.MonadMVar (
28-
MonadMVar (MVar, newMVar, withMVar),
29-
)
22+
import Control.Concurrent.Class.MonadMVar (MonadMVar (..))
3023
import Control.Monad (forever)
31-
import Control.Monad.Class.MonadAsync (MonadAsync)
3224
import Control.Monad.Class.MonadFork (MonadFork (forkIO))
33-
import Control.Tracer (Contravariant (contramap), Tracer)
3425
import Data.Array (Array, listArray, (!))
35-
import Data.Dynamic (Dynamic, Typeable, fromDynamic, toDyn)
36-
import Data.Maybe (fromJust)
3726
import STMCompat
38-
import TimeCompat
3927

40-
class MuxBundle bundle where
41-
type MuxMsg bundle
42-
toFromMuxMsgBundle :: bundle (ToFromMuxMsg (MuxMsg bundle))
28+
class ConnectionBundle bundle where
29+
type BundleMsg bundle
30+
toFromBundleMsgBundle :: bundle (ToFromBundleMsg (BundleMsg bundle))
4331

44-
traverseMuxBundle ::
32+
traverseConnectionBundle ::
4533
Monad m =>
4634
(forall a. f a -> m (g a)) ->
4735
bundle f ->
@@ -50,24 +38,24 @@ class MuxBundle bundle where
5038
-- | Injection, projection, between a common mux message type, and an
5139
-- individual message type. The following must hold:
5240
--
53-
-- > fromMuxMsg (toMuxMsg x) = x
41+
-- > fromBundleMsg (toBundleMsg x) = x
5442
--
55-
-- But 'fromMuxMsg' is not required to be defined outside of the image of
56-
-- 'toMuxMsg'. For example, a valid implementation would be:
43+
-- But 'fromBundleMsg' is not required to be defined outside of the image of
44+
-- 'toBundleMsg'. For example, a valid implementation would be:
5745
--
58-
-- > ToFromMuxMsg toDynamic (fromJust . fromDynamic)
59-
data ToFromMuxMsg mm a
60-
= ToFromMuxMsg
61-
{ toMuxMsg :: a -> mm
62-
, fromMuxMsg :: mm -> a
46+
-- > ToFromBundleMsg toDynamic (fromJust . fromDynamic)
47+
data ToFromBundleMsg mm a
48+
= ToFromBundleMsg
49+
{ toBundleMsg :: a -> mm
50+
, fromBundleMsg :: mm -> a
6351
}
6452

65-
instance Cat.Category ToFromMuxMsg where
66-
id = ToFromMuxMsg id id
67-
(.) (ToFromMuxMsg f f') (ToFromMuxMsg g g') = ToFromMuxMsg (g . f) (f' . g')
53+
instance Cat.Category ToFromBundleMsg where
54+
id = ToFromBundleMsg id id
55+
(.) (ToFromBundleMsg f f') (ToFromBundleMsg g g') = ToFromBundleMsg (g . f) (f' . g')
6856

69-
-- dynToFromMuxMsg :: Typeable a => ToFromMuxMsg Dynamic a
70-
-- dynToFromMuxMsg = ToFromMuxMsg toDyn (fromJust . fromDynamic)
57+
-- dynToFromBundleMsg :: Typeable a => ToFromBundleMsg Dynamic a
58+
-- dynToFromBundleMsg = ToFromBundleMsg toDyn (fromJust . fromDynamic)
7159

7260
data BearerMsg a = BearerMsg !Int a
7361

@@ -79,24 +67,24 @@ instance MessageSize a => MessageSize (BearerMsg a) where
7967

8068
newMuxChan ::
8169
forall bundle m.
82-
(MuxBundle bundle, MonadMVar m, MonadSTM m, MonadFork m) =>
83-
Chan m (BearerMsg (MuxMsg bundle)) ->
70+
(ConnectionBundle bundle, MonadMVar m, MonadSTM m, MonadFork m) =>
71+
Chan m (BearerMsg (BundleMsg bundle)) ->
8472
m (bundle (Chan m))
8573
newMuxChan bearer = do
8674
sendLock <- newMVar ()
87-
-- Bit of a hack to use these TVars, could run the traverseMuxBundle
75+
-- Bit of a hack to use these TVars, could run the traverseConnectionBundle
8876
-- in a reader+state monad instead. That'd be cleaner.
8977
recvQueuesAccum <- newTVarIO []
9078
recvQueuesIx <- newTVarIO 0
9179
chans <-
92-
traverseMuxBundle
80+
traverseConnectionBundle
9381
( newMuxChanSingle @bundle
9482
bearer
9583
sendLock
9684
recvQueuesIx
9785
recvQueuesAccum
9886
)
99-
toFromMuxMsgBundle
87+
toFromBundleMsgBundle
10088
recvQueues <- reverse <$> readTVarIO recvQueuesAccum
10189
let recvQueues' = listArray (0, length recvQueues - 1) recvQueues
10290
_ <- forkIO $ demuxer @bundle bearer recvQueues'
@@ -105,29 +93,29 @@ newMuxChan bearer = do
10593
newMuxChanSingle ::
10694
forall bundle m a.
10795
(MonadMVar m, MonadSTM m) =>
108-
Chan m (BearerMsg (MuxMsg bundle)) ->
96+
Chan m (BearerMsg (BundleMsg bundle)) ->
10997
MVar m () ->
11098
TVar m Int ->
111-
TVar m [RecvQueue m (MuxMsg bundle)] ->
112-
ToFromMuxMsg (MuxMsg bundle) a ->
99+
TVar m [RecvQueue m (BundleMsg bundle)] ->
100+
ToFromBundleMsg (BundleMsg bundle) a ->
113101
m (Chan m a)
114102
newMuxChanSingle
115103
bearer
116104
sendLock
117105
recvQueuesIx
118106
recvQueuesAccum
119-
ToFromMuxMsg{..} = do
107+
ToFromBundleMsg{..} = do
120108
queue <- newTQueueIO
121109
i <- atomically $ do
122-
modifyTVar recvQueuesAccum (RecvQueue fromMuxMsg queue :)
110+
modifyTVar recvQueuesAccum (RecvQueue fromBundleMsg queue :)
123111
i <- readTVar recvQueuesIx
124112
writeTVar recvQueuesIx $! (i + 1)
125113
return i
126114
return
127115
Chan
128116
{ readChan = atomically (readTQueue queue)
129117
, writeChan = \msg ->
130-
let !muxmsg = BearerMsg i (toMuxMsg msg)
118+
let !muxmsg = BearerMsg i (toBundleMsg msg)
131119
in withMVar sendLock $ \_ -> writeChan bearer muxmsg
132120
}
133121

@@ -137,8 +125,8 @@ data RecvQueue m mm where
137125
demuxer ::
138126
forall bundle m.
139127
MonadSTM m =>
140-
Chan m (BearerMsg (MuxMsg bundle)) ->
141-
Array Int (RecvQueue m (MuxMsg bundle)) ->
128+
Chan m (BearerMsg (BundleMsg bundle)) ->
129+
Array Int (RecvQueue m (BundleMsg bundle)) ->
142130
m ()
143131
demuxer bearer queues =
144132
forever $ do
@@ -147,17 +135,6 @@ demuxer bearer queues =
147135
RecvQueue convert queue ->
148136
atomically $ writeTQueue queue $! convert msg
149137

150-
newConnectionBundleTCP ::
151-
forall bundle m.
152-
(MuxBundle bundle, MonadTime m, MonadMonotonicTimeNSec m, MonadDelay m, MonadAsync m, MessageSize (MuxMsg bundle), MonadMVar m, MonadFork m) =>
153-
Tracer m (LabelTcpDir (TcpEvent (MuxMsg bundle))) ->
154-
TcpConnProps ->
155-
m (bundle (Chan m), bundle (Chan m))
156-
newConnectionBundleTCP tracer tcpprops = do
157-
let tracer' = contramap ((fmap . fmap) fromBearerMsg) tracer
158-
(mA, mB) <- newConnectionTCP tracer' tcpprops
159-
(,) <$> newMuxChan mA <*> newMuxChan mB
160-
161138
data ExampleBundle f = ExampleBundle
162139
{ exampleFoo :: f Int
163140
, exampleBar :: f Bool
@@ -167,16 +144,16 @@ data ExampleMsg
167144
= MsgFoo {fromMsgFoo :: Int}
168145
| MsgBar {fromMsgBar :: Bool}
169146

170-
instance MuxBundle ExampleBundle where
171-
type MuxMsg ExampleBundle = ExampleMsg
147+
instance ConnectionBundle ExampleBundle where
148+
type BundleMsg ExampleBundle = ExampleMsg
172149

173-
toFromMuxMsgBundle =
150+
toFromBundleMsgBundle =
174151
ExampleBundle
175-
{ exampleFoo = ToFromMuxMsg MsgFoo fromMsgFoo
176-
, exampleBar = ToFromMuxMsg MsgBar fromMsgBar
152+
{ exampleFoo = ToFromBundleMsg MsgFoo fromMsgFoo
153+
, exampleBar = ToFromBundleMsg MsgBar fromMsgBar
177154
}
178155

179-
traverseMuxBundle f ExampleBundle{..} =
156+
traverseConnectionBundle f ExampleBundle{..} =
180157
ExampleBundle
181158
<$> f exampleFoo
182159
<*> f exampleBar

simulation/src/ExamplesRelay.hs

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,27 @@
11
module ExamplesRelay where
22

33
import Data.Word (Word8)
4-
import RelayProtocol
5-
import SimRelay
6-
import SimTCPLinks (kilobytes, mkTcpConnProps)
4+
import ModelTCP (kilobytes, mkTcpConnProps)
5+
import RelayProtocol (BlockRelayMessage (..), BlockTTL)
6+
import SimRelay (
7+
PacketGenerationPattern (UniformGenerationPattern),
8+
TestBlock (TestBlock),
9+
TestBlockId (..),
10+
traceRelayLink1,
11+
traceRelayLink4,
12+
traceRelayLink4Asymmetric,
13+
)
714
import System.Random (mkStdGen, uniform)
8-
import Viz
9-
import VizSimRelay
15+
import Viz (
16+
Layout (Layout, LayoutReqSize),
17+
Visualization (..),
18+
slowmoVisualization,
19+
)
20+
import VizSimRelay (
21+
RelaySimVizConfig (..),
22+
relaySimVizModel,
23+
relaySimVizRender,
24+
)
1025

1126
example1 :: Visualization
1227
example1 =

simulation/src/ExamplesRelayP2P.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ module ExamplesRelayP2P where
55
import Data.Functor.Contravariant (Contravariant (contramap))
66
import Data.Maybe (fromMaybe)
77
import Data.Word (Word8)
8+
import ModelTCP (kilobytes, mkTcpConnProps)
89
import P2P (P2PTopographyCharacteristics (..), genArbitraryP2PTopography)
910
import RelayProtocol
1011
import SimRelay
1112
import SimRelayP2P
12-
import SimTCPLinks (kilobytes, mkTcpConnProps)
1313
import SimTypes
1414
import System.Random (mkStdGen, uniform)
1515
import TimeCompat (secondsToDiffTime)

simulation/src/LeiosProtocol/Short.hs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@
1414
{-# LANGUAGE TypeApplications #-}
1515
{-# LANGUAGE NoFieldSelectors #-}
1616

17-
module LeiosProtocol.Short (module LeiosProtocol.Short, DiffusionStrategy (..))
18-
where
17+
module LeiosProtocol.Short (module LeiosProtocol.Short, DiffusionStrategy (..)) where
1918

19+
import Chan (mkConnectionConfig)
2020
import Control.Exception (assert)
2121
import Control.Monad (guard)
2222
import Data.Kind
@@ -170,6 +170,7 @@ convertConfig disk =
170170
, blockGenerationDelay = \(Block _ body) ->
171171
durationMsToDiffTime disk.rbGenerationCpuTimeMs
172172
+ sum (map (certificateGeneration . snd) body.endorseBlocks)
173+
, configureConnection = mkConnectionConfig (tcpCongestionControl disk) (multiplexMiniProtocols disk)
173174
}
174175
certificateSize (Certificate votesMap) =
175176
fromIntegral $

simulation/src/LeiosProtocol/Short/Node.hs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -170,20 +170,20 @@ instance MessageSize LeiosMessage where
170170
RelayVote m -> messageSizeBytes m
171171
PraosMsg m -> messageSizeBytes m
172172

173-
instance MuxBundle Leios where
174-
type MuxMsg Leios = LeiosMessage
175-
toFromMuxMsgBundle =
173+
instance ConnectionBundle Leios where
174+
type BundleMsg Leios = LeiosMessage
175+
toFromBundleMsgBundle =
176176
Leios
177-
{ protocolIB = ToFromMuxMsg RelayIB (.fromRelayIB)
178-
, protocolEB = ToFromMuxMsg RelayEB (.fromRelayEB)
179-
, protocolVote = ToFromMuxMsg RelayVote (.fromRelayVote)
180-
, protocolPraos = case toFromMuxMsgBundle @(PraosNode.Praos RankingBlockBody) of
177+
{ protocolIB = ToFromBundleMsg RelayIB (.fromRelayIB)
178+
, protocolEB = ToFromBundleMsg RelayEB (.fromRelayEB)
179+
, protocolVote = ToFromBundleMsg RelayVote (.fromRelayVote)
180+
, protocolPraos = case toFromBundleMsgBundle @(PraosNode.Praos RankingBlockBody) of
181181
PraosNode.Praos a b -> PraosNode.Praos (p >>> a) (p >>> b)
182182
}
183183
where
184-
p = ToFromMuxMsg PraosMsg (.fromPraosMsg)
184+
p = ToFromBundleMsg PraosMsg (.fromPraosMsg)
185185

186-
traverseMuxBundle f (Leios a b c d) = Leios <$> f a <*> f b <*> f c <*> traverseMuxBundle f d
186+
traverseConnectionBundle f (Leios a b c d) = Leios <$> f a <*> f b <*> f c <*> traverseConnectionBundle f d
187187

188188
--------------------------------------------------------------
189189

0 commit comments

Comments
 (0)