{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}

-- | Concrete Peras vote types using BLS signatures.
--
-- NOTE: this module is meant to be imported qualified.
module Ouroboros.Consensus.Peras.Vote.V1
  ( PerasVote (..)
  , castPerasVote
  , PerasVoteEligibilityProof (..)
  ) where

import Cardano.Binary
  ( FromCBOR (..)
  , ToCBOR (..)
  , decodeListLen
  , decodeListLenOf
  , encodeListLen
  )
import Data.Coerce (coerce)
import Data.Typeable (Typeable)
import Data.Word (Word8)
import GHC.Generics (Generic)
import NoThunks.Class (NoThunks)
import Ouroboros.Consensus.Block.Abstract (ConvertRawHash (..))
import Ouroboros.Consensus.Committee.Crypto (CryptoSupportsVoteSigning (..))
import Ouroboros.Consensus.Committee.EveryoneVotes
  ( EveryoneVotes
  , Vote (..)
  )
import Ouroboros.Consensus.Committee.WFALS (Vote (..), WFALS)
import Ouroboros.Consensus.Peras.Crypto.BLS
  ( PerasBLSCrypto
  , VRFOutput
  )
import Ouroboros.Consensus.Peras.Types
  ( BoostedBlock
  , PerasBoostedBlock (..)
  , PerasRoundNo
  , PerasSeatIndex
  )
import Ouroboros.Consensus.Peras.Vote.Class (IsPerasVote (..))
import Ouroboros.Consensus.Peras.Voting.Adapter
  ( PerasConversionError (..)
  , PerasVoteCompatibleWithVotingCommittee (..)
  , fromPerasSeatIndex
  , toPerasSeatIndex
  )
import Ouroboros.Network.Util.ShowProxy

-- | Concrete Peras votes using BLS signatures
--
-- NOTE: the 'blk' parameter is a phantom type used to track the block type that
-- the vote is associated with, to ensure injectivity when 'V1.PerasVote' is
-- used as a type instance for 'BlockSupportsPeras' class.
data PerasVote blk
  = PerasVote
  { forall blk. PerasVote blk -> PerasRoundNo
pvRoundNo :: !PerasRoundNo
  -- ^ Election identifier
  , forall blk. PerasVote blk -> PerasBoostedBlock
pvBoostedBlock :: !PerasBoostedBlock
  -- ^ Vote message, i.e., the hash of the block being voted for
  , forall blk. PerasVote blk -> PerasSeatIndex
pvSeatIndex :: !PerasSeatIndex
  -- ^ Seat index assigned to the committee member (identifies the voter)
  , forall blk. PerasVote blk -> PerasVoteEligibilityProof
pvEligibilityProof :: !PerasVoteEligibilityProof
  -- ^ Proof of eligibility for voting, depending on the type of membership to
  -- the committee (persistent vs non-persistent)
  , forall blk. PerasVote blk -> VoteSignature PerasBLSCrypto
pvSignature :: !(VoteSignature PerasBLSCrypto)
  -- ^ BLS signature on the hash of the election identifier and vote message
  }
  deriving stock (Int -> PerasVote blk -> ShowS
[PerasVote blk] -> ShowS
PerasVote blk -> String
(Int -> PerasVote blk -> ShowS)
-> (PerasVote blk -> String)
-> ([PerasVote blk] -> ShowS)
-> Show (PerasVote blk)
forall blk. Int -> PerasVote blk -> ShowS
forall blk. [PerasVote blk] -> ShowS
forall blk. PerasVote blk -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: forall blk. Int -> PerasVote blk -> ShowS
showsPrec :: Int -> PerasVote blk -> ShowS
$cshow :: forall blk. PerasVote blk -> String
show :: PerasVote blk -> String
$cshowList :: forall blk. [PerasVote blk] -> ShowS
showList :: [PerasVote blk] -> ShowS
Show, PerasVote blk -> PerasVote blk -> Bool
(PerasVote blk -> PerasVote blk -> Bool)
-> (PerasVote blk -> PerasVote blk -> Bool) -> Eq (PerasVote blk)
forall blk. PerasVote blk -> PerasVote blk -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: forall blk. PerasVote blk -> PerasVote blk -> Bool
== :: PerasVote blk -> PerasVote blk -> Bool
$c/= :: forall blk. PerasVote blk -> PerasVote blk -> Bool
/= :: PerasVote blk -> PerasVote blk -> Bool
Eq, (forall x. PerasVote blk -> Rep (PerasVote blk) x)
-> (forall x. Rep (PerasVote blk) x -> PerasVote blk)
-> Generic (PerasVote blk)
forall x. Rep (PerasVote blk) x -> PerasVote blk
forall x. PerasVote blk -> Rep (PerasVote blk) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall blk x. Rep (PerasVote blk) x -> PerasVote blk
forall blk x. PerasVote blk -> Rep (PerasVote blk) x
$cfrom :: forall blk x. PerasVote blk -> Rep (PerasVote blk) x
from :: forall x. PerasVote blk -> Rep (PerasVote blk) x
$cto :: forall blk x. Rep (PerasVote blk) x -> PerasVote blk
to :: forall x. Rep (PerasVote blk) x -> PerasVote blk
Generic)
  deriving anyclass Context -> PerasVote blk -> IO (Maybe ThunkInfo)
