Skip to content

Commit 40dec23

Browse files
authored
Merge pull request #73 from IntersectMBO/coot/test-fix
peer-metric: fix prop_sigSubmissionV2_metric flakiness
2 parents 4a6f910 + ce98386 commit 40dec23

1 file changed

Lines changed: 65 additions & 36 deletions

File tree

  • dmq-node/test/Test/DMQ/SigSubmission

dmq-node/test/Test/DMQ/SigSubmission/App.hs

Lines changed: 65 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ import Control.Monad.Class.MonadThrow
2525
import Control.Monad.Class.MonadTime.SI
2626
import Control.Monad.Class.MonadTimer.SI
2727
import Control.Monad.IOSim
28-
import Control.Tracer (Tracer (..), contramap, mkTracer)
28+
import Control.Tracer (Tracer (..), contramap, mkTracer, traceWith)
2929

3030
import Data.ByteString.Lazy qualified as BSL
31-
import Data.Foldable (toList, traverse_)
31+
import Data.Foldable (traverse_)
3232
import Data.Foldable qualified as Foldable
3333
import Data.Function (on)
3434
import Data.Functor.Identity (runIdentity)
@@ -40,8 +40,6 @@ import Data.Maybe (fromMaybe)
4040
import Data.Set qualified as Set
4141
import Data.Typeable (Typeable)
4242

43-
import Network.TypedProtocol.Codec (AnyMessage (..))
44-
4543
import Ouroboros.Network.Channel
4644
import Ouroboros.Network.ControlMessage (ControlMessage (..), ControlMessageSTM)
4745
import Ouroboros.Network.Driver
@@ -56,8 +54,7 @@ import DMQ.Protocol.SigSubmissionV2.Codec (byteLimitsSigSubmissionV2,
5654
import DMQ.Protocol.SigSubmissionV2.Inbound
5755
(sigSubmissionV2InboundPeerPipelined)
5856
import DMQ.Protocol.SigSubmissionV2.Outbound (sigSubmissionV2OutboundPeer)
59-
import DMQ.Protocol.SigSubmissionV2.Type (Message (..), NumIdsAck (..),
60-
SigSubmissionV2)
57+
import DMQ.Protocol.SigSubmissionV2.Type (NumIdsAck (..), SigSubmissionV2)
6158
import DMQ.SigSubmissionV2.Inbound (sigSubmissionInbound)
6259
import DMQ.SigSubmissionV2.Outbound (sigSubmissionOutbound)
6360

@@ -366,6 +363,21 @@ type SimPeerAddr = Int
366363
type 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').
371383
type SimAppEvent = TraceLabelPeer SimPeerAddr
@@ -381,6 +393,7 @@ type SimMetricSnapshot = PeerMetricState TxId SimPeerAddr
381393
-- (sig_add → snapshot → sig_add → snapshot …) that separate calls would lose.
382394
data 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.
443458
runSigSubmissionV2WithMetric
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.
556589
prop_sigSubmissionV2_metric :: PeerMetric.PeerMetricConfiguration
557590
-> SigSubmissionState
558591
-> Property
@@ -612,9 +645,9 @@ data PureModelState = PureModelState
612645
emptyPureModelState :: PureModelState
613646
emptyPureModelState = 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
--
625658
updatePureModelOnSigAnnounced
626659
:: PeerMetric.PeerMetricConfiguration
627-
-> Time
628-
-> SimProtocolEvent
660+
-> SimAnnouncedEvent
629661
-> PureModelState
630662
-> PureModelState
631663
updatePureModelOnSigAnnounced
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

Comments
 (0)