Skip to content

Commit e1120d6

Browse files
Niolsneilmayhew
authored andcommitted
Specify the order in which to start the peers
1 parent 76217aa commit e1120d6

File tree

11 files changed

+98
-38
lines changed

11 files changed

+98
-38
lines changed

ouroboros-consensus-diffusion/test/consensus-test/Test/Consensus/Genesis/Tests/DensityDisconnect.hs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -499,7 +499,8 @@ prop_densityDisconnectTriggersChainSel =
499499
(AF.Empty _) -> Origin
500500
(_ AF.:> tipBlock) -> At tipBlock
501501
advTip = getOnlyBranchTip tree
502-
in mkPointSchedule $ peers'
502+
in PointSchedule {
503+
psSchedule = peers'
503504
-- Eagerly serve the honest tree, but after the adversary has
504505
-- advertised its chain up to the intersection.
505506
[[(Time 0, scheduleTipPoint trunkTip),
@@ -514,4 +515,7 @@ prop_densityDisconnectTriggersChainSel =
514515
(Time 0, ScheduleBlockPoint intersect),
515516
(Time 1, scheduleHeaderPoint advTip),
516517
(Time 1, scheduleBlockPoint advTip)
517-
]]
518+
]],
519+
psStartOrder = [],
520+
psMinEndTime = Time 0
521+
}

ouroboros-consensus-diffusion/test/consensus-test/Test/Consensus/Genesis/Tests/LoE.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,4 +115,4 @@ prop_adversaryHitsTimeouts timeoutsEnabled =
115115
]
116116
-- We want to wait more than the short wait timeout
117117
psMinEndTime = Time 11
118-
in PointSchedule {psSchedule, psMinEndTime}
118+
in PointSchedule {psSchedule, psStartOrder = [], psMinEndTime}

ouroboros-consensus-diffusion/test/consensus-test/Test/Consensus/Genesis/Tests/LoP.hs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ prop_wait mustTimeout =
7979
let offset :: DiffTime = if mustTimeout then 1 else -1
8080
in PointSchedule
8181
{ psSchedule = peersOnlyHonest [(Time 0, scheduleTipPoint tipBlock)]
82+
, psStartOrder = []
8283
, psMinEndTime = Time $ timeout + offset
8384
}
8485

@@ -108,6 +109,7 @@ prop_waitBehindForecastHorizon =
108109
[ (Time 0, scheduleTipPoint tipBlock)
109110
, (Time 0, scheduleHeaderPoint tipBlock)
110111
]
112+
, psStartOrder = []
111113
, psMinEndTime = Time 11
112114
}
113115

@@ -166,13 +168,18 @@ prop_serve mustTimeout =
166168
makeSchedule :: (HasHeader blk) => AnchoredFragment blk -> PointSchedule blk
167169
makeSchedule (AF.Empty _) = error "fragment must have at least one block"
168170
makeSchedule fragment@(_ AF.:> tipBlock) =
169-
mkPointSchedule $ peersOnlyHonest $
171+
PointSchedule {
172+
psSchedule =
173+
peersOnlyHonest $
170174
(Time 0, scheduleTipPoint tipBlock)
171175
: ( flip concatMap (zip [1 ..] (AF.toOldestFirst fragment)) $ \(i, block) ->
172176
[ (Time (secondsRationalToDiffTime (i * timeBetweenBlocks)), scheduleHeaderPoint block),
173177
(Time (secondsRationalToDiffTime (i * timeBetweenBlocks)), scheduleBlockPoint block)
174178
]
175-
)
179+
),
180+
psStartOrder = [],
181+
psMinEndTime = Time 0
182+
}
176183

177184
-- NOTE: Same as 'LoE.prop_adversaryHitsTimeouts' with LoP instead of timeouts.
178185
prop_delayAttack :: Bool -> Property
@@ -249,4 +256,4 @@ prop_delayAttack lopEnabled =
249256
]
250257
-- Wait for LoP bucket to empty
251258
psMinEndTime = Time 11
252-
in PointSchedule {psSchedule, psMinEndTime}
259+
in PointSchedule {psSchedule, psStartOrder = [], psMinEndTime}