Proxy (PerasVote blk) -> String
(Context -> PerasVote blk -> IO (Maybe ThunkInfo))
-> (Context -> PerasVote blk -> IO (Maybe ThunkInfo))
-> (Proxy (PerasVote blk) -> String)
-> NoThunks (PerasVote blk)
forall blk. Context -> PerasVote blk -> IO (Maybe ThunkInfo)
forall blk. Proxy (PerasVote blk) -> String
forall a.
(Context -> a -> IO (Maybe ThunkInfo))
-> (Context -> a -> IO (Maybe ThunkInfo))
-> (Proxy a -> String)
-> NoThunks a
$cnoThunks :: forall blk. Context -> PerasVote blk -> IO (Maybe ThunkInfo)
noThunks :: Context -> PerasVote blk -> IO (Maybe ThunkInfo)
$cwNoThunks :: forall blk. Context -> PerasVote blk -> IO (Maybe ThunkInfo)
wNoThunks :: Context -> PerasVote blk -> IO (Maybe ThunkInfo)
$cshowTypeOf :: forall blk. Proxy (PerasVote blk) -> String
showTypeOf :: Proxy (PerasVote blk) -> String
NoThunks

-- | Retag a 'PerasVote' with a new phantom @blk@ type.
castPerasVote :: forall blk' blk. PerasVote blk -> PerasVote blk'
castPerasVote :: forall blk' blk. PerasVote blk -> PerasVote blk'
castPerasVote = PerasVote blk -> PerasVote blk'
forall a b. Coercible a b => a -> b
coerce

type instance BoostedBlock (PerasVote blk) = PerasBoostedBlock

instance
  ( ConvertRawHash blk
  , HashSize blk ~ 32
  ) =>
  IsPerasVote (PerasVote blk) blk
  where
  getPerasVoteSeatIndex :: PerasVote blk -> PerasSeatIndex
getPerasVoteSeatIndex = PerasVote blk -> PerasSeatIndex
forall blk. PerasVote blk -> PerasSeatIndex
pvSeatIndex
  getPerasVoteRound :: PerasVote blk -> PerasRoundNo
getPerasVoteRound = PerasVote blk -> PerasRoundNo
forall blk. PerasVote blk -> PerasRoundNo
pvRoundNo
  getPerasVoteBlock :: PerasVote blk -> BoostedBlock (PerasVote blk)
getPerasVoteBlock = PerasVote blk -> BoostedBlock (PerasVote blk)
PerasVote blk -> PerasBoostedBlock
forall blk. PerasVote blk -> PerasBoostedBlock
pvBoostedBlock

