Skip to content

Commit

Permalink
Tests for honest peer shrinking function
Browse files Browse the repository at this point in the history
  • Loading branch information
nbacquey authored and facundominguez committed Apr 24, 2024
1 parent 6b9babf commit a2bfae0
Show file tree
Hide file tree
Showing 6 changed files with 119 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,7 @@ test-suite consensus-test
Test.Consensus.PointSchedule
Test.Consensus.PointSchedule.Peers
Test.Consensus.PointSchedule.Shrinking
Test.Consensus.PointSchedule.Shrinking.Tests
Test.Consensus.PointSchedule.SinglePeer
Test.Consensus.PointSchedule.SinglePeer.Indices
Test.Consensus.PointSchedule.Tests
Expand Down
2 changes: 2 additions & 0 deletions ouroboros-consensus-diffusion/test/consensus-test/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import qualified Test.Consensus.GSM (tests)
import qualified Test.Consensus.HardFork.Combinator (tests)
import qualified Test.Consensus.Node (tests)
import qualified Test.Consensus.PeerSimulator.Tests (tests)
import qualified Test.Consensus.PointSchedule.Shrinking.Tests (tests)
import qualified Test.Consensus.PointSchedule.Tests (tests)
import Test.Tasty
import Test.Util.TestEnv (defaultMainWithTestEnv,
Expand All @@ -25,5 +26,6 @@ tests =
, Test.Consensus.Genesis.Tests.tests
, testGroup "GSM" Test.Consensus.GSM.tests
, Test.Consensus.PeerSimulator.Tests.tests
, Test.Consensus.PointSchedule.Shrinking.Tests.tests
, Test.Consensus.PointSchedule.Tests.tests
]
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@
-- block tree with the right age (roughly @k@ blocks from the tip). Contrary to
-- other tests cases (eg. long range attack), the schedules are not particularly
-- biased towards a specific situation.
module Test.Consensus.Genesis.Tests.Uniform (tests) where
module Test.Consensus.Genesis.Tests.Uniform (
genUniformSchedulePoints
, tests
) where

import Cardano.Slotting.Slot (SlotNo (SlotNo), WithOrigin (..))
import Control.Monad (replicateM)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ data Peers a =
instance Functor Peers where
fmap f Peers {honest, others} = Peers {honest = f <$> honest, others = fmap f <$> others}

instance Foldable Peers where
foldMap f Peers {honest, others} = (f . value) honest <> foldMap (f . value) others

-- | A set of peers with only one honest peer carrying the given value.
peersOnlyHonest :: a -> Peers a
peersOnlyHonest value =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@

module Test.Consensus.PointSchedule.Shrinking (
shrinkByRemovingAdversaries
-- | Exported only for testing (that is, checking the properties of the function)
, shrinkHonestPeer
, shrinkPeerSchedules
, trimBlockTree'
) where

import Control.Monad.Class.MonadTime.SI (DiffTime, Time, addTime,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}

-- | Test properties of the shrinking functions
module Test.Consensus.PointSchedule.Shrinking.Tests (tests) where

import Data.Foldable (toList)
import Data.Map (keys)
import Data.Maybe (mapMaybe)
import Test.Consensus.Genesis.Setup (genChains)
import Test.Consensus.Genesis.Tests.Uniform (genUniformSchedulePoints)
import Test.Consensus.PointSchedule (PeerSchedule, PeersSchedule,
prettyPeersSchedule)
import Test.Consensus.PointSchedule.Peers (Peer (..), Peers (..))
import Test.Consensus.PointSchedule.Shrinking (shrinkHonestPeer)
import Test.Consensus.PointSchedule.SinglePeer (SchedulePoint (..))
import Test.QuickCheck (Property, conjoin, counterexample)
import Test.Tasty
import Test.Tasty.QuickCheck (choose, forAllBlind, testProperty)
import Test.Util.TestBlock (TestBlock)

tests :: TestTree
tests =
testGroup "shrinking functions"
[ testGroup "honest peer shrinking"
[ testProperty "actually shortens the schedule" prop_shortens
, testProperty "preserves the final state all peers" prop_preservesFinalStates
, testProperty "doesn't remove points of the adversarial schedule" prop_preserversAdversarial
]
]

prop_shortens :: Property
prop_shortens = checkShrinkProperty isShorterThan

prop_preservesFinalStates :: Property
prop_preservesFinalStates = checkShrinkProperty doesNotChangeFinalState

prop_preserversAdversarial :: Property
prop_preserversAdversarial = checkShrinkProperty doesNotRemoveAdversarialPoints

-- | Apparently, `unsnoc` hasn't been invented yet, so we'll do this manually
lastM :: [a] -> Maybe a
lastM [] = Nothing
lastM [a] = Just a
lastM (_:ps) = lastM ps

samePeers :: PeersSchedule blk -> PeersSchedule blk -> Bool
samePeers sch1 sch2 = (keys $ others sch1) == (keys $ others sch2)

-- | Checks whether at least one peer schedule in the second given peers schedule
-- is shorter than its corresponding one in the fist given peers schedule. “Shorter”
-- here means that it executes in less time.
isShorterThan :: PeersSchedule blk -> PeersSchedule blk -> Bool
isShorterThan original shrunk =
samePeers original shrunk
&& (or $ zipWith
(\oldSch newSch -> (fst <$> lastM newSch) < (fst <$> lastM oldSch))
(toList original)
(toList shrunk)
)

doesNotChangeFinalState :: Eq blk => PeersSchedule blk -> PeersSchedule blk -> Bool
doesNotChangeFinalState original shrunk =
samePeers original shrunk
&& (and $ zipWith
(\oldSch newSch ->
lastTP oldSch == lastTP newSch &&
lastHP oldSch == lastHP newSch &&
lastBP oldSch == lastBP newSch
)
(toList original)
(toList shrunk)
)
where
lastTP :: PeerSchedule blk -> Maybe (SchedulePoint blk)
lastTP sch = lastM $ mapMaybe (\case (_, p@(ScheduleTipPoint _)) -> Just p ; _ -> Nothing) sch
lastHP :: PeerSchedule blk -> Maybe (SchedulePoint blk)
lastHP sch = lastM $ mapMaybe (\case (_, p@(ScheduleHeaderPoint _)) -> Just p ; _ -> Nothing) sch
lastBP :: PeerSchedule blk -> Maybe (SchedulePoint blk)
lastBP sch = lastM $ mapMaybe (\case (_, p@(ScheduleBlockPoint _)) -> Just p ; _ -> Nothing) sch

doesNotRemoveAdversarialPoints :: Eq blk => PeersSchedule blk -> PeersSchedule blk -> Bool
doesNotRemoveAdversarialPoints original shrunk =
samePeers original shrunk
&& (and $ zipWith
(\oldSch newSch -> fmap snd oldSch == fmap snd newSch)
(toList $ (fmap value) $ others original)
(toList $ (fmap value) $ others shrunk)
)

checkShrinkProperty :: (PeersSchedule TestBlock -> PeersSchedule TestBlock -> Bool) -> Property
checkShrinkProperty prop =
forAllBlind
(genChains (choose (1, 4)) >>= genUniformSchedulePoints)
(\schedule ->
conjoin $ map
(\shrunk ->
counterexample
( "Original schedule:\n"
++ unlines (map (" " ++) $ prettyPeersSchedule schedule)
++ "\nShrunk schedule:\n"
++ unlines (map (" " ++) $ prettyPeersSchedule shrunk)
)
(prop schedule shrunk)
)
(shrinkHonestPeer schedule)
)

0 comments on commit a2bfae0

Please sign in to comment.