Skip to content

Commit bf3a52c

Browse files
committed
Introduce Peras votes and helpers type classes
1 parent d51b1a1 commit bf3a52c

File tree

1 file changed

+154
-1
lines changed
  • ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/Block

1 file changed

+154
-1
lines changed

ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/Block/SupportsPeras.hs

Lines changed: 154 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
{-# LANGUAGE DataKinds #-}
12
{-# LANGUAGE DeriveAnyClass #-}
23
{-# LANGUAGE DeriveGeneric #-}
34
{-# LANGUAGE DerivingVia #-}
@@ -16,19 +17,30 @@ module Ouroboros.Consensus.Block.SupportsPeras
1617
, onPerasRoundNo
1718
, BlockSupportsPeras (..)
1819
, PerasCert (..)
20+
, PerasVote (..)
1921
, ValidatedPerasCert (..)
22+
, ValidatedPerasVote (..)
2023
, HasPerasCertRound (..)
2124
, HasPerasCertBoostedBlock (..)
2225
, HasPerasCertBoost (..)
26+
, HasPerasVoteRound (..)
27+
, HasPerasVoteBlock (..)
28+
, HasPerasVoteVoterId (..)
2329

2430
-- * Convenience re-exports
2531
, module Ouroboros.Consensus.Peras.Params
2632
) where
2733

34+
import qualified Cardano.Binary as KeyHash
35+
import Cardano.Ledger.Hashes (KeyHash, KeyRole (..))
36+
import Cardano.Ledger.State (IndividualPoolStake)
37+
import qualified Cardano.Ledger.State as SL
2838
import Codec.Serialise (Serialise (..))
2939
import Codec.Serialise.Decoding (decodeListLenOf)
3040
import Codec.Serialise.Encoding (encodeListLen)
3141
import Data.Coerce (coerce)
42+
import Data.Function (on)
43+
import qualified Data.Map as Map
3244
import Data.Proxy (Proxy (..))
3345
import Data.Word (Word64)
3446
import GHC.Generics (Generic)
@@ -40,6 +52,12 @@ import Ouroboros.Consensus.Util
4052
import Ouroboros.Consensus.Util.Condense
4153
import Quiet (Quiet (..))
4254

55+
{-------------------------------------------------------------------------------
56+
-- * Peras types
57+
-------------------------------------------------------------------------------}
58+
59+
-- ** Round numbers
60+
4361
newtype PerasRoundNo = PerasRoundNo {unPerasRoundNo :: Word64}
4462
deriving Show via Quiet PerasRoundNo
4563
deriving stock Generic
@@ -57,14 +75,56 @@ onPerasRoundNo ::
5775
(PerasRoundNo -> PerasRoundNo -> PerasRoundNo)
5876
onPerasRoundNo = coerce
5977

60-
-- TODO using 'Validated' for extra safety? Or some @.Unsafe@ module?
78+
-- ** Stake pool distributions
79+
80+
newtype PerasVoterId = PerasVoterId
81+
{ unPerasVoterId :: KeyHash StakePool
82+
}
83+
deriving stock (Show, Eq, Ord, Generic)
84+
deriving newtype NoThunks
85+
86+
newtype PerasIndividualVoterStake = PerasIndividualVoterStake
87+
{ perasIndividualVoterStake :: IndividualPoolStake
88+
}
89+
deriving stock (Show, Eq, Generic)
90+
deriving newtype NoThunks
91+
92+
instance Ord PerasIndividualVoterStake where
93+
compare = compare `on` (SL.individualPoolStakeVrf . perasIndividualVoterStake)
94+
95+
newtype PerasVoterStakeDistr = PerasVotingStakeDistr
96+
{ unPerasVotingStakeDistr :: SL.PoolDistr
97+
}
98+
deriving stock (Show, Eq, Generic)
99+
deriving newtype NoThunks
100+
101+
-- | Lookup the stake of a vote's stake pool in a given stake distribution.
102+
lookupPerasVoterStake ::
103+
PerasVote blk ->
104+
PerasVoterStakeDistr ->
105+
Maybe PerasIndividualVoterStake
106+
lookupPerasVoterStake vote (PerasVotingStakeDistr distr) =
107+
PerasIndividualVoterStake
108+
<$> Map.lookup
109+
(unPerasVoterId (pvVoteVoterId vote))
110+
(SL.unPoolDistr distr)
111+
112+
-- ** Validated types
113+
61114
data ValidatedPerasCert blk = ValidatedPerasCert
62115
{ vpcCert :: !(PerasCert blk)
63116
, vpcCertBoost :: !PerasWeight
64117
}
65118
deriving stock (Show, Eq, Ord, Generic)
66119
deriving anyclass NoThunks
67120

121+
data ValidatedPerasVote blk = ValidatedPerasVote
122+
{ vpvVote :: !(PerasVote blk)
123+
, vpvVoteStake :: !PerasIndividualVoterStake
124+
}
125+
deriving stock (Show, Eq, Ord, Generic)
126+
deriving anyclass NoThunks
127+
68128
{-------------------------------------------------------------------------------
69129
-- * BlockSupportsPeras class
70130
-------------------------------------------------------------------------------}
@@ -79,13 +139,21 @@ class
79139

80140
data PerasCert blk
81141

142+
data PerasVote blk
143+
82144
data PerasValidationErr blk
83145

84146
validatePerasCert ::
85147
PerasCfg blk ->
86148
PerasCert blk ->
87149
Either (PerasValidationErr blk) (ValidatedPerasCert blk)
88150

151+
validatePerasVote ::
152+
PerasCfg blk ->
153+
PerasVote blk ->
154+
PerasVoterStakeDistr ->
155+
Either (PerasValidationErr blk) (ValidatedPerasVote blk)
156+
89157
-- TODO: degenerate instance for all blks to get things to compile
90158
-- see https://github.com/tweag/cardano-peras/issues/73
91159
instance StandardHash blk => BlockSupportsPeras blk where
@@ -98,6 +166,14 @@ instance StandardHash blk => BlockSupportsPeras blk where
98166
deriving stock (Generic, Eq, Ord, Show)
99167
deriving anyclass NoThunks
100168

169+
data PerasVote blk = PerasVote
170+
{ pvVoteRound :: PerasRoundNo
171+
, pvVoteBlock :: Point blk
172+
, pvVoteVoterId :: PerasVoterId
173+
}
174+
deriving stock (Generic, Eq, Ord, Show)
175+
deriving anyclass NoThunks
176+
101177
-- TODO: enrich with actual error types
102178
-- see https://github.com/tweag/cardano-peras/issues/120
103179
data PerasValidationErr blk
@@ -114,9 +190,25 @@ instance StandardHash blk => BlockSupportsPeras blk where
114190
, vpcCertBoost = perasWeight params
115191
}
116192

193+
-- TODO: perform actual validation against all
194+
-- possible 'PerasValidationErr' variants
195+
-- see https://github.com/tweag/cardano-peras/issues/120
196+
validatePerasVote _params vote stakeDistr
197+
| Just stake <- lookupPerasVoterStake vote stakeDistr =
198+
Right
199+
ValidatedPerasVote
200+
{ vpvVote = vote
201+
, vpvVoteStake = stake
202+
}
203+
| otherwise =
204+
Left PerasValidationErr
205+
117206
instance ShowProxy blk => ShowProxy (PerasCert blk) where
118207
showProxy _ = "PerasCert " <> showProxy (Proxy @blk)
119208

209+
instance ShowProxy blk => ShowProxy (PerasVote blk) where
210+
showProxy _ = "PerasVote " <> showProxy (Proxy @blk)
211+
120212
instance Serialise (HeaderHash blk) => Serialise (PerasCert blk) where
121213
encode PerasCert{pcCertRound, pcCertBoostedBlock} =
122214
encodeListLen 2
@@ -128,6 +220,19 @@ instance Serialise (HeaderHash blk) => Serialise (PerasCert blk) where
128220
pcCertBoostedBlock <- decode
129221
pure $ PerasCert{pcCertRound, pcCertBoostedBlock}
130222

223+
instance Serialise (HeaderHash blk) => Serialise (PerasVote blk) where
224+
encode PerasVote{pvVoteRound, pvVoteBlock, pvVoteVoterId} =
225+
encodeListLen 3
226+
<> encode pvVoteRound
227+
<> encode pvVoteBlock
228+
<> KeyHash.toCBOR (unPerasVoterId pvVoteVoterId)
229+
decode = do
230+
decodeListLenOf 3
231+
pvVoteRound <- decode
232+
pvVoteBlock <- decode
233+
pvVoteVoterId <- PerasVoterId <$> KeyHash.fromCBOR
234+
pure $ PerasVote{pvVoteRound, pvVoteBlock, pvVoteVoterId}
235+
131236
-- | Extract the certificate round from a Peras certificate container
132237
class HasPerasCertRound cert where
133238
getPerasCertRound :: cert -> PerasRoundNo
@@ -172,3 +277,51 @@ instance
172277
HasPerasCertBoost (WithArrivalTime cert)
173278
where
174279
getPerasCertBoost = getPerasCertBoost . forgetArrivalTime
280+
281+
-- | Extract the vote round from a Peras vote container
282+
class HasPerasVoteRound vote where
283+
getPerasVoteRound :: vote -> PerasRoundNo
284+
285+
instance HasPerasVoteRound (PerasVote blk) where
286+
getPerasVoteRound = pvVoteRound
287+
288+
instance HasPerasVoteRound (ValidatedPerasVote blk) where
289+
getPerasVoteRound = getPerasVoteRound . vpvVote
290+
291+
instance
292+
HasPerasVoteRound vote =>
293+
HasPerasVoteRound (WithArrivalTime vote)
294+
where
295+
getPerasVoteRound = getPerasVoteRound . forgetArrivalTime
296+
297+
-- | Extract the vote block point from a Peras vote container
298+
class HasPerasVoteBlock vote blk | vote -> blk where
299+
getPerasVoteBlock :: vote -> Point blk
300+
301+
instance HasPerasVoteBlock (PerasVote blk) blk where
302+
getPerasVoteBlock = pvVoteBlock
303+
304+
instance HasPerasVoteBlock (ValidatedPerasVote blk) blk where
305+
getPerasVoteBlock = getPerasVoteBlock . vpvVote
306+
307+
instance
308+
HasPerasVoteBlock vote blk =>
309+
HasPerasVoteBlock (WithArrivalTime vote) blk
310+
where
311+
getPerasVoteBlock = getPerasVoteBlock . forgetArrivalTime
312+
313+
-- | Extract the stake pool ID from a Peras vote container
314+
class HasPerasVoteVoterId vote where
315+
getPerasVoteVoterId :: vote -> PerasVoterId
316+
317+
instance HasPerasVoteVoterId (PerasVote blk) where
318+
getPerasVoteVoterId = pvVoteVoterId
319+
320+
instance HasPerasVoteVoterId (ValidatedPerasVote blk) where
321+
getPerasVoteVoterId = getPerasVoteVoterId . vpvVote
322+
323+
instance
324+
HasPerasVoteVoterId vote =>
325+
HasPerasVoteVoterId (WithArrivalTime vote)
326+
where
327+
getPerasVoteVoterId = getPerasVoteVoterId . forgetArrivalTime

0 commit comments

Comments
 (0)