instance Typeable blk => FromCBOR (PerasVote blk) where
  fromCBOR :: forall s. Decoder s (PerasVote blk)
fromCBOR = do
    Int -> Decoder s ()
forall s. Int -> Decoder s ()
decodeListLenOf Int
5
    pvRoundNo <- Decoder s PerasRoundNo
forall s. Decoder s PerasRoundNo
forall a s. FromCBOR a => Decoder s a
fromCBOR
    pvBoostedBlock <- fromCBOR
    pvSeatIndex <- fromCBOR
    pvEligibilityProof <- fromCBOR
    pvSignature <- fromCBOR
    pure
      PerasVote
        { pvRoundNo
        , pvBoostedBlock
        , pvSeatIndex
        , pvEligibilityProof
        , pvSignature
        }

instance Typeable blk => ToCBOR (PerasVote blk) where
  toCBOR :: PerasVote blk -> Encoding
toCBOR
    PerasVote
      { PerasRoundNo
pvRoundNo :: forall blk. PerasVote blk -> PerasRoundNo
pvRoundNo :: PerasRoundNo
pvRoundNo
      , PerasBoostedBlock
pvBoostedBlock :: forall blk. PerasVote blk -> PerasBoostedBlock
pvBoostedBlock :: PerasBoostedBlock
pvBoostedBlock
      , PerasSeatIndex
pvSeatIndex :: forall blk. PerasVote blk -> PerasSeatIndex
pvSeatIndex :: PerasSeatIndex
pvSeatIndex
      , PerasVoteEligibilityProof
pvEligibilityProof :: forall blk. PerasVote blk -> PerasVoteEligibilityProof
pvEligibilityProof :: PerasVoteEligibilityProof
pvEligibilityProof
      , VoteSignature PerasBLSCrypto
pvSignature :: forall blk. PerasVote blk -> VoteSignature PerasBLSCrypto
pvSignature :: VoteSignature PerasBLSCrypto
pvSignature
      } =
      Word -> Encoding
encodeListLen Word
5
        Encoding -> Encoding -> Encoding
forall a. Semigroup a => a -> a -> a
<> PerasRoundNo -> Encoding
forall a. ToCBOR a => a -> Encoding
toCBOR PerasRoundNo
pvRoundNo
        Encoding -> Encoding -> Encoding
forall a. Semigroup a => a -> a -> a
<> PerasBoostedBlock -> Encoding
forall a. ToCBOR a => a -> Encoding
toCBOR PerasBoostedBlock
pvBoostedBlock
        Encoding -> Encoding -> Encoding
forall a. Semigroup a => a -> a -> a
<> PerasSeatIndex -> Encoding
forall a. ToCBOR a => a -> Encoding
toCBOR PerasSeatIndex
pvSeatIndex
        Encoding -> Encoding -> Encoding
forall a. Semigroup a => a -> a -> a
<> PerasVoteEligibilityProof -> Encoding
forall a. ToCBOR a => a -> Encoding
toCBOR PerasVoteEligibilityProof
pvEligibilityProof
        Encoding -> Encoding -> Encoding
forall a. Semigroup a => a -> a -> a
<> VoteSignature PerasBLSCrypto -> Encoding
forall a. ToCBOR a => a -> Encoding
toCBOR VoteSignature PerasBLSCrypto
pvSignature