ouroboros-consensus-diffusion/test/consensus-test/Test/Consensus/Genesis/Tests/Uniform.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,7 @@ prop_leashingAttackTimeLimited =
288288
advs = fmap (takePointsUntil timeLimit) advs0
289289
pure $ PointSchedule
290290
{ psSchedule = Peers honests advs
291+
, psStartOrder = []
291292
, psMinEndTime = timeLimit
292293
}
293294

ouroboros-consensus-diffusion/test/consensus-test/Test/Consensus/PeerSimulator/Run.hs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import Control.ResourceRegistry
1717
import Control.Tracer (Tracer (..), nullTracer, traceWith)
1818
import Data.Coerce (coerce)
1919
import Data.Foldable (for_)
20+
import Data.List (sort)
2021
import qualified Data.List.NonEmpty as NonEmpty
2122
import Data.Map.Strict (Map)
2223
import qualified Data.Map.Strict as Map
@@ -340,8 +341,15 @@ startNode schedulerConfig genesisTest interval = do
340341
getCandidates = viewChainSyncState (cschcMap handles) CSClient.csCandidate
341342
fetchClientRegistry <- newFetchClientRegistry
342343
let chainDbView = CSClient.defaultChainDbView lnChainDb
343-
activePeers = Map.restrictKeys (psrPeers lrPeerSim) (lirActive liveResult)
344-
for_ activePeers $ \PeerResources {prShared, prChainSync, prBlockFetch} -> do
344+
activePeers = Map.toList $ Map.restrictKeys (psrPeers lrPeerSim) (lirActive liveResult)
345+
peersStartOrder = psStartOrder ++ sort [pid | (pid, _) <- activePeers, pid `notElem` psStartOrder]
346+
activePeersOrdered = [
347+
peerResources
348+
| pid <- peersStartOrder
349+
, (pid', peerResources) <- activePeers
350+
, pid == pid'
351+
]
352+
for_ activePeersOrdered $ \PeerResources {prShared, prChainSync, prBlockFetch} -> do
345353
let pid = srPeerId prShared
346354
forkLinkedThread lrRegistry ("Peer overview " ++ show pid) $
347355
-- The peerRegistry helps ensuring that if any thread fails, then
@@ -405,6 +413,7 @@ startNode schedulerConfig genesisTest interval = do
405413
, gtBlockFetchTimeouts
406414
, gtLoPBucketParams = LoPBucketParams { lbpCapacity, lbpRate }
407415
, gtCSJParams = CSJParams { csjpJumpSize }
416+
, gtSchedule = PointSchedule {psStartOrder}
408417
} = genesisTest
409418

410419
StateViewTracers{svtTraceTracer} = lnStateViewTracers

ouroboros-consensus-diffusion/test/consensus-test/Test/Consensus/PeerSimulator/Tests/LinkedThreads.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,4 +72,4 @@ prop_chainSyncKillsBlockFetch = do
7272
(Time 0, scheduleHeaderPoint firstBlock)
7373
]
7474
psMinEndTime = Time $ timeout + 1
75-
in PointSchedule {psSchedule, psMinEndTime}
75+
in PointSchedule {psSchedule, psStartOrder = [], psMinEndTime}

ouroboros-consensus-diffusion/test/consensus-test/Test/Consensus/PeerSimulator/Tests/Rollback.hs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,11 @@ rollbackSchedule n blockTree =
9595
, banalSchedulePoints trunkSuffix
9696
, banalSchedulePoints (btbSuffix branch)
9797
]
98-
in mkPointSchedule $ peersOnlyHonest $ zip (map (Time . (/30)) [0..]) schedulePoints
98+
in PointSchedule {
99+
psSchedule = peersOnlyHonest $ zip (map (Time . (/30)) [0..]) schedulePoints,
100+
psStartOrder = [],
101+
psMinEndTime = Time 0
102+
}
99103
where
100104
banalSchedulePoints :: AnchoredFragment blk -> [SchedulePoint blk]
101105
banalSchedulePoints = concatMap banalSchedulePoints' . toOldestFirst

