@@ -25,10 +25,10 @@ import Control.Monad.Class.MonadThrow
2525import Control.Monad.Class.MonadTime.SI
2626import Control.Monad.Class.MonadTimer.SI
2727import Control.Monad.IOSim
28- import Control.Tracer (Tracer (.. ), contramap , mkTracer )
28+ import Control.Tracer (Tracer (.. ), contramap , mkTracer , traceWith )
2929
3030import Data.ByteString.Lazy qualified as BSL
31- import Data.Foldable (toList , traverse_ )
31+ import Data.Foldable (traverse_ )
3232import Data.Foldable qualified as Foldable
3333import Data.Function (on )
3434import Data.Functor.Identity (runIdentity )
@@ -40,8 +40,6 @@ import Data.Maybe (fromMaybe)
4040import Data.Set qualified as Set
4141import Data.Typeable (Typeable )
4242
43- import Network.TypedProtocol.Codec (AnyMessage (.. ))
44-
4543import Ouroboros.Network.Channel
4644import Ouroboros.Network.ControlMessage (ControlMessage (.. ), ControlMessageSTM )
4745import Ouroboros.Network.Driver
@@ -56,8 +54,7 @@ import DMQ.Protocol.SigSubmissionV2.Codec (byteLimitsSigSubmissionV2,
5654import DMQ.Protocol.SigSubmissionV2.Inbound
5755 (sigSubmissionV2InboundPeerPipelined )
5856import DMQ.Protocol.SigSubmissionV2.Outbound (sigSubmissionV2OutboundPeer )
59- import DMQ.Protocol.SigSubmissionV2.Type (Message (.. ), NumIdsAck (.. ),
60- SigSubmissionV2 )
57+ import DMQ.Protocol.SigSubmissionV2.Type (NumIdsAck (.. ), SigSubmissionV2 )
6158import DMQ.SigSubmissionV2.Inbound (sigSubmissionInbound )
6259import DMQ.SigSubmissionV2.Outbound (sigSubmissionOutbound )
6360
@@ -366,6 +363,21 @@ type SimPeerAddr = Int
366363type SimProtocolEvent = TraceLabelPeer SimPeerAddr
367364 (TraceSendRecv (SigSubmissionV2 TxId (Tx TxId )))
368365
366+ -- | Dynamic-trace type for sigid announcements as the peer metric sees them:
367+ -- the peer, the time the announcement is stamped with and the announced
368+ -- sigids.
369+ --
370+ -- Note: this is deliberately not derived from 'SimProtocolEvent'.
371+ -- 'sigSubmissionInbound' stamps an announcement with the time at which it
372+ -- /collects/ the pipelined @MsgReplySigIds@ reply, which can be strictly later
373+ -- than the time that reply was decoded off the wire — e.g. while the
374+ -- application is still blocked on an earlier reply of a peer behind a delayed
375+ -- channel. Both times feed the pruning cut-offs of 'reportSigIdsImpl' and
376+ -- 'reportSigImpl', so a model driven by the wire time prunes at a different
377+ -- boundary than the implementation and disagrees whenever an entry falls
378+ -- between the two.
379+ type SimAnnouncedEvent = TraceLabelPeer SimPeerAddr (Time , [TxId ])
380+
369381-- | Dynamic-trace type for inbound application-layer events (emitted by the
370382-- per-peer application tracer in 'runSigSubmissionV2WithMetric').
371383type SimAppEvent = TraceLabelPeer SimPeerAddr
@@ -381,6 +393,7 @@ type SimMetricSnapshot = PeerMetricState TxId SimPeerAddr
381393-- (sig_add → snapshot → sig_add → snapshot …) that separate calls would lose.
382394data SimTraceEvent
383395 = SimProtocolEvent SimProtocolEvent
396+ | SimAnnouncedEvent SimAnnouncedEvent
384397 | SimAppEvent SimAppEvent
385398 | SimMetricSnapshot SimMetricSnapshot
386399 deriving Show
@@ -437,9 +450,11 @@ sigSubmissionSimulationWithMetric config (SigSubmissionState state sigDecisionPo
437450-- meaningful change to the metric state is emitted into the IOSim dynamic
438451-- trace as a 'SimMetricSnapshot'.
439452--
440- -- The inbound protocol tracer emits 'SimProtocolEvent' and the application
441- -- tracer emits 'SimAppEvent'; all three event kinds are consumed by
442- -- 'prop_sigSubmissionV2_metric'.
453+ -- It also wraps 'applyReceivedTxIds' so that each announcement is emitted as
454+ -- a 'SimAnnouncedEvent' carrying the time the metric stamps it with. The
455+ -- inbound protocol tracer emits 'SimProtocolEvent' and the application tracer
456+ -- emits 'SimAppEvent'; 'prop_sigSubmissionV2_metric' consumes all but the
457+ -- former.
443458runSigSubmissionV2WithMetric
444459 :: forall s .
445460 Tracer (IOSim s ) (String , TraceSendRecv (SigSubmissionV2 TxId (Tx TxId )))
@@ -500,13 +515,31 @@ runSigSubmissionV2WithMetric tracer tracerSigLogic config st0 sigDecisionPolicy
500515 sigPeerRegistry
501516 sigCountersVar
502517 addr $ \ (api :: PeerTxAPI (IOSim s ) TxId (Tx TxId )) -> do
503- let inbound = sigSubmissionInbound
518+ let simTracer :: Tracer (IOSim s ) SimTraceEvent
519+ simTracer = dynamicTracer <> sayTracer
520+
521+ -- `sigSubmissionInbound` reports received
522+ -- sigids to the peer metric and passes the
523+ -- very same time and sigids on to
524+ -- `applyReceivedTxIds`; wrapping the latter
525+ -- is what makes the time the metric is
526+ -- stamped with observable, see
527+ -- 'SimAnnouncedEvent'.
528+ api' = api {
529+ applyReceivedTxIds = \ time numIdsToReq sigids peerState -> do
530+ traceWith simTracer
531+ (SimAnnouncedEvent
532+ (TraceLabelPeer addr (time, fst <$> sigids)))
533+ applyReceivedTxIds api time numIdsToReq sigids peerState
534+ }
535+
536+ inbound = sigSubmissionInbound
504537 (contramap (SimAppEvent . TraceLabelPeer addr)
505- (dynamicTracer <> sayTracer :: Tracer ( IOSim s ) SimTraceEvent ) )
538+ simTracer )
506539 sigDecisionPolicy
507540 (getMempoolWriter duplicateSigsVar inboundMempool)
508541 getTxSize
509- api
542+ api'
510543 (PeerMetric. hoist
511544 (TraceLabelPeer addr . runIdentity)
512545 (PeerMetric. reportMetric
@@ -515,7 +548,7 @@ runSigSubmissionV2WithMetric tracer tracerSigLogic config st0 sigDecisionPolicy
515548 ctrlMsgSTM
516549 runPipelinedPeerWithLimits
517550 (contramap (SimProtocolEvent . TraceLabelPeer addr)
518- (dynamicTracer <> sayTracer :: Tracer ( IOSim s ) SimTraceEvent ) )
551+ simTracer )
519552 sigSubmissionCodec2
520553 (byteLimitsSigSubmissionV2 (fromIntegral . BSL. length ))
521554 timeLimitsSigSubmissionV2
@@ -551,8 +584,8 @@ runSigSubmissionV2WithMetric tracer tracerSigLogic config st0 sigDecisionPolicy
551584
552585
553586-- | Checks that on every 'SimMetricSnapshot' in the merged trace the actual
554- -- 'announcinessImpl' agrees with the pure model rebuilt from 'SimProtocolEvent'
555- -- and 'SimAppEvent' events seen so far.
587+ -- 'announcinessImpl' agrees with the pure model rebuilt from
588+ -- 'SimAnnouncedEvent' and 'SimAppEvent' events seen so far.
556589prop_sigSubmissionV2_metric :: PeerMetric. PeerMetricConfiguration
557590 -> SigSubmissionState
558591 -> Property
@@ -612,9 +645,9 @@ data PureModelState = PureModelState
612645emptyPureModelState :: PureModelState
613646emptyPureModelState = PureModelState Map. empty Map. empty
614647
615- -- | Advance the pure model when a sigid is announced using a protocol message.
616- -- Only 'TraceRecvMsg' of 'MsgReplySigIds' matters: it records the IOSim time at
617- -- which the inbound peer received the sigid announcement .
648+ -- | Advance the pure model when a peer announces sigids. The event records
649+ -- the sigids together with the time that 'sigSubmissionInbound' stamps them
650+ -- with, which is the time the metric uses as well .
618651--
619652-- Mirrors 'reportSigIdsImpl': prune stale per-peer announced entries (those
620653-- older than @timeWindowToKeep@ relative to the new announcement time) before
@@ -624,28 +657,21 @@ emptyPureModelState = PureModelState Map.empty Map.empty
624657--
625658updatePureModelOnSigAnnounced
626659 :: PeerMetric. PeerMetricConfiguration
627- -> Time
628- -> SimProtocolEvent
660+ -> SimAnnouncedEvent
629661 -> PureModelState
630662 -> PureModelState
631663updatePureModelOnSigAnnounced
632664 (PeerMetric. PeerMetricConfiguration window)
633- t
634- (TraceLabelPeer addr (TraceRecvMsg (AnyMessage msg)))
665+ (TraceLabelPeer addr (t, sigids))
635666 st =
636- case msg of
637- MsgReplySigIds sigids ->
638- -- Mirror reportSigIdsImpl: pruning only happens when reportSigIds is
639- -- called.
640- let sigidsLst = fst <$> toList sigids
641- threshold = (- window) `addTime` t
642- announced' = Map. filterWithKey
643- (\ (_, a) tann -> a /= addr || tann > threshold)
644- (announced st)
645- in st { announced = Foldable. foldl' (\ m txid -> Map. insert (txid, addr) t m)
646- announced' sigidsLst }
647- _ -> st
648- updatePureModelOnSigAnnounced _ _ _ st = st
667+ -- Mirror reportSigIdsImpl: pruning only happens when reportSigIds is
668+ -- called.
669+ let threshold = (- window) `addTime` t
670+ announced' = Map. filterWithKey
671+ (\ (_, a) tann -> a /= addr || tann > threshold)
672+ (announced st)
673+ in st { announced = Foldable. foldl' (\ m sigid -> Map. insert (sigid, addr) t m)
674+ announced' sigids }
649675
650676
651677-- | Advance the pure model when on mempool submission result. Only
@@ -726,7 +752,10 @@ checkTrace config evs =
726752 step :: (PureModelState , Property , Int )
727753 -> (Time , SimTraceEvent )
728754 -> (PureModelState , Property , Int )
729- step (st, prop, maxScore) (t, SimProtocolEvent event) = (updatePureModelOnSigAnnounced config t event st, prop, maxScore)
755+ -- protocol events are traced to make counterexamples readable; the model
756+ -- must not take announcement times from them, see 'SimAnnouncedEvent'.
757+ step acc (_, SimProtocolEvent _) = acc
758+ step (st, prop, maxScore) (_, SimAnnouncedEvent event) = (updatePureModelOnSigAnnounced config event st, prop, maxScore)
730759 step (st, prop, maxScore) (_, SimAppEvent event) = (updatePureModelOnMempoolResult config event st, prop, maxScore)
731760 step (st, prop, maxScore) (t, SimMetricSnapshot snapshot) =
732761 let expected = expectedAnnounciness st
0 commit comments