-- | Proof of eligibility for voting for committee members
data PerasVoteEligibilityProof
  = -- | Persistent committee members require no additional proof of eligibility
    PersistentPerasVoteEligibilityProof
  | -- | Non-persistent committee members provide a VRF proof of eligibility
    NonPersistentPerasVoteEligibilityProof !(VRFOutput PerasBLSCrypto)
  deriving stock (Int -> PerasVoteEligibilityProof -> ShowS
[PerasVoteEligibilityProof] -> ShowS
PerasVoteEligibilityProof -> String
(Int -> PerasVoteEligibilityProof -> ShowS)
-> (PerasVoteEligibilityProof -> String)
-> ([PerasVoteEligibilityProof] -> ShowS)
-> Show PerasVoteEligibilityProof
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> PerasVoteEligibilityProof -> ShowS
showsPrec :: Int -> PerasVoteEligibilityProof -> ShowS
$cshow :: PerasVoteEligibilityProof -> String
show :: PerasVoteEligibilityProof -> String
$cshowList :: [PerasVoteEligibilityProof] -> ShowS
showList :: [PerasVoteEligibilityProof] -> ShowS
Show, PerasVoteEligibilityProof -> PerasVoteEligibilityProof -> Bool
(PerasVoteEligibilityProof -> PerasVoteEligibilityProof -> Bool)
-> (PerasVoteEligibilityProof -> PerasVoteEligibilityProof -> Bool)
-> Eq PerasVoteEligibilityProof
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: PerasVoteEligibilityProof -> PerasVoteEligibilityProof -> Bool
== :: PerasVoteEligibilityProof -> PerasVoteEligibilityProof -> Bool
$c/= :: PerasVoteEligibilityProof -> PerasVoteEligibilityProof -> Bool
/= :: PerasVoteEligibilityProof -> PerasVoteEligibilityProof -> Bool
Eq, (forall x.
 PerasVoteEligibilityProof -> Rep PerasVoteEligibilityProof x)
-> (forall x.
    Rep PerasVoteEligibilityProof x -> PerasVoteEligibilityProof)
-> Generic PerasVoteEligibilityProof
forall x.
Rep PerasVoteEligibilityProof x -> PerasVoteEligibilityProof
forall x.
PerasVoteEligibilityProof -> Rep PerasVoteEligibilityProof x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x.
PerasVoteEligibilityProof -> Rep PerasVoteEligibilityProof x
from :: forall x.
PerasVoteEligibilityProof -> Rep PerasVoteEligibilityProof x
$cto :: forall x.
Rep PerasVoteEligibilityProof x -> PerasVoteEligibilityProof
to :: forall x.
Rep PerasVoteEligibilityProof x -> PerasVoteEligibilityProof
Generic)
  deriving anyclass Context -> PerasVoteEligibilityProof -> IO (Maybe ThunkInfo)
Proxy PerasVoteEligibilityProof -> String
(Context -> PerasVoteEligibilityProof -> IO (Maybe ThunkInfo))
-> (Context -> PerasVoteEligibilityProof -> IO (Maybe ThunkInfo))
-> (Proxy PerasVoteEligibilityProof -> String)
-> NoThunks PerasVoteEligibilityProof
forall a.
(Context -> a -> IO (Maybe ThunkInfo))
-> (Context -> a -> IO (Maybe ThunkInfo))
-> (Proxy a -> String)
-> NoThunks a
$cnoThunks :: Context -> PerasVoteEligibilityProof -> IO (Maybe ThunkInfo)
noThunks :: Context -> PerasVoteEligibilityProof -> IO (Maybe ThunkInfo)
$cwNoThunks :: Context -> PerasVoteEligibilityProof -> IO (Maybe ThunkInfo)
wNoThunks :: Context -> PerasVoteEligibilityProof -> IO (Maybe ThunkInfo)
$cshowTypeOf :: Proxy PerasVoteEligibilityProof -> String
showTypeOf :: Proxy PerasVoteEligibilityProof -> String
NoThunks

instance FromCBOR PerasVoteEligibilityProof where
  fromCBOR :: forall s. Decoder s PerasVoteEligibilityProof
fromCBOR = do
    len <- Decoder s Int
