@@ -19,7 +19,7 @@ module Test.Consensus.Genesis.Tests.Uniform (
19
19
import Cardano.Slotting.Slot (SlotNo (SlotNo ), WithOrigin (.. ))
20
20
import Control.Monad (replicateM )
21
21
import Control.Monad.Class.MonadTime.SI (Time , addTime )
22
- import Data.List (intercalate , sort )
22
+ import Data.List (intercalate , sort , uncons )
23
23
import qualified Data.List.NonEmpty as NE
24
24
import qualified Data.Map.Strict as Map
25
25
import Data.Maybe (fromMaybe , mapMaybe )
@@ -40,7 +40,8 @@ import Test.Consensus.PeerSimulator.Run (SchedulerConfig (..),
40
40
defaultSchedulerConfig )
41
41
import Test.Consensus.PeerSimulator.StateView
42
42
import Test.Consensus.PointSchedule
43
- import Test.Consensus.PointSchedule.Peers (Peers (.. ), isHonestPeerId )
43
+ import Test.Consensus.PointSchedule.Peers (Peers (.. ), getPeerIds ,
44
+ isHonestPeerId , peers' )
44
45
import Test.Consensus.PointSchedule.Shrinking
45
46
(shrinkByRemovingAdversaries , shrinkPeerSchedules )
46
47
import Test.Consensus.PointSchedule.SinglePeer
@@ -72,7 +73,8 @@ tests =
72
73
-- because this test writes the immutable chain to disk and `instance Binary TestBlock`
73
74
-- chokes on long chains.
74
75
adjustQuickCheckMaxSize (const 10 ) $
75
- testProperty " the node is shut down and restarted after some time" prop_downtime
76
+ testProperty " the node is shut down and restarted after some time" prop_downtime,
77
+ testProperty " block fetch leashing attack" prop_blockFetchLeashingAttack
76
78
]
77
79
78
80
theProperty ::
@@ -416,3 +418,44 @@ prop_downtime = forAllGenesisTest
416
418
{ pgpExtraHonestPeers = fromIntegral (gtExtraHonestPeers gt)
417
419
, pgpDowntime = DowntimeWithSecurityParam (gtSecurityParam gt)
418
420
}
421
+
422
+ prop_blockFetchLeashingAttack :: Property
423
+ prop_blockFetchLeashingAttack =
424
+ forAllGenesisTest
425
+ (disableBoringTimeouts <$> genChains (pure 0 ) `enrichedWith` genBlockFetchLeashingSchedule)
426
+ defaultSchedulerConfig
427
+ { scEnableLoE = True ,
428
+ scEnableLoP = True ,
429
+ scEnableCSJ = True
430
+ }
431
+ shrinkPeerSchedules
432
+ theProperty
433
+ where
434
+ genBlockFetchLeashingSchedule :: GenesisTest TestBlock () -> QC. Gen (PointSchedule TestBlock )
435
+ genBlockFetchLeashingSchedule genesisTest = do
436
+ PointSchedule {psSchedule, psMinEndTime} <-
437
+ stToGen $
438
+ uniformPoints
439
+ (PointsGeneratorParams {pgpExtraHonestPeers = 1 , pgpDowntime = NoDowntime })
440
+ (gtBlockTree genesisTest)
441
+ peers <- QC. shuffle $ Map. elems $ honestPeers psSchedule
442
+ let (honest, adversaries) = fromMaybe (error " blockFetchLeashingAttack" ) $ uncons peers
443
+ adversaries' = map (filter (not . isBlockPoint . snd )) adversaries
444
+ psSchedule' = peers' [honest] adversaries'
445
+ -- Important to shuffle the order in which the peers start, otherwise the
446
+ -- honest peer starts first and systematically becomes dynamo.
447
+ psStartOrder <- shuffle $ getPeerIds psSchedule'
448
+ pure $ PointSchedule {psSchedule = psSchedule', psStartOrder, psMinEndTime}
449
+
450
+ isBlockPoint :: SchedulePoint blk -> Bool
451
+ isBlockPoint (ScheduleBlockPoint _) = True
452
+ isBlockPoint _ = False
453
+
454
+ disableBoringTimeouts gt =
455
+ gt
456
+ { gtChainSyncTimeouts =
457
+ (gtChainSyncTimeouts gt)
458
+ { mustReplyTimeout = Nothing ,
459
+ idleTimeout = Nothing
460
+ }
461
+ }
0 commit comments