@@ -106,7 +106,7 @@ prop_yield_regression =
106106 yieldRegressionActions :: QD. Actions Model
107107 yieldRegressionActions =
108108 (wrapPositiveAction $ NewCandidate Amara (B 1 ))
109- <> (wrapPositiveAction $ StartIdling Amara )
109+ <> (wrapPositiveAction $ ChainSyncStartIdling Amara )
110110 <> (wrapPositiveAction $ TimePasses 61 )
111111 <> (wrapPositiveAction $ ExtendSelection (S (- 4 )))
112112 <> (wrapPositiveAction $ ReadMarker )
@@ -137,8 +137,8 @@ setupGsm isHaaSatisfied vars = do
137137 (id , tracer)
138138 GSM. GsmView
139139 { GSM. antiThunderingHerd = Nothing
140- , GSM. getCandidateOverSelection = pure $ \ s ( PeerState c _) ->
141- candidateOverSelection s c
140+ , GSM. getCandidateOverSelection = pure $ \ s peer ->
141+ candidateOverSelection s (psCandidate peer)
142142 , GSM. peerIsIdle = isIdling
143143 , GSM. durationUntilTooOld = Just durationUntilTooOld
144144 , GSM. equivalent = (==) -- unsound, but harmless in this test
@@ -246,7 +246,8 @@ data StaticParams = StaticParams
246246data Model = Model
247247 { mCandidates :: Map. Map UpstreamPeer Candidate
248248 , mClock :: SI. Time
249- , mIdlers :: Set. Set UpstreamPeer
249+ , mChainSyncIdlers :: Set. Set UpstreamPeer
250+ , mPerasCertDiffusionIdlers :: Set. Set UpstreamPeer
250251 , mNotables :: Set. Set Notable
251252 , mPrev :: WhetherPrevTimePasses
252253 , mSelection :: Selection
@@ -261,18 +262,20 @@ initModel =
261262 Model
262263 { mCandidates = Map. empty
263264 , mClock = SI. Time 0
264- , mIdlers = idlers
265+ , mChainSyncIdlers = chainSyncIdlers
266+ , mPerasCertDiffusionIdlers = perasCertDiffusionIdlers
265267 , mNotables = Set. empty
266268 , mPrev = WhetherPrevTimePasses True
267269 , mSelection = initialSelection pInitialJudgement
268270 , mState = case pInitialJudgement of
269271 TooOld
270- | pIsHaaSatisfied idlers -> ModelSyncing
272+ | pIsHaaSatisfied chainSyncIdlers -> ModelSyncing
271273 | otherwise -> ModelPreSyncing
272274 YoungEnough -> ModelCaughtUp (SI. Time (- 10000 ))
273275 }
274276 where
275- idlers = Set. empty
277+ perasCertDiffusionIdlers = Set. empty
278+ chainSyncIdlers = Set. empty
276279
277280 StaticParams {pIsHaaSatisfied, pInitialJudgement} = Reflection. given
278281
@@ -296,10 +299,16 @@ instance Reflection.Given StaticParams => QD.StateModel Model where
296299 NewCandidate :: UpstreamPeer -> B -> QD. Action Model ()
297300 -- \^ INVARIANT new peer
298301 --
299- -- Mocks the necessary ChainSync client behavior.z
302+ -- Mocks the necessary ChainSync client behavior.
303+ NewPerasCert :: UpstreamPeer -> QD. Action Model ()
304+ -- \^ INVARIANT existing peer
305+ --
306+ -- Mocks the necessary PerasCertDiffusion client behavior.
300307 ReadGsmState :: QD. Action Model GSM. GsmState
301308 ReadMarker :: QD. Action Model MarkerState
302- StartIdling :: UpstreamPeer -> QD. Action Model ()
309+ ChainSyncStartIdling :: UpstreamPeer -> QD. Action Model ()
310+ -- \^ INVARIANT existing peer, not idling
311+ PerasCertDiffusionStartIdling :: UpstreamPeer -> QD. Action Model ()
303312 -- \^ INVARIANT existing peer, not idling
304313 TimePasses :: Int -> QD. Action Model ()
305314
@@ -437,23 +446,51 @@ instance (IOLike m, Reflection.Given StaticParams) => QD.RunModel Model (RunMona
437446 ModifyCandidate peer bdel -> do
438447 atomically $ do
439448 v <- (Map. ! peer) <$> readTVar varStates
440- Candidate b <- psCandidate <$> readTVar v
441- writeTVar v $! PeerState (Candidate (b + bdel)) (Idling False )
442-
449+ modifyTVar v $! \ ps ->
450+ let Candidate b = psCandidate ps
451+ in ps
452+ { psCandidate = Candidate (b + bdel)
453+ , psChainSyncIdling = Idling False
454+ }
443455 pure ()
444456 NewCandidate peer bdel -> do
445457 atomically $ do
446458 Selection b _s <- readTVar varSelection
447- v <- newTVar $! PeerState (Candidate (b + bdel)) (Idling False )
459+ v <-
460+ newTVar $!
461+ PeerState
462+ { psCandidate = Candidate (b + bdel)
463+ , psChainSyncIdling = Idling False
464+ , psPerasCertDiffusionIdling = Idling True
465+ -- NOTE: this new peer will idle until it gets a 'NewPerasCert'
466+ }
448467 modifyTVar varStates $ Map. insert peer v
449468 pure ()
469+ NewPerasCert peer -> do
470+ atomically $ do
471+ v <- (Map. ! peer) <$> readTVar varStates
472+ modifyTVar v $ \ ps ->
473+ ps
474+ { psPerasCertDiffusionIdling = Idling False
475+ }
476+ pure ()
450477 ReadGsmState -> do
451478 atomically $ readTVar varGsmState
452479 ReadMarker -> do
453480 atomically $ readTVar varMarker
454- StartIdling peer -> atomically $ do
481+ ChainSyncStartIdling peer -> atomically $ do
455482 v <- (Map. ! peer) <$> readTVar varStates
456- modifyTVar v $ \ (PeerState c _) -> PeerState c (Idling True )
483+ modifyTVar v $ \ ps ->
484+ ps
485+ { psChainSyncIdling = Idling True
486+ }
487+ pure ()
488+ PerasCertDiffusionStartIdling peer -> atomically $ do
489+ v <- (Map. ! peer) <$> readTVar varStates
490+ modifyTVar v $ \ ps ->
491+ ps
492+ { psPerasCertDiffusionIdling = Idling True
493+ }
457494 pure ()
458495 TimePasses dur -> do
459496 SI. threadDelay (0.1 * fromIntegral dur)
@@ -596,20 +633,26 @@ precondition model = \case
596633 peer `Map.member` cands
597634 NewCandidate peer _bdel ->
598635 peer `Map.notMember` cands
636+ NewPerasCert peer ->
637+ peer `Map.member` cands
599638 ReadGsmState ->
600639 True
601640 ReadMarker ->
602641 True
603- StartIdling peer ->
642+ ChainSyncStartIdling peer ->
643+ peer `Map.member` cands
644+ && peer `Set.notMember` chainSyncIdlers
645+ PerasCertDiffusionStartIdling peer ->
604646 peer `Map.member` cands
605- && peer `Set.notMember` idlers
647+ && peer `Set.notMember` perasCertDiffusionIdlers
606648 TimePasses dur ->
607649 0 < dur
608650 && boringDur model dur
609651 where
610652 Model
611653 { mCandidates = cands
612- , mIdlers = idlers
654+ , mChainSyncIdlers = chainSyncIdlers
655+ , mPerasCertDiffusionIdlers = perasCertDiffusionIdlers
613656 } = model
614657
615658generator ::
@@ -635,15 +678,29 @@ generator model =
635678 )
636679 | notNull new
637680 ]
681+ <> [ (,) 20 $ do
682+ QD. Some . NewPerasCert <$> QC. elements old
683+ | notNull old
684+ ]
638685 <> [(,) 20 $ pure . QD. Some $ ReadGsmState ]
639686 <> [(,) 20 $ pure . QD. Some $ ReadMarker ]
640- <> [(,) 50 $ QD. Some . StartIdling <$> QC. elements oldNotIdling | notNull oldNotIdling]
687+ <> [ (,) 50 $
688+ QD. Some . ChainSyncStartIdling <$> do
689+ QC. elements oldNotChainSyncIdling
690+ | notNull oldNotChainSyncIdling
691+ ]
692+ <> [ (,) 50 $
693+ QD. Some . PerasCertDiffusionStartIdling <$> do
694+ QC. elements oldNotPerasCertDiffusionIdling
695+ | notNull oldNotPerasCertDiffusionIdling
696+ ]
641697 <> [(,) 100 $ QD. Some . TimePasses <$> genTimePassesDur | prev == WhetherPrevTimePasses False ]
642698 where
643699 Model
644700 { mCandidates = cands
645701 , mClock = clk
646- , mIdlers = idlers
702+ , mChainSyncIdlers = chainSyncIdlers
703+ , mPerasCertDiffusionIdlers = perasCertDiffusionIdlers
647704 , mPrev = prev
648705 , mSelection = sel
649706 } = model
@@ -659,7 +716,8 @@ generator model =
659716 Nothing -> []
660717 Just peer -> [minBound .. peer] \\ old
661718
662- oldNotIdling = old \\ Set. toList idlers
719+ oldNotChainSyncIdling = old \\ Set. toList chainSyncIdlers
720+ oldNotPerasCertDiffusionIdling = old \\ Set. toList perasCertDiffusionIdlers
663721
664722 genTimePassesDur =
665723 QC. frequency $
@@ -700,11 +758,15 @@ shrinker _model = \case
700758 [QD. Some $ ModifyCandidate peer bdel' | bdel' <- shrinkB bdel, bdel' /= 0 ]
701759 NewCandidate peer bdel ->
702760 [QD. Some $ NewCandidate peer bdel' | bdel' <- shrinkB bdel, bdel' /= 0 ]
761+ NewPerasCert {} ->
762+ []
703763 ReadGsmState ->
704764 []
705765 ReadMarker ->
706766 []
707- StartIdling {} ->
767+ ChainSyncStartIdling {} ->
768+ []
769+ PerasCertDiffusionStartIdling {} ->
708770 []
709771 TimePasses dur ->
710772 [QD. Some $ TimePasses dur' | dur' <- QC. shrink dur, 0 < dur']
@@ -722,23 +784,40 @@ transition model cmd =
722784 Disconnect peer ->
723785 model'
724786 { mCandidates = Map. delete peer cands
725- , mIdlers = Set. delete peer idlers
787+ , mChainSyncIdlers = Set. delete peer chainSyncIdlers
788+ , mPerasCertDiffusionIdlers = Set. delete peer perasCertDiffusionIdlers
726789 }
727790 ExtendSelection sdel ->
728- model'{mSelection = Selection (b + 1 ) (s + sdel)}
791+ model'
792+ { mSelection = Selection (b + 1 ) (s + sdel)
793+ }
729794 ModifyCandidate peer bdel ->
730795 model'
731796 { mCandidates = Map. insertWith plusC peer (Candidate bdel) cands
732- , mIdlers = Set. delete peer idlers
797+ , mChainSyncIdlers = Set. delete peer chainSyncIdlers
733798 }
734799 NewCandidate peer bdel ->
735- model'{mCandidates = Map. insert peer (Candidate (b + bdel)) cands}
800+ model'
801+ { mCandidates = Map. insert peer (Candidate (b + bdel)) cands
802+ , mPerasCertDiffusionIdlers = Set. insert peer perasCertDiffusionIdlers
803+ -- NOTE: this new peer will idle until it gets a 'NewPerasCert'
804+ }
805+ NewPerasCert peer ->
806+ model'
807+ { mPerasCertDiffusionIdlers = Set. delete peer perasCertDiffusionIdlers
808+ }
736809 ReadGsmState ->
737810 model'
738811 ReadMarker ->
739812 model'
740- StartIdling peer ->
741- model'{mIdlers = Set. insert peer idlers}
813+ ChainSyncStartIdling peer ->
814+ model'
815+ { mChainSyncIdlers = Set. insert peer chainSyncIdlers
816+ }
817+ PerasCertDiffusionStartIdling peer ->
818+ model'
819+ { mPerasCertDiffusionIdlers = Set. insert peer perasCertDiffusionIdlers
820+ }
742821 TimePasses dur ->
743822 addNotableWhen BigDurN (dur > 300 ) $
744823 model
@@ -749,7 +828,8 @@ transition model cmd =
749828 Model
750829 { mCandidates = cands
751830 , mClock = clk
752- , mIdlers = idlers
831+ , mChainSyncIdlers = chainSyncIdlers
832+ , mPerasCertDiffusionIdlers = perasCertDiffusionIdlers
753833 , mSelection = Selection b s
754834 } = model
755835
@@ -806,7 +886,8 @@ fixupModelState cmd model =
806886 Model
807887 { mCandidates = cands
808888 , mClock = clk
809- , mIdlers = idlers
889+ , mChainSyncIdlers = chainSyncIdlers
890+ , mPerasCertDiffusionIdlers = perasCertDiffusionIdlers
810891 , mSelection = sel
811892 , mState = st
812893 } = model
@@ -820,7 +901,9 @@ fixupModelState cmd model =
820901
821902 some = 0 < Map. size cands
822903
823- allIdling = idlers == Map. keysSet cands
904+ allIdling =
905+ chainSyncIdlers == Map. keysSet cands
906+ && perasCertDiffusionIdlers == Map. keysSet cands
824907
825908 ok cand =
826909 GSM. WhetherCandidateIsBetter False == candidateOverSelection sel cand
@@ -936,14 +1019,20 @@ instance TD.ToExpr Notable where toExpr = TD.defaultExprViaShow
9361019
9371020---
9381021
939- newtype Idling = Idling Bool
1022+ newtype Idling = Idling { unIdling :: Bool }
9401023 deriving (Eq , Ord , Show )
9411024
942- data PeerState = PeerState { psCandidate :: ! Candidate , psIdling :: ! Idling }
1025+ data PeerState = PeerState
1026+ { psCandidate :: ! Candidate
1027+ , psChainSyncIdling :: ! Idling
1028+ , psPerasCertDiffusionIdling :: ! Idling
1029+ }
9431030 deriving (Eq , Ord , Show )
9441031
9451032isIdling :: PeerState -> Bool
946- isIdling (PeerState {psIdling = Idling i}) = i
1033+ isIdling (PeerState {psChainSyncIdling, psPerasCertDiffusionIdling}) =
1034+ unIdling psChainSyncIdling
1035+ && unIdling psPerasCertDiffusionIdling
9471036
9481037-- | Ensure the GSM thread's transactions quiesce
9491038--
0 commit comments