forall s. Decoder s Int
decodeListLen
    tag <- fromCBOR @Word8
    case (len, tag) of
      (Int
1, Word8
0) -> PerasVoteEligibilityProof -> Decoder s PerasVoteEligibilityProof
forall a. a -> Decoder s a
forall (f :: * -> *) a. Applicative f => a -> f a
pure PerasVoteEligibilityProof
PersistentPerasVoteEligibilityProof
      (Int
2, Word8
1) -> VRFOutput PerasBLSCrypto -> PerasVoteEligibilityProof
NonPersistentPerasVoteEligibilityProof (VRFOutput PerasBLSCrypto -> PerasVoteEligibilityProof)
-> Decoder s (VRFOutput PerasBLSCrypto)
-> Decoder s PerasVoteEligibilityProof
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Decoder s (VRFOutput PerasBLSCrypto)
forall s. Decoder s (VRFOutput PerasBLSCrypto)
forall a s. FromCBOR a => Decoder s a
fromCBOR
      (Int, Word8)
_ ->
        String -> Decoder s PerasVoteEligibilityProof
forall a. HasCallStack => String -> Decoder s a
forall (m :: * -> *) a.
(MonadFail m, HasCallStack) =>
String -> m a
fail (String -> Decoder s PerasVoteEligibilityProof)
-> String -> Decoder s PerasVoteEligibilityProof
forall a b. (a -> b) -> a -> b
$
          String
"Invalid PerasVoteEligibilityProof length/tag: "
            String -> ShowS
forall a. Semigroup a => a -> a -> a
<> (Int, Word8) -> String
forall a. Show a => a -> String
show (Int
len, Word8
tag)

instance ToCBOR PerasVoteEligibilityProof where
  toCBOR :: PerasVoteEligibilityProof -> Encoding
toCBOR = \case
    PerasVoteEligibilityProof
PersistentPerasVoteEligibilityProof ->
      Word -> Encoding
encodeListLen Word
1
        Encoding -> Encoding -> Encoding
forall a. Semigroup a => a -> a -> a
<> Word8 -> Encoding
forall a. ToCBOR a => a -> Encoding
toCBOR (Word8
0 :: Word8)
    NonPersistentPerasVoteEligibilityProof VRFOutput PerasBLSCrypto
vrfOutput ->
      Word -> Encoding
encodeListLen Word
2
        Encoding -> Encoding -> Encoding
forall a. Semigroup a => a -> a -> a
<> Word8 -> Encoding
forall a. ToCBOR a => a -> Encoding
toCBOR (Word8
1 :: Word8)
        Encoding -> Encoding -> Encoding
forall a. Semigroup a => a -> a -> a
<> VRFOutput PerasBLSCrypto -> Encoding
forall a. ToCBOR a => a -> Encoding
toCBOR VRFOutput PerasBLSCrypto
vrfOutput

instance ShowProxy blk => ShowProxy (PerasVote blk) where
  showProxy :: Proxy (PerasVote blk) -> String
showProxy Proxy (PerasVote blk)
_ = String
"PerasVote " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> Proxy blk -> String
forall {k} (p :: k). ShowProxy p => Proxy p -> String
showProxy (forall t. Proxy t
forall {k} (t :: k). Proxy t
Proxy @blk)

-- * Compatibility with voting committee implementations

-- 'PerasVote's are compatible with 'WFALS' as long as we make sure to avoid
-- overflowing their `Word16` seat index.
instance
  PerasVoteCompatibleWithVotingCommittee
    (PerasVote blk)
    PerasBLSCrypto
    WFALS
  where
  toPerasVote :: Vote PerasBLSCrypto WFALS
-> Either PerasConversionError (PerasVote blk)
toPerasVote = \case
    WFALSPersistentVote SeatIndex
seatIndex ElectionId PerasBLSCrypto
electionId VoteCandidate PerasBLSCrypto
candidate VoteSignature PerasBLSCrypto
sig -> do
      perasSeatIndex <- SeatIndex -> Either PerasConversionError PerasSeatIndex
toPerasSeatIndex SeatIndex
seatIndex
      pure $
        PerasVote
          { pvRoundNo = electionId
          , pvBoostedBlock = candidate
          , pvSeatIndex = perasSeatIndex
          , pvEligibilityProof = PersistentPerasVoteEligibilityProof
          , pvSignature = sig
          }
    WFALSNonPersistentVote SeatIndex
