Skip to content

Commit 0c8ce7c

Browse files
committed
WIP implementing state-machine tests for PerasVoteDB
1 parent 9019813 commit 0c8ce7c

File tree

8 files changed

+647
-28
lines changed

8 files changed

+647
-28
lines changed

ouroboros-consensus/ouroboros-consensus.cabal

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -804,6 +804,9 @@ test-suite storage-test
804804
Test.Ouroboros.Storage.PerasCertDB
805805
Test.Ouroboros.Storage.PerasCertDB.Model
806806
Test.Ouroboros.Storage.PerasCertDB.StateMachine
807+
Test.Ouroboros.Storage.PerasVoteDB
808+
Test.Ouroboros.Storage.PerasVoteDB.Model
809+
Test.Ouroboros.Storage.PerasVoteDB.StateMachine
807810
Test.Ouroboros.Storage.VolatileDB
808811
Test.Ouroboros.Storage.VolatileDB.Mock
809812
Test.Ouroboros.Storage.VolatileDB.Model
@@ -816,6 +819,7 @@ test-suite storage-test
816819
bifunctors,
817820
bytestring,
818821
cardano-binary,
822+
cardano-crypto-class,
819823
cardano-ledger-binary:testlib,
820824
cardano-ledger-core:{cardano-ledger-core, testlib},
821825
cardano-slotting:{cardano-slotting, testlib},

ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/Peras/Vote/Aggregation.hs

