Skip to content

Commit d24f776

Browse files
committed
Add tests for PerasWeightSnapshot
1 parent 35de907 commit d24f776

File tree

3 files changed

+142
-0
lines changed

3 files changed

+142
-0
lines changed

ouroboros-consensus/ouroboros-consensus.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -598,6 +598,7 @@ test-suite consensus-test
598598
Test.Consensus.MiniProtocol.ChainSync.CSJ
599599
Test.Consensus.MiniProtocol.ChainSync.Client
600600
Test.Consensus.MiniProtocol.LocalStateQuery.Server
601+
Test.Consensus.Peras.WeightSnapshot
601602
Test.Consensus.Util.MonadSTM.NormalForm
602603
Test.Consensus.Util.Versioned
603604

ouroboros-consensus/test/consensus-test/Main.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import qualified Test.Consensus.MiniProtocol.BlockFetch.Client (tests)
1616
import qualified Test.Consensus.MiniProtocol.ChainSync.CSJ (tests)
1717
import qualified Test.Consensus.MiniProtocol.ChainSync.Client (tests)
1818
import qualified Test.Consensus.MiniProtocol.LocalStateQuery.Server (tests)
19+
import qualified Test.Consensus.Peras.WeightSnapshot (tests)
1920
import qualified Test.Consensus.Util.MonadSTM.NormalForm (tests)
2021
import qualified Test.Consensus.Util.Versioned (tests)
2122
import Test.Tasty
@@ -43,6 +44,7 @@ tests =
4344
, Test.Consensus.Mempool.Fairness.tests
4445
, Test.Consensus.Mempool.StateMachine.tests
4546
]
47+
, Test.Consensus.Peras.WeightSnapshot.tests
4648
, Test.Consensus.Util.MonadSTM.NormalForm.tests
4749
, Test.Consensus.Util.Versioned.tests
4850
, testGroup
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
{-# LANGUAGE BlockArguments #-}
2+
{-# LANGUAGE CPP #-}
3+
{-# LANGUAGE DerivingStrategies #-}
4+
{-# LANGUAGE NamedFieldPuns #-}
5+
{-# LANGUAGE ScopedTypeVariables #-}
6+
{-# LANGUAGE TupleSections #-}
7+
{-# LANGUAGE TypeApplications #-}
8+
9+
#if __GLASGOW_HASKELL__ >= 910
10+
{-# OPTIONS_GHC -Wno-x-partial #-}
11+
#endif
12+
13+
-- | Test that 'PerasWeightSnapshot' can correctly compute the weight of points
14+
-- and fragments.
15+
module Test.Consensus.Peras.WeightSnapshot (tests) where
16+
17+
import Data.Containers.ListUtils (nubOrd)
18+
import Data.Map.Strict (Map)
19+
import qualified Data.Map.Strict as Map
20+
import Data.Maybe (catMaybes)
21+
import Data.Traversable (for)
22+
import Ouroboros.Consensus.Block
23+
import Ouroboros.Consensus.Peras.Weight
24+
import Ouroboros.Consensus.Util.Condense
25+
import Ouroboros.Network.AnchoredFragment (AnchoredFragment)
26+
import qualified Ouroboros.Network.AnchoredFragment as AF
27+
import qualified Ouroboros.Network.Mock.Chain as Chain
28+
import Test.QuickCheck
29+
import Test.Tasty
30+
import Test.Tasty.QuickCheck
31+
import Test.Util.Orphans.Arbitrary ()
32+
import Test.Util.QuickCheck
33+
import Test.Util.TestBlock
34+
35+
tests :: TestTree
36+
tests =
37+
testGroup
38+
"PerasWeightSnapshot"
39+
[ testProperty "correctness" prop_perasWeightSnapshot
40+
]
41+
42+
prop_perasWeightSnapshot :: TestSetup -> Property
43+
prop_perasWeightSnapshot testSetup =
44+
tabulate "log₂ # of points" [show $ round @Double @Int $ logBase 2 (fromIntegral (length tsPoints))]
45+
. counterexample ("PerasWeightSnapshot: " <> show snap)
46+
$ conjoin
47+
[ conjoin
48+
[ counterexample ("Incorrect weight for " <> condense pt) $
49+
weightBoostOfPointReference pt =:= weightBoostOfPoint snap pt
50+
| pt <- tsPoints
51+
]
52+
, conjoin
53+
[ counterexample ("Incorrect weight for " <> condense frag) $
54+
weightBoostOfFragmentReference frag =:= weightBoostOfFragment snap frag
55+
| frag <- tsFragments
56+
]
57+
]
58+
where
59+
TestSetup
60+
{ tsWeights
61+
, tsPoints
62+
, tsFragments
63+
} = testSetup
64+
65+
snap = mkPerasWeightSnapshot $ Map.toList tsWeights
66+
67+
weightBoostOfPointReference :: Point TestBlock -> PerasWeight
68+
weightBoostOfPointReference pt = Map.findWithDefault mempty pt tsWeights
69+
70+
weightBoostOfFragmentReference :: AnchoredFragment TestBlock -> PerasWeight
71+
weightBoostOfFragmentReference frag =
72+
foldMap
73+
(weightBoostOfPointReference . blockPoint)
74+
(AF.toOldestFirst frag)
75+
76+
data TestSetup = TestSetup
77+
{ tsWeights :: Map (Point TestBlock) PerasWeight
78+
, tsPoints :: [Point TestBlock]
79+
-- ^ Check the weight of these points.
80+
, tsFragments :: [AnchoredFragment TestBlock]
81+
-- ^ Check the weight of these fragments.
82+
}
83+
deriving stock Show
84+
85+
instance Arbitrary TestSetup where
86+
arbitrary = do
87+
tree :: BlockTree <- arbitrary
88+
let tsPoints = nubOrd $ GenesisPoint : (blockPoint <$> treeToBlocks tree)
89+
treeChains = treeToChains tree
90+
tsWeights <- do
91+
boostedChain <- elements treeChains
92+
let boostablePts =
93+
GenesisPoint : (blockPoint <$> Chain.toOldestFirst boostedChain)
94+
Map.fromList . catMaybes <$> for boostablePts \pt -> do
95+
weight <-
96+
frequency
97+
[ (3, pure Nothing)
98+
, (1, Just . PerasWeight <$> choose (1, 10))
99+
]
100+
pure $ (pt,) <$> weight
101+
tsFragments <- for treeChains \chain -> do
102+
let lenChain = Chain.length chain
103+
fullFrag = Chain.toAnchoredFragment chain
104+
nTakeNewest <- choose (0, lenChain)
105+
nDropNewest <- choose (0, nTakeNewest)
106+
pure $
107+
AF.dropNewest nDropNewest $
108+
AF.anchorNewest (fromIntegral nTakeNewest) fullFrag
109+
pure
110+
TestSetup
111+
{ tsWeights
112+
, tsPoints
113+
, tsFragments
114+
}
115+
116+
shrink ts =
117+
concat
118+
[ [ ts{tsWeights = Map.fromList tsWeights'}
119+
| tsWeights' <-
120+
shrinkList
121+
-- Shrink boosted points to have weight 1.
122+
(\(pt, w) -> [(pt, w1) | w1 /= w])
123+
$ Map.toList tsWeights
124+
]
125+
, [ ts{tsPoints = tsPoints'}
126+
| tsPoints' <- shrinkList (\_pt -> []) tsPoints
127+
]
128+
, [ ts{tsFragments = tsFragments'}
129+
| tsFragments' <- shrinkList (\_frag -> []) tsFragments
130+
]
131+
]
132+
where
133+
w1 = PerasWeight 1
134+
135+
TestSetup
136+
{ tsWeights
137+
, tsPoints
138+
, tsFragments
139+
} = ts

0 commit comments

Comments
 (0)