seatIndex ElectionId PerasBLSCrypto
electionId VoteCandidate PerasBLSCrypto
candidate VRFOutput PerasBLSCrypto
vrfOutput VoteSignature PerasBLSCrypto
sig -> do
      perasSeatIndex <- SeatIndex -> Either PerasConversionError PerasSeatIndex
toPerasSeatIndex SeatIndex
seatIndex
      let proof = VRFOutput PerasBLSCrypto -> PerasVoteEligibilityProof
NonPersistentPerasVoteEligibilityProof VRFOutput PerasBLSCrypto
vrfOutput
      pure $
        PerasVote
          { pvRoundNo = electionId
          , pvBoostedBlock = candidate
          , pvSeatIndex = perasSeatIndex
          , pvEligibilityProof = proof
          , pvSignature = sig
          }

  fromPerasVote :: PerasVote blk
-> Either PerasConversionError (Vote PerasBLSCrypto WFALS)
fromPerasVote = \case
    PerasVote PerasRoundNo
electionId PerasBoostedBlock
candidate PerasSeatIndex
seatIndex PerasVoteEligibilityProof
proof VoteSignature PerasBLSCrypto
sig -> do
      let seatIndex' :: SeatIndex
seatIndex' = PerasSeatIndex -> SeatIndex
fromPerasSeatIndex PerasSeatIndex
seatIndex
      case PerasVoteEligibilityProof
proof of
        PerasVoteEligibilityProof
PersistentPerasVoteEligibilityProof ->
          Vote PerasBLSCrypto WFALS
-> Either PerasConversionError (Vote PerasBLSCrypto WFALS)
forall a. a -> Either PerasConversionError a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Vote PerasBLSCrypto WFALS
 -> Either PerasConversionError (Vote PerasBLSCrypto WFALS))
-> Vote PerasBLSCrypto WFALS
-> Either PerasConversionError (Vote PerasBLSCrypto WFALS)
forall a b. (a -> b) -> a -> b
$
            SeatIndex
-> ElectionId PerasBLSCrypto
-> VoteCandidate PerasBLSCrypto
-> VoteSignature PerasBLSCrypto
-> Vote PerasBLSCrypto WFALS
forall crypto.
SeatIndex
-> ElectionId crypto
-> VoteCandidate crypto
-> VoteSignature crypto
-> Vote crypto WFALS
WFALSPersistentVote
              SeatIndex
seatIndex'
              ElectionId PerasBLSCrypto
PerasRoundNo
electionId
              VoteCandidate PerasBLSCrypto
PerasBoostedBlock
candidate
              VoteSignature PerasBLSCrypto
sig
        NonPersistentPerasVoteEligibilityProof VRFOutput PerasBLSCrypto
vrfOutput ->
          Vote PerasBLSCrypto WFALS
-> Either PerasConversionError (Vote PerasBLSCrypto WFALS)
forall a. a -> Either PerasConversionError a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Vote PerasBLSCrypto WFALS
 -> Either PerasConversionError (Vote PerasBLSCrypto WFALS))
-> Vote PerasBLSCrypto WFALS
-> Either PerasConversionError (Vote PerasBLSCrypto WFALS)
forall a b. (a -> b) -> a -> b
$
            SeatIndex
-> ElectionId PerasBLSCrypto
-> VoteCandidate PerasBLSCrypto
-> VRFOutput PerasBLSCrypto
-> VoteSignature PerasBLSCrypto
-> Vote PerasBLSCrypto WFALS
forall crypto.
SeatIndex
-> ElectionId crypto
-> VoteCandidate crypto
-> VRFOutput crypto
-> VoteSignature crypto
-> Vote crypto WFALS
WFALSNonPersistentVote
              SeatIndex
seatIndex'
              ElectionId PerasBLSCrypto
