@@ -12,13 +12,14 @@ module Ouroboros.Consensus.MiniProtocol.ObjectDiffusion.Outbound
12
12
) where
13
13
14
14
import Control.Exception (assert )
15
- import Control.Monad (unless , when , forM )
15
+ import Control.Monad (forM , unless , when )
16
16
import Control.Monad.Class.MonadSTM
17
17
import Control.Monad.Class.MonadThrow
18
18
import Control.Tracer (Tracer , traceWith )
19
19
import Data.List.NonEmpty qualified as NonEmpty
20
20
import Data.Sequence.Strict (StrictSeq )
21
21
import Data.Sequence.Strict qualified as Seq
22
+ import Data.Set qualified as Set
22
23
import Ouroboros.Consensus.MiniProtocol.ObjectDiffusion.ObjectPool.API
23
24
import Ouroboros.Network.ControlMessage
24
25
( ControlMessage
@@ -28,16 +29,14 @@ import Ouroboros.Network.ControlMessage
28
29
import Ouroboros.Network.NodeToNode.Version (NodeToNodeVersion )
29
30
import Ouroboros.Network.Protocol.ObjectDiffusion.Outbound
30
31
import Ouroboros.Network.Protocol.ObjectDiffusion.Type
31
- import qualified Data.Set as Set
32
+
33
+ -- Note: This module is inspired from TxSubmission outbound side.
32
34
33
35
data TraceObjectDiffusionOutbound objectId object
34
- =
35
- TraceObjectDiffusionOutboundRecvMsgRequestObjectIds NumObjectIdsReq
36
- |
37
- -- | The IDs to be sent in the response
36
+ = TraceObjectDiffusionOutboundRecvMsgRequestObjectIds NumObjectIdsReq
37
+ | -- | The IDs to be sent in the response
38
38
TraceObjectDiffusionOutboundSendMsgReplyObjectIds [objectId ]
39
- |
40
- -- | The IDs of the objects requested.
39
+ | -- | The IDs of the objects requested.
41
40
TraceObjectDiffusionOutboundRecvMsgRequestObjects
42
41
[objectId ]
43
42
| -- | The objects to be sent in the response.
@@ -100,20 +99,27 @@ objectDiffusionOutbound tracer maxFifoLength ObjectPoolReader{..} _version contr
100
99
makeBundle :: OutboundSt objectId object ticketNo -> OutboundStIdle objectId object m ()
101
100
makeBundle ! st =
102
101
OutboundStIdle
103
- { recvMsgRequestObjectIds = recvMsgRequestObjectIds st
104
- , recvMsgRequestObjects = recvMsgRequestObjects st}
102
+ { recvMsgRequestObjectIds = recvMsgRequestObjectIds st
103
+ , recvMsgRequestObjects = recvMsgRequestObjects st
104
+ }
105
105
106
- updateStNewObjects :: OutboundSt objectId object ticketNo -> [(object , ticketNo )] -> OutboundSt objectId object ticketNo
106
+ updateStNewObjects ::
107
+ OutboundSt objectId object ticketNo ->
108
+ [(object , ticketNo )] ->
109
+ OutboundSt objectId object ticketNo
107
110
updateStNewObjects ! OutboundSt {.. } newObjectsWithTicketNos =
108
111
-- These objects should all be fresh
109
- assert (all (\ (_, ticketNo) -> ticketNo > lastTicketNo) newObjectsWithTicketNos) $
110
- let ! outstandingFifo' =
111
- outstandingFifo
112
- <> (Seq. fromList $ fst <$> newObjectsWithTicketNos)
113
- ! lastTicketNo'
114
- | null newObjectsWithTicketNos = lastTicketNo
115
- | otherwise = snd $ last newObjectsWithTicketNos
116
- in OutboundSt { outstandingFifo = outstandingFifo', lastTicketNo = lastTicketNo' }
112
+ assert (all (\ (_, ticketNo) -> ticketNo > lastTicketNo) newObjectsWithTicketNos) $
113
+ let ! outstandingFifo' =
114
+ outstandingFifo
115
+ <> (Seq. fromList $ fst <$> newObjectsWithTicketNos)
116
+ ! lastTicketNo'
117
+ | null newObjectsWithTicketNos = lastTicketNo
118
+ | otherwise = snd $ last newObjectsWithTicketNos
119
+ in OutboundSt
120
+ { outstandingFifo = outstandingFifo'
121
+ , lastTicketNo = lastTicketNo'
122
+ }
117
123
118
124
recvMsgRequestObjectIds ::
119
125
forall blocking .
@@ -136,14 +142,15 @@ objectDiffusionOutbound tracer maxFifoLength ObjectPoolReader{..} _version contr
136
142
)
137
143
$ throwIO (ProtocolErrorRequestedTooManyObjectIds numIdsToReq maxFifoLength)
138
144
139
- -- First we update our FIFO to remove the number of objectIds
140
- -- that the inbound peer has acknowledged.
145
+ -- First we update our FIFO to remove the number of objectIds that the
146
+ -- inbound peer has acknowledged.
141
147
let ! outstandingFifo' = Seq. drop (fromIntegral numIdsToAck) outstandingFifo
142
- st' :: OutboundSt objectId object ticketNo -- must specify the type here otherwise GHC complains about mismatch objectId types
143
- ! st' = st{ outstandingFifo = outstandingFifo' }
148
+ -- must specify the type here otherwise GHC complains about mismatch objectId types
149
+ st' :: OutboundSt objectId object ticketNo
150
+ ! st' = st{outstandingFifo = outstandingFifo'}
144
151
145
- -- Grab info about any new objects after the last object ticketNo we've seen,
146
- -- up to the number that the peer has requested.
152
+ -- Grab info about any new objects after the last object ticketNo we've
153
+ -- seen, up to the number that the peer has requested.
147
154
case blocking of
148
155
-----------------------------------------------------------------------
149
156
SingBlocking -> do
@@ -154,28 +161,34 @@ objectDiffusionOutbound tracer maxFifoLength ObjectPoolReader{..} _version contr
154
161
155
162
mbNewContent <- timeoutWithControlMessage controlMessageSTM $
156
163
do
157
- newObjectsWithTicketNos <- oprObjectsAfter lastTicketNo (fromIntegral numIdsToReq)
164
+ newObjectsWithTicketNos <-
165
+ oprObjectsAfter
166
+ lastTicketNo
167
+ (fromIntegral numIdsToReq)
158
168
check (not $ null newObjectsWithTicketNos)
159
169
pure newObjectsWithTicketNos
160
170
161
171
case mbNewContent of
162
172
Nothing -> pure (SendMsgDone () )
163
173
Just newContent -> do
164
- newObjectsWithTicketNos <- forM newContent $ \ (ticketNo, _, getObject) -> do
165
- object <- getObject
166
- pure ( object, ticketNo)
167
-
168
-
174
+ newObjectsWithTicketNos <- forM newContent $
175
+ \ (ticketNo, _, getObject) -> do
176
+ object <- getObject
177
+ pure (object, ticketNo)
178
+
169
179
let ! newIds = oprObjectId . fst <$> newObjectsWithTicketNos
170
180
st'' = updateStNewObjects st' newObjectsWithTicketNos
171
-
181
+
172
182
traceWith tracer (TraceObjectDiffusionOutboundSendMsgReplyObjectIds newIds)
173
183
174
- -- Assert objects is non-empty: we blocked until objects was non-null,
175
- -- and we know reqNo > 0, hence `take reqNo objects` is non-null.
184
+ -- Assert objects is non-empty: we blocked until objects was
185
+ -- non-null, and we know numIdsToReq > 0, hence
186
+ -- `take numIdsToReq objects` is non-null.
176
187
assert (not $ null newObjectsWithTicketNos) $
177
- pure (SendMsgReplyObjectIds (BlockingReply (NonEmpty. fromList $ newIds)) (makeBundle st''))
178
-
188
+ pure $
189
+ SendMsgReplyObjectIds
190
+ (BlockingReply (NonEmpty. fromList $ newIds))
191
+ (makeBundle st'')
179
192
180
193
-----------------------------------------------------------------------
181
194
SingNonBlocking -> do
@@ -184,14 +197,17 @@ objectDiffusionOutbound tracer maxFifoLength ObjectPoolReader{..} _version contr
184
197
when (Seq. null outstandingFifo') $
185
198
throwIO ProtocolErrorRequestNonBlocking
186
199
187
- newContent <- atomically $ oprObjectsAfter lastTicketNo (fromIntegral numIdsToReq)
188
- newObjectsWithTicketNos <- forM newContent $ \ (ticketNo, _, getObject) -> do
189
- object <- getObject
190
- pure (object, ticketNo)
200
+ newContent <-
201
+ atomically $
202
+ oprObjectsAfter lastTicketNo (fromIntegral numIdsToReq)
203
+ newObjectsWithTicketNos <- forM newContent $
204
+ \ (ticketNo, _, getObject) -> do
205
+ object <- getObject
206
+ pure (object, ticketNo)
191
207
192
208
let ! newIds = oprObjectId . fst <$> newObjectsWithTicketNos
193
209
st'' = updateStNewObjects st' newObjectsWithTicketNos
194
-
210
+
195
211
traceWith tracer (TraceObjectDiffusionOutboundSendMsgReplyObjectIds newIds)
196
212
197
213
pure (SendMsgReplyObjectIds (NonBlockingReply newIds) (makeBundle st''))
@@ -203,22 +219,31 @@ objectDiffusionOutbound tracer maxFifoLength ObjectPoolReader{..} _version contr
203
219
recvMsgRequestObjects ! st@ OutboundSt {.. } requestedIds = do
204
220
traceWith tracer (TraceObjectDiffusionOutboundRecvMsgRequestObjects requestedIds)
205
221
206
- -- All the objects correspond to advertised objectIds are already in the outstandingFifo.
207
- -- So we don't need to read from the object pool here.
222
+ -- All the objects correspond to advertised objectIds are already in the
223
+ -- outstandingFifo. So we don't need to read from the object pool here.
208
224
209
- -- TODO: I've improved the search to do only one traversal of 'outstandingFifo'.
225
+ -- I've optimized the search to do only one traversal of 'outstandingFifo'.
210
226
-- When the 'requestedIds' is exactly the whole 'outstandingFifo', then this
211
227
-- should take O(n * log n) time.
212
- -- We will need to revisit the underlying outstandingFifo data structure and search if
213
- -- performance isn't sufficient when we'll use ObjectDiffusion for votes (and not just cert diffusion).
228
+ --
229
+ -- TODO: We might need to revisit the underlying 'outstandingFifo' data
230
+ -- structure and the search if performance isn't sufficient when we'll use
231
+ -- ObjectDiffusion for votes diffusion (and not just cert diffusion).
232
+
214
233
let requestedIdsSet = Set. fromList requestedIds
215
234
216
235
when (Set. size requestedIdsSet /= length requestedIds) $
217
236
throwIO ProtocolErrorRequestedDuplicateObject
218
237
219
- let requestedObjects = foldr (\ obj acc -> if Set. member (oprObjectId obj) requestedIdsSet
220
- then obj : acc
221
- else acc) [] outstandingFifo
238
+ let requestedObjects =
239
+ foldr
240
+ ( \ obj acc ->
241
+ if Set. member (oprObjectId obj) requestedIdsSet
242
+ then obj : acc
243
+ else acc
244
+ )
245
+ []
246
+ outstandingFifo
222
247
223
248
when (Set. size requestedIdsSet /= length requestedObjects) $
224
249
throwIO ProtocolErrorRequestedUnavailableObject
0 commit comments