ouroboros-consensus-diffusion/test/consensus-test/Test/Consensus/PeerSimulator/Tests/Timeouts.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,4 +70,4 @@ prop_timeouts mustTimeout = do
7070
]
7171
-- This keeps the test running long enough to pass the timeout by 'offset'.
7272
psMinEndTime = Time $ timeout + offset
73-
in PointSchedule {psSchedule, psMinEndTime}
73+
in PointSchedule {psSchedule, psStartOrder = [], psMinEndTime}

ouroboros-consensus-diffusion/test/consensus-test/Test/Consensus/PointSchedule.hs

Lines changed: 56 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ module Test.Consensus.PointSchedule (
3737
, ensureScheduleDuration
3838
, genesisNodeState
3939
, longRangeAttack
40-
, mkPointSchedule
4140
, peerSchedulesBlocks
4241
, peerStates
4342
, peersStates
@@ -55,7 +54,6 @@ import Control.Monad.Class.MonadTime.SI (Time (Time), addTime,
5554
import Control.Monad.ST (ST)
5655
import Data.Functor (($>))
5756
import Data.List (mapAccumL, partition, scanl')
58-
import qualified Data.Map.Strict as Map
5957
import Data.Maybe (catMaybes, fromMaybe, mapMaybe)
6058
import Data.Time (DiffTime)
6159
import Data.Word (Word64)
@@ -77,8 +75,8 @@ import Test.Consensus.BlockTree (BlockTree (..), BlockTreeBranch (..),
7775
import Test.Consensus.PeerSimulator.StateView (StateView)
7876
import Test.Consensus.PointSchedule.NodeState (NodeState (..),
7977
genesisNodeState)
80-
import Test.Consensus.PointSchedule.Peers (Peer (..), Peers (..),
81-
peers', peersList)
78+
import Test.Consensus.PointSchedule.Peers (Peer (..), PeerId,
79+
Peers (..), getPeerIds, peers', peersList)
8280
import Test.Consensus.PointSchedule.SinglePeer
8381
(IsTrunk (IsBranch, IsTrunk), PeerScheduleParams (..),
8482
SchedulePoint (..), defaultPeerScheduleParams, mergeOn,
@@ -97,21 +95,24 @@ prettyPointSchedule ::
9795
(CondenseList (NodeState blk)) =>
9896
PointSchedule blk ->
9997
[String]
100-
prettyPointSchedule peers =
101-
[ "honest peers: " ++ show (Map.size (honestPeers $ psSchedule peers))
102-
, "adversaries: " ++ show (Map.size (adversarialPeers $ psSchedule peers))
103-
, "minimal duration: " ++ show (psMinEndTime peers)
104-
] ++
105-
zipWith3
106-
(\number time peerState ->
107-
number ++ ": " ++ peerState ++ " @ " ++ time
108-
)
109-
(condenseListWithPadding PadLeft $ fst <$> numberedPeersStates)
110-
(showDT . fst . snd <$> numberedPeersStates)
111-
(condenseList $ (snd . snd) <$> numberedPeersStates)
98+
prettyPointSchedule ps@PointSchedule {psStartOrder, psMinEndTime} =
99+
[]
100+
++ [ "psSchedule ="
101+
]
102+
++ ( zipWith3
103+
( \number time peerState ->
104+
" " ++ number ++ ": " ++ peerState ++ " @ " ++ time
105+
)
106+
(condenseListWithPadding PadLeft $ fst <$> numberedPeersStates)
107+
(showDT . fst . snd <$> numberedPeersStates)
108+
(condenseList $ (snd . snd) <$> numberedPeersStates)
109+
)
110+
++ [ "psStartOrder = " ++ show psStartOrder,
111+
"psMinEndTime = " ++ show psMinEndTime
112+
]
112113
where
113114
numberedPeersStates :: [(Int, (Time, Peer (NodeState blk)))]
114-
numberedPeersStates = zip [0..] (peersStates peers)
115+
numberedPeersStates = zip [0 ..] (peersStates ps)
115116

116117
showDT :: Time -> String
117118
showDT (Time dt) = printf "%.6f" (realToFrac dt :: Double)
@@ -177,15 +178,17 @@ peerScheduleBlocks = mapMaybe (withOriginToMaybe . schedulePointToBlock . snd)
177178
data PointSchedule blk = PointSchedule {
178179
-- | The actual point schedule
179180
psSchedule :: Peers (PeerSchedule blk),
181+
-- | The order in which the peers start and connect to the node under test.
182+
-- The peers that are absent from 'psSchedule' are ignored; the peers from
183+
-- 'psSchedule' that are absent of 'psStartOrder' are started in the end in
184+
-- the order of 'PeerId'.
185+
psStartOrder :: [PeerId],
180186
-- | Minimum duration for the simulation of this point schedule.
181187
-- If no point in the schedule is larger than 'psMinEndTime',
182188
-- the simulation will still run until this time is reached.
183189
psMinEndTime :: Time
184190
}
185191

186-
mkPointSchedule :: Peers (PeerSchedule blk) -> PointSchedule blk
187-
mkPointSchedule sch = PointSchedule sch $ Time 0
188-
189192
-- | List of all blocks appearing in the schedules.
190193
peerSchedulesBlocks :: Peers (PeerSchedule blk) -> [blk]
191194
peerSchedulesBlocks = concatMap (peerScheduleBlocks . value) . peersList
@@ -208,7 +211,11 @@ longRangeAttack ::
208211
longRangeAttack BlockTree {btTrunk, btBranches = [branch]} g = do
209212
honest <- peerScheduleFromTipPoints g honParams [(IsTrunk, [AF.length btTrunk - 1])] btTrunk []
210213
adv <- peerScheduleFromTipPoints g advParams [(IsBranch, [AF.length (btbFull branch) - 1])] btTrunk [btbFull branch]
211-
pure $ mkPointSchedule $ peers' [honest] [adv]
214+
pure $ PointSchedule {
215+
psSchedule = peers' [honest] [adv],
216+
psStartOrder = [],
217+
psMinEndTime = Time 0
218+
}
212219
where
213220
honParams = defaultPeerScheduleParams {pspHeaderDelayInterval = (0.3, 0.4)}
214221
advParams = defaultPeerScheduleParams {pspTipDelayInterval = (0, 0.1)}
@@ -240,6 +247,7 @@ uniformPoints PointsGeneratorParams {pgpExtraHonestPeers, pgpDowntime} = case pg
240247
-- Include rollbacks in a percentage of adversaries, in which case that peer uses two branchs.
241248
--
242249
uniformPointsWithExtraHonestPeers ::
250+
forall g m blk.
243251
(StatefulGen g m, AF.HasHeader blk) =>
244252
Int ->
245253
BlockTree blk ->
@@ -254,7 +262,9 @@ uniformPointsWithExtraHonestPeers
254262
honests <- replicateM (extraHonestPeers + 1) $
255263
mkSchedule [(IsTrunk, [honestTip0 .. AF.length btTrunk - 1])] []
256264
advs <- takeBranches btBranches
257-
pure $ mkPointSchedule $ peers' honests advs
265+
let psSchedule = peers' honests advs
266+
psStartOrder <- shuffle (getPeerIds psSchedule)
267+
pure $ PointSchedule {psSchedule, psStartOrder, psMinEndTime = Time 0}
258268
where
259269
takeBranches = \case
260270
[] -> pure []
@@ -305,6 +315,15 @@ uniformPointsWithExtraHonestPeers
305315

306316
rollbackProb = 0.2
307317

318+
-- Inefficient implementation, but sufficient for small lists.
319+
shuffle :: [a] -> m [a]
320+
shuffle [] = pure []
321+
shuffle xs = do
322+
i <- Random.uniformRM (0, length xs - 1) g
323+
let x = xs !! i
324+
xs' = take i xs ++ drop (i+1) xs
325+
(x :) <$> shuffle xs'
326+
308327
minusClamp :: (Ord a, Num a) => a -> a -> a
309328
minusClamp a b | a <= b = 0
310329
| otherwise = a - b
@@ -361,6 +380,7 @@ syncTips honests advs =
361380
--
362381
-- Includes rollbacks in some schedules.
363382
uniformPointsWithExtraHonestPeersAndDowntime ::
383+
forall g m blk.
364384
(StatefulGen g m, AF.HasHeader blk) =>
365385
Int ->
366386
SecurityParam ->
@@ -383,7 +403,9 @@ uniformPointsWithExtraHonestPeersAndDowntime
383403
mkSchedule [(IsTrunk, [honestTip0, minusClamp (AF.length btTrunk) 1])] []
384404
advs <- takeBranches pauseSlot btBranches
385405
let (honests', advs') = syncTips honests advs
386-
pure $ mkPointSchedule $ peers' honests' advs'
406+
psSchedule = peers' honests' advs'
407+
psStartOrder <- shuffle $ getPeerIds psSchedule
408+
pure $ PointSchedule {psSchedule, psStartOrder, psMinEndTime = Time 0}
387409
where
388410
takeBranches pause = \case
389411
[] -> pure []
@@ -438,6 +460,15 @@ uniformPointsWithExtraHonestPeersAndDowntime
438460

439461
rollbackProb = 0.2
440462

463+
-- Inefficient implementation, but sufficient for small lists.
464+
shuffle :: [a] -> m [a]
465+
shuffle [] = pure []
466+
shuffle xs = do
467+
i <- Random.uniformRM (0, length xs - 1) g
468+
let x = xs !! i
469+
xs' = take i xs ++ drop (i+1) xs
470+
(x :) <$> shuffle xs'
471+
441472
newtype ForecastRange = ForecastRange { unForecastRange :: Word64 }
442473
deriving (Show)
443474

@@ -545,9 +576,10 @@ stToGen gen = do
545576
pure (runSTGen_ seed gen)
546577

547578
ensureScheduleDuration :: GenesisTest blk a -> PointSchedule blk -> PointSchedule blk
548-
ensureScheduleDuration gt PointSchedule{psSchedule, psMinEndTime} =
579+
ensureScheduleDuration gt PointSchedule{psSchedule, psStartOrder, psMinEndTime} =
549580
PointSchedule
550581
{ psSchedule
582+
, psStartOrder
551583
, psMinEndTime = max psMinEndTime (Time endingDelay)
552584
}
553585
where

ouroboros-consensus-diffusion/test/consensus-test/Test/Consensus/PointSchedule/Shrinking.hs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ shrinkPeerSchedules ::
4141
StateView TestBlock ->
4242
[GenesisTestFull TestBlock]
4343
shrinkPeerSchedules genesisTest@GenesisTest{gtBlockTree, gtSchedule} _stateView =
44-
let PointSchedule {psSchedule} = gtSchedule
44+
let PointSchedule {psSchedule, psStartOrder} = gtSchedule
4545
simulationDuration = duration gtSchedule
4646
trimmedBlockTree sch = trimBlockTree' sch gtBlockTree
4747
shrunkAdversarialPeers =
@@ -50,6 +50,7 @@ shrinkPeerSchedules genesisTest@GenesisTest{gtBlockTree, gtSchedule} _stateView
5050
genesisTest
5151
{ gtSchedule = PointSchedule
5252
{ psSchedule = shrunkSchedule
53+
, psStartOrder
5354
, psMinEndTime = simulationDuration
5455
}
5556
, gtBlockTree = trimmedBlockTree shrunkSchedule
@@ -61,6 +62,7 @@ shrinkPeerSchedules genesisTest@GenesisTest{gtBlockTree, gtSchedule} _stateView
6162
<&> \shrunkSchedule -> genesisTest
6263
{ gtSchedule = PointSchedule
6364
{ psSchedule = shrunkSchedule
65+
, psStartOrder
6466
, psMinEndTime = simulationDuration
6567
}
6668
}
@@ -81,6 +83,7 @@ shrinkByRemovingAdversaries genesisTest@GenesisTest{gtSchedule, gtBlockTree} _st
8183
in genesisTest
8284
{ gtSchedule = PointSchedule
8385
{ psSchedule = shrunkSchedule
86+
, psStartOrder = psStartOrder gtSchedule
8487
, psMinEndTime = simulationDuration
8588
}
8689
, gtBlockTree = trimmedBlockTree

0 commit comments

Comments
 (0)