PerasRoundNo
electionId
              VoteCandidate PerasBLSCrypto
PerasBoostedBlock
candidate
              VRFOutput PerasBLSCrypto
vrfOutput
              VoteSignature PerasBLSCrypto
sig

-- 'PerasVote's are compatible with 'EveryoneVotes' as long as we make sure
-- to only accept votes with persistent eligibility proofs (in addition to
-- avoiding overflowing their `Word16` seat index).
instance
  PerasVoteCompatibleWithVotingCommittee
    (PerasVote blk)
    PerasBLSCrypto
    EveryoneVotes
  where
  toPerasVote :: Vote PerasBLSCrypto EveryoneVotes
-> Either PerasConversionError (PerasVote blk)
toPerasVote = \case
    EveryoneVotesVote SeatIndex
seatIndex ElectionId PerasBLSCrypto
electionId VoteCandidate PerasBLSCrypto
candidate VoteSignature PerasBLSCrypto
sig -> do
      perasSeatIndex <- SeatIndex -> Either PerasConversionError PerasSeatIndex
toPerasSeatIndex SeatIndex
seatIndex
      pure $
        PerasVote
          { pvRoundNo = electionId
          , pvBoostedBlock = candidate
          , pvSeatIndex = perasSeatIndex
          , pvEligibilityProof = PersistentPerasVoteEligibilityProof
          , pvSignature = sig
          }

  fromPerasVote :: PerasVote blk
-> Either PerasConversionError (Vote PerasBLSCrypto EveryoneVotes)
fromPerasVote = \case
    PerasVote PerasRoundNo
electionId PerasBoostedBlock
candidate PerasSeatIndex
seatIndex PerasVoteEligibilityProof
proof VoteSignature PerasBLSCrypto
sig -> do
      let seatIndex' :: SeatIndex
seatIndex' = PerasSeatIndex -> SeatIndex
fromPerasSeatIndex PerasSeatIndex
seatIndex
      case PerasVoteEligibilityProof
proof of
        PerasVoteEligibilityProof
PersistentPerasVoteEligibilityProof ->
          Vote PerasBLSCrypto EveryoneVotes
-> Either PerasConversionError (Vote PerasBLSCrypto EveryoneVotes)
forall a. a -> Either PerasConversionError a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Vote PerasBLSCrypto EveryoneVotes
 -> Either PerasConversionError (Vote PerasBLSCrypto EveryoneVotes))
-> Vote PerasBLSCrypto EveryoneVotes
-> Either PerasConversionError (Vote PerasBLSCrypto EveryoneVotes)
forall a b. (a -> b) -> a -> b
$
            SeatIndex
-> ElectionId PerasBLSCrypto
-> VoteCandidate PerasBLSCrypto
-> VoteSignature PerasBLSCrypto
-> Vote PerasBLSCrypto EveryoneVotes
forall crypto.
SeatIndex
-> ElectionId crypto
-> VoteCandidate crypto
-> VoteSignature crypto
-> Vote crypto EveryoneVotes
EveryoneVotesVote
              SeatIndex
seatIndex'
              ElectionId PerasBLSCrypto
PerasRoundNo
electionId
              VoteCandidate PerasBLSCrypto
PerasBoostedBlock
candidate
              VoteSignature PerasBLSCrypto
sig
        NonPersistentPerasVoteEligibilityProof VRFOutput PerasBLSCrypto
_ ->
          PerasConversionError
-> Either PerasConversionError (Vote PerasBLSCrypto EveryoneVotes)
forall a b. a -> Either a b
Left (PerasConversionError
 -> Either PerasConversionError (Vote PerasBLSCrypto EveryoneVotes))
-> PerasConversionError
-> Either PerasConversionError (Vote PerasBLSCrypto EveryoneVotes)
forall a b. (a -> b) -> a -> b
$
            SeatIndex -> PerasConversionError
EveryoneVotesButFoundNonPersistentVoterInVote SeatIndex
seatIndex'