Lines changed: 39 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ data PerasRoundVoteState blk
5050
}
5151
| PerasRoundVoteStateQuorumReachedAlready
5252
{ prvsRoundNo :: !PerasRoundNo
53+
, prvsExcessVotes :: !Word64
5354
, prvsLoserStates :: !(Map (Point blk) (PerasTargetVoteState blk 'Loser))
5455
, prvsWinnerState :: !(PerasTargetVoteState blk 'Winner)
5556
}
@@ -64,8 +65,8 @@ prvsMaybeCert :: PerasRoundVoteState blk -> Maybe (ValidatedPerasCert blk)
6465
prvsMaybeCert = \case
6566
PerasRoundVoteStateQuorumNotReached{} ->
6667
Nothing
67-
PerasRoundVoteStateQuorumReachedAlready _ _ winner ->
68-
let (PerasTargetVoteWinner _ _ cert) = winner
68+
PerasRoundVoteStateQuorumReachedAlready _ _ _ winner ->
69+
let (PerasTargetVoteWinner _ cert) = winner
6970
in Just cert
7071

7172
-- | Create a fresh round vote state for the given round number
@@ -138,31 +139,43 @@ updatePerasRoundVoteState vote cfg roundState = do
138139
pure $
139140
PerasRoundVoteStateQuorumReachedAlready
140141
{ prvsRoundNo = prvsRoundNo roundState
142+
, prvsExcessVotes = 0
141143
, prvsLoserStates = loserStates
142144
, prvsWinnerState = winnerState
143145
}
144146

145147
-- Quorum already reached
146148
state@PerasRoundVoteStateQuorumReachedAlready{prvsLoserStates, prvsWinnerState} -> do
147-
let votePoint = getPerasVoteBlock vote
148-
winnerPoint = getPerasVoteBlock prvsWinnerState
149-
existingOrFreshLoserVoteState =
150-
fromMaybe (freshLoserVoteState (getPerasVoteTarget vote))
151-
152-
updateMaybeLoser mState =
153-
updateLoserVoteState cfg vote (existingOrFreshLoserVoteState mState)
154-
`onErr` \err ->
155-
RoundVoteStateLoserAboveQuorum prvsWinnerState err
149+
let votePoint =
150+
getPerasVoteBlock vote
151+
winnerPoint =
152+
getPerasVoteBlock prvsWinnerState
156153

157154
if votePoint == winnerPoint
158-
then
155+
-- The vote ratifies the winner => update winner state
156+
then do
157+
let winnerState' = updateWinnerVoteState vote prvsWinnerState
159158
pure $
160-
state{prvsWinnerState = updateWinnerVoteState vote prvsWinnerState}
159+
state
160+
{ prvsExcessVotes = prvsExcessVotes state + 1
161+
, prvsWinnerState = winnerState'
162+
}
163+
164+
-- The vote is for a loser => update loser state
161165
else do
162-
prvsLoserStates' <-
163-
Map.alterF (fmap Just . updateMaybeLoser) votePoint prvsLoserStates
166+
let existingOrFreshLoserVoteState =
167+
fromMaybe (freshLoserVoteState (getPerasVoteTarget vote))
168+
updateMaybeLoserVoteState mState =
169+
fmap Just $
170+
updateLoserVoteState cfg vote (existingOrFreshLoserVoteState mState)
171+
`onErr` \err ->
172+
RoundVoteStateLoserAboveQuorum prvsWinnerState err
173+
prvsLoserStates' <- Map.alterF updateMaybeLoserVoteState votePoint prvsLoserStates
164174
pure $
165-
state{prvsLoserStates = prvsLoserStates'}
175+
state
176+
{ prvsExcessVotes = prvsExcessVotes state + 1
177+
, prvsLoserStates = prvsLoserStates'
178+
}
166179

167180
-- | Updates the round vote states map with the given vote.
168181
--
@@ -243,9 +256,11 @@ pattern VoteDidntGenerateNewCert <-
243256
voteGeneratedCert :: PerasRoundVoteState blk -> Maybe (ValidatedPerasCert blk)
244257
voteGeneratedCert = \case
245258
PerasRoundVoteStateQuorumReachedAlready
246-
{ prvsWinnerState = PerasTargetVoteWinner _ 0 cert
259+
{ prvsExcessVotes = 0
260+
, prvsWinnerState = PerasTargetVoteWinner _ cert
247261
} -> Just cert
248-
_ -> Nothing
262+
_ ->
263+
Nothing
249264

250265
{-------------------------------------------------------------------------------
251266
Peras target vote tally
@@ -340,9 +355,6 @@ data PerasTargetVoteState blk (status :: PerasTargetVoteStatus) where
340355
PerasTargetVoteState blk 'Loser
341356
PerasTargetVoteWinner ::
342357
!(PerasTargetVoteTally blk) ->
343-
-- | Number of extra votes received since the target was elected winner and
344-
-- the cert was forged.
345-
!Word64 ->
346358
!(ValidatedPerasCert blk) ->
347359
PerasTargetVoteState blk 'Winner
348360

@@ -380,8 +392,8 @@ instance
380392
noThunks ctx tally
381393
noThunks ctx (PerasTargetVoteLoser tally) =
382394
noThunks ctx tally
383-
noThunks ctx (PerasTargetVoteWinner tally w cert) =
384-
noThunks ctx (tally, w, cert)
395+
noThunks ctx (PerasTargetVoteWinner tally cert) =
396+
noThunks ctx (tally, cert)
385397

386398
instance HasPerasVoteTarget (PerasTargetVoteState blk status) blk where
387399
getPerasVoteTarget = getPerasVoteTarget . ptvsVoteTally
@@ -397,7 +409,7 @@ ptvsVoteTally :: PerasTargetVoteState blk status -> PerasTargetVoteTally blk
397409
ptvsVoteTally = \case
398410
PerasTargetVoteCandidate tally -> tally
399411
PerasTargetVoteLoser tally -> tally
400-
PerasTargetVoteWinner tally _ _ -> tally
412+
PerasTargetVoteWinner tally _ -> tally
401413

402414
freshCandidateVoteState :: PerasVoteTarget blk -> PerasTargetVoteState blk 'Candidate
403415
freshCandidateVoteState target =
@@ -443,7 +455,7 @@ updateCandidateVoteState cfg vote oldState = do
443455
in if stakeAboveThreshold cfg (ptvtTotalStake newVoteTally)
444456
then do
445457
cert <- forgePerasCert cfg (ptvtTarget newVoteTally) voteList
446-
pure $ BecameWinner (PerasTargetVoteWinner newVoteTally 0 cert)
458+
pure $ BecameWinner (PerasTargetVoteWinner newVoteTally cert)
447459
else
448460
pure $ RemainedCandidate (PerasTargetVoteCandidate newVoteTally)
449461

@@ -475,8 +487,8 @@ updateWinnerVoteState ::
475487
PerasTargetVoteState blk 'Winner
476488
updateWinnerVoteState vote oldState =
477489
let newVoteTally = updateTargetVoteTally vote (ptvsVoteTally oldState)
478-
(PerasTargetVoteWinner _ extraCertCount cert) = oldState
479-
in PerasTargetVoteWinner newVoteTally (extraCertCount + 1) cert
490+
(PerasTargetVoteWinner _ cert) = oldState
491+
in PerasTargetVoteWinner newVoteTally cert
480492

481493
{-------------------------------------------------------------------------------
482494
Helpers

ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/Storage/PerasVoteDB/API.hs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
{-# LANGUAGE DerivingVia #-}
55
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
66
{-# LANGUAGE ScopedTypeVariables #-}
7+
{-# LANGUAGE UndecidableInstances #-}
78

89
module Ouroboros.Consensus.Storage.PerasVoteDB.API
910
( PerasVoteDB (..)
@@ -55,7 +56,7 @@ data PerasVoteSnapshot blk = PerasVoteSnapshot
5556

5657
-- | A sequence number, incremented every time we receive a new vote.
5758
newtype PerasVoteTicketNo = PerasVoteTicketNo Word64
58-
deriving stock Show
59+
deriving stock (Generic, Show)
5960
deriving newtype (Eq, Ord, Enum, NoThunks)
6061

6162
zeroPerasVoteTicketNo :: PerasVoteTicketNo

ouroboros-consensus/test/storage-test/Test/Ouroboros/Storage.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import qualified Test.Ouroboros.Storage.ChainDB as ChainDB
66
import qualified Test.Ouroboros.Storage.ImmutableDB as ImmutableDB
77
import qualified Test.Ouroboros.Storage.LedgerDB as LedgerDB
88
import qualified Test.Ouroboros.Storage.PerasCertDB as PerasCertDB
9+
import qualified Test.Ouroboros.Storage.PerasVoteDB as PerasVoteDB
910
import qualified Test.Ouroboros.Storage.VolatileDB as VolatileDB
1011
import Test.Tasty (TestTree, testGroup)
1112

@@ -22,4 +23,5 @@ tests =
2223
, LedgerDB.tests
2324
, ChainDB.tests
2425
, PerasCertDB.tests
26+
, PerasVoteDB.tests
2527
]

ouroboros-consensus/test/storage-test/Test/Ouroboros/Storage/Orphans.hs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
{-# LANGUAGE FlexibleInstances #-}
12
{-# LANGUAGE StandaloneDeriving #-}
23
{-# OPTIONS_GHC -Wno-orphans #-}
34

@@ -19,6 +20,7 @@ import Ouroboros.Consensus.Util.CallStack
1920
import System.FS.API.Types (FsError, sameFsError)
2021
import Test.QuickCheck.StateModel (HasVariables)
2122
import Test.QuickCheck.StateModel.Variables (HasVariables (..))
23+
import Cardano.Crypto.Hash.Class (PackedBytes)
2224

2325
{-------------------------------------------------------------------------------
2426
PrettyCallStack
@@ -76,3 +78,17 @@ deriving instance StandardHash blk => Eq (ChainDbError blk)
7678

7779
instance HasVariables NominalDiffTime where
7880
getAllVariables _ = mempty
81+
82+
{-------------------------------------------------------------------------------
83+
Rational
84+
-------------------------------------------------------------------------------}
85+
86+
instance HasVariables Rational where
87+
getAllVariables _ = mempty
88+
89+
{-------------------------------------------------------------------------------
90+
PackedBytes
91+
-------------------------------------------------------------------------------}
92+
93+
instance HasVariables (PackedBytes a) where
94+
getAllVariables _ = mempty
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
module Test.Ouroboros.Storage.PerasVoteDB (tests) where
2+
3+
import qualified Test.Ouroboros.Storage.PerasVoteDB.StateMachine as StateMachine
4+
import Test.Tasty (TestTree, testGroup)
5+
6+
--
7+
-- The list of all PerasVoteDB tests
8+
--
9+
10+
tests :: TestTree
11+
tests =
12+
testGroup
13+
"PerasVoteDB"
14+
[ StateMachine.tests
15+
]

0 commit comments

Comments
 (0)