1+ {-# LANGUAGE DataKinds #-}
12{-# LANGUAGE DeriveAnyClass #-}
23{-# LANGUAGE DeriveGeneric #-}
34{-# LANGUAGE DerivingVia #-}
78{-# LANGUAGE GeneralizedNewtypeDeriving #-}
89{-# LANGUAGE NamedFieldPuns #-}
910{-# LANGUAGE ScopedTypeVariables #-}
11+ {-# LANGUAGE StandaloneDeriving #-}
1012{-# LANGUAGE TypeApplications #-}
1113{-# LANGUAGE TypeFamilies #-}
1214{-# LANGUAGE UndecidableInstances #-}
15+ {-# OPTIONS_GHC -Wno-orphans #-}
1316
1417module Ouroboros.Consensus.Block.SupportsPeras
1518 ( PerasRoundNo (.. )
1619 , onPerasRoundNo
1720 , PerasWeight (.. )
1821 , BlockSupportsPeras (.. )
1922 , PerasCert (.. )
23+ , PerasVote (.. )
2024 , PerasCfg (.. )
2125 , ValidatedPerasCert (.. )
26+ , ValidatedPerasVote (.. )
2227 , makePerasCfg
2328 , HasPerasCertRound (.. )
2429 , HasPerasCertBoostedBlock (.. )
2530 , HasPerasCertBoost (.. )
31+ , HasPerasVoteRound (.. )
32+ , HasPerasVoteVotedBlock (.. )
33+ , HasStakePoolId (.. )
2634
2735 -- * Ouroboros Peras round length
2836 , PerasRoundLength (.. )
2937 , defaultPerasRoundLength
3038 ) where
3139
40+ import qualified Cardano.Binary as KeyHash
41+ import Cardano.Ledger.Core (KeyHash , KeyRole (StakePool ))
42+ import Cardano.Ledger.State (IndividualPoolStake (.. ), PoolDistr (PoolDistr , unPoolDistr ))
3243import Codec.Serialise (Serialise (.. ))
3344import Codec.Serialise.Decoding (decodeListLenOf )
3445import Codec.Serialise.Encoding (encodeListLen )
3546import Data.Coerce (coerce )
47+ import qualified Data.Map as Map
3648import Data.Monoid (Sum (.. ))
3749import Data.Proxy (Proxy (.. ))
3850import Data.Word (Word64 )
@@ -49,6 +61,9 @@ newtype PerasRoundNo = PerasRoundNo {unPerasRoundNo :: Word64}
4961 deriving stock Generic
5062 deriving newtype (Enum , Eq , Ord , Num , Bounded , NoThunks , Serialise )
5163
64+ -- | TODO: what is the proper underlying type?
65+ type StakePoolId = KeyHash 'StakePool
66+
5267instance Condense PerasRoundNo where
5368 condense = show . unPerasRoundNo
5469
@@ -83,6 +98,15 @@ data ValidatedPerasCert blk = ValidatedPerasCert
8398 deriving stock (Show , Eq , Ord , Generic )
8499 deriving anyclass NoThunks
85100
101+ deriving instance Ord IndividualPoolStake
102+
103+ data ValidatedPerasVote blk = ValidatedPerasVote
104+ { vpvVote :: ! (PerasVote blk )
105+ , vpvVoteStake :: ! IndividualPoolStake
106+ }
107+ deriving stock (Show , Eq , Ord , Generic )
108+ deriving anyclass NoThunks
109+
86110{- ------------------------------------------------------------------------------
87111 Ouroboros Peras round length
88112-------------------------------------------------------------------------------}
@@ -108,13 +132,21 @@ class
108132
109133 data PerasCert blk
110134
135+ data PerasVote blk
136+
111137 data PerasValidationErr blk
112138
113139 validatePerasCert ::
114140 PerasCfg blk ->
115141 PerasCert blk ->
116142 Either (PerasValidationErr blk ) (ValidatedPerasCert blk )
117143
144+ validatePerasVote ::
145+ PerasCfg blk ->
146+ PerasVote blk ->
147+ PoolDistr ->
148+ Either (PerasValidationErr blk ) (ValidatedPerasVote blk )
149+
118150-- TODO: degenerate instance for all blks to get things to compile
119151-- see https://github.com/tweag/cardano-peras/issues/73
120152instance StandardHash blk => BlockSupportsPeras blk where
@@ -133,6 +165,14 @@ instance StandardHash blk => BlockSupportsPeras blk where
133165 deriving stock (Generic , Eq , Ord , Show )
134166 deriving anyclass NoThunks
135167
168+ data PerasVote blk = PerasVote
169+ { pvVoteRound :: PerasRoundNo
170+ , pvVotedBlock :: Point blk
171+ , pvVoteStakePoolId :: StakePoolId
172+ }
173+ deriving stock (Generic , Eq , Ord , Show )
174+ deriving anyclass NoThunks
175+
136176 -- TODO: enrich with actual error types
137177 -- see https://github.com/tweag/cardano-peras/issues/120
138178 data PerasValidationErr blk
@@ -149,9 +189,16 @@ instance StandardHash blk => BlockSupportsPeras blk where
149189 , vpcCertBoost = perasCfgWeightBoost cfg
150190 }
151191
192+ validatePerasVote _cfg vote PoolDistr {unPoolDistr} =
193+ let stake = unPoolDistr Map. ! (pvVoteStakePoolId vote)
194+ in Right (ValidatedPerasVote {vpvVote = vote, vpvVoteStake = stake})
195+
152196instance ShowProxy blk => ShowProxy (PerasCert blk ) where
153197 showProxy _ = " PerasCert " <> showProxy (Proxy @ blk )
154198
199+ instance ShowProxy blk => ShowProxy (PerasVote blk ) where
200+ showProxy _ = " PerasVote " <> showProxy (Proxy @ blk )
201+
155202instance Serialise (HeaderHash blk ) => Serialise (PerasCert blk ) where
156203 encode PerasCert {pcCertRound, pcCertBoostedBlock} =
157204 encodeListLen 2
@@ -163,6 +210,19 @@ instance Serialise (HeaderHash blk) => Serialise (PerasCert blk) where
163210 pcCertBoostedBlock <- decode
164211 pure $ PerasCert {pcCertRound, pcCertBoostedBlock}
165212
213+ instance Serialise (HeaderHash blk ) => Serialise (PerasVote blk ) where
214+ encode PerasVote {pvVoteRound, pvVotedBlock, pvVoteStakePoolId} =
215+ encodeListLen 3
216+ <> encode pvVoteRound
217+ <> encode pvVotedBlock
218+ <> KeyHash. toCBOR pvVoteStakePoolId
219+ decode = do
220+ decodeListLenOf 3
221+ pvVoteRound <- decode
222+ pvVotedBlock <- decode
223+ pvVoteStakePoolId <- KeyHash. fromCBOR
224+ pure $ PerasVote {pvVoteRound, pvVotedBlock, pvVoteStakePoolId}
225+
166226-- | Derive a 'PerasCfg' from a 'BlockConfig'
167227--
168228-- TODO: this currently doesn't depend on 'BlockConfig' at all, but likely will
@@ -218,3 +278,39 @@ instance
218278 HasPerasCertBoost (WithArrivalTime cert )
219279 where
220280 getPerasCertBoost = getPerasCertBoost . forgetArrivalTime
281+
282+ class HasPerasVoteRound vote where
283+ getPerasVoteRound :: vote -> PerasRoundNo
284+ instance HasPerasVoteRound (PerasVote blk ) where
285+ getPerasVoteRound = pvVoteRound
286+ instance HasPerasVoteRound (ValidatedPerasVote blk ) where
287+ getPerasVoteRound = getPerasVoteRound . vpvVote
288+ instance
289+ HasPerasVoteRound vote =>
290+ HasPerasVoteRound (WithArrivalTime vote )
291+ where
292+ getPerasVoteRound = getPerasVoteRound . forgetArrivalTime
293+
294+ class HasPerasVoteVotedBlock vote blk | vote -> blk where
295+ getPerasVoteVotedBlock :: vote -> Point blk
296+ instance HasPerasVoteVotedBlock (PerasVote blk ) blk where
297+ getPerasVoteVotedBlock = pvVotedBlock
298+ instance HasPerasVoteVotedBlock (ValidatedPerasVote blk ) blk where
299+ getPerasVoteVotedBlock = getPerasVoteVotedBlock . vpvVote
300+ instance
301+ HasPerasVoteVotedBlock vote blk =>
302+ HasPerasVoteVotedBlock (WithArrivalTime vote ) blk
303+ where
304+ getPerasVoteVotedBlock = getPerasVoteVotedBlock . forgetArrivalTime
305+
306+ class HasStakePoolId vote where
307+ getStakePoolId :: vote -> StakePoolId
308+ instance HasStakePoolId (PerasVote blk ) where
309+ getStakePoolId = pvVoteStakePoolId
310+ instance HasStakePoolId (ValidatedPerasVote blk ) where
311+ getStakePoolId = getStakePoolId . vpvVote
312+ instance
313+ HasStakePoolId vote =>
314+ HasStakePoolId (WithArrivalTime vote )
315+ where
316+ getStakePoolId = getStakePoolId . forgetArrivalTime
0 commit comments