{-# LANGUAGE DataKinds #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
module Test.Util.Peras.V1
( perasVoteIsPersistent
, perasCertContainsOnlyPersistentVotes
, genPerasVote
, genPerasCert
, tabulatePerasCert
, tabulatePerasVote
) where
import Cardano.Crypto.Hash (ByteString)
import Cardano.Ledger.BaseTypes (SlotNo (..))
import Control.Monad (forM)
import qualified Data.ByteString as ByteString
import qualified Data.ByteString.Short as ShortByteString
import qualified Data.List.NonEmpty as NonEmpty
import qualified Data.Map.NonEmpty as NEMap
import Data.Maybe (catMaybes, fromMaybe)
import Data.Proxy (Proxy (..))
import Data.String (IsString (..))
import Data.Traversable (mapAccumM)
import Data.Word (Word8)
import GHC.Word (Word16)
import Ouroboros.Consensus.Block.Abstract (WithOrigin (..))
import Ouroboros.Consensus.Block.RealPoint (Bytes32RealPoint (..))
import qualified Ouroboros.Consensus.Committee.Crypto.BLS as BLS
import qualified Ouroboros.Consensus.Peras.Cert.V1 as V1
import Ouroboros.Consensus.Peras.Crypto.BLS
( PerasBLSCryptoAggregateVoteSignature (..)
, VRFOutput (..)
, VoteSignature (..)
)
import Ouroboros.Consensus.Peras.Types
( PerasBoostedBlock (..)
, PerasSeatIndex (..)
)
import qualified Ouroboros.Consensus.Peras.Vote.V1 as V1
import Test.QuickCheck
( Arbitrary (..)
, Gen
, Property
, choose
, frequency
, sized
, tabulate
, vectorOf
)
import Test.Util.Peras.Common
( genRoundNo
, genSeatIndex
, mkBucket
)
perasVoteIsPersistent :: V1.PerasVote tag -> Bool
perasVoteIsPersistent :: forall tag. PerasVote tag -> Bool
perasVoteIsPersistent PerasVote tag
vote
| V1.PersistentPerasVoteEligibilityProof{} <- PerasVote tag -> PerasVoteEligibilityProof
forall blk. PerasVote blk -> PerasVoteEligibilityProof
V1.pvEligibilityProof PerasVote tag
vote = Bool
True
| Bool
otherwise = Bool
False
perasCertContainsOnlyPersistentVotes :: V1.PerasCert tag -> Bool
perasCertContainsOnlyPersistentVotes :: forall tag. PerasCert tag -> Bool
perasCertContainsOnlyPersistentVotes PerasCert tag
cert =
(PerasVoteEligibilityProof -> Bool)
-> NonEmpty PerasVoteEligibilityProof -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all
( \case
PerasVoteEligibilityProof
V1.PersistentPerasVoteEligibilityProof -> Bool
True
V1.NonPersistentPerasVoteEligibilityProof{} -> Bool
False
)
( NEMap PerasSeatIndex PerasVoteEligibilityProof
-> NonEmpty PerasVoteEligibilityProof
forall k a. NEMap k a -> NonEmpty a
NEMap.elems
(NEMap PerasSeatIndex PerasVoteEligibilityProof
-> NonEmpty PerasVoteEligibilityProof)
-> (PerasCert tag
-> NEMap PerasSeatIndex PerasVoteEligibilityProof)
-> PerasCert tag
-> NonEmpty PerasVoteEligibilityProof
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PerasCertVoters -> NEMap PerasSeatIndex PerasVoteEligibilityProof
PerasCertVoters
-> NE (Map PerasSeatIndex PerasVoteEligibilityProof)
V1.unPerasCertVoters
(PerasCertVoters -> NEMap PerasSeatIndex PerasVoteEligibilityProof)
-> (PerasCert tag -> PerasCertVoters)
-> PerasCert tag
-> NEMap PerasSeatIndex PerasVoteEligibilityProof
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PerasCert tag -> PerasCertVoters
forall blk. PerasCert blk -> PerasCertVoters
V1.pcVoters
(PerasCert tag -> NonEmpty PerasVoteEligibilityProof)
-> PerasCert tag -> NonEmpty PerasVoteEligibilityProof
forall a b. (a -> b) -> a -> b
$ PerasCert tag
cert
)
genBoostedBlock :: Gen PerasBoostedBlock
genBoostedBlock :: Gen PerasBoostedBlock
genBoostedBlock =
WithOrigin Bytes32RealPoint -> PerasBoostedBlock
PerasBoostedBlock (WithOrigin Bytes32RealPoint -> PerasBoostedBlock)
-> Gen (WithOrigin Bytes32RealPoint) -> Gen PerasBoostedBlock
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen Bytes32RealPoint -> Gen (WithOrigin Bytes32RealPoint)
forall {t}. Gen t -> Gen (WithOrigin t)
genWithOrigin Gen Bytes32RealPoint
genBytes32RealPoint
where
genWithOrigin :: Gen t -> Gen (WithOrigin t)
genWithOrigin Gen t
gen =
[(Int, Gen (WithOrigin t))] -> Gen (WithOrigin t)
forall a. HasCallStack => [(Int, Gen a)] -> Gen a
frequency
[ (Int
1, WithOrigin t -> Gen (WithOrigin t)
forall a. a -> Gen a
forall (f :: * -> *) a. Applicative f => a -> f a
pure WithOrigin t
forall t. WithOrigin t
Origin)
, (Int
9, t -> WithOrigin t
forall t. t -> WithOrigin t
NotOrigin (t -> WithOrigin t) -> Gen t -> Gen (WithOrigin t)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen t
gen)
]
genBytes32RealPoint :: Gen Bytes32RealPoint
genBytes32RealPoint = do
slotNo <- Word64 -> SlotNo
SlotNo (Word64 -> SlotNo) -> Gen Word64 -> Gen SlotNo
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen Word64
forall a. Arbitrary a => Gen a
arbitrary
hash <- ShortByteString.pack <$> vectorOf 32 arbitrary
pure $ Bytes32RealPoint slotNo hash
genPrivateKey :: Proxy r -> Gen (BLS.PrivateKey r)
genPrivateKey :: forall (r :: KeyRole). Proxy r -> Gen (PrivateKey r)
genPrivateKey Proxy r
_ =
PrivateKey r -> Maybe (PrivateKey r) -> PrivateKey r
forall a. a -> Maybe a -> a
fromMaybe ([Char] -> PrivateKey r
forall a. HasCallStack => [Char] -> a
error [Char]
"genPrivateKey: invalid key bytes")
(Maybe (PrivateKey r) -> PrivateKey r)
-> ([Word8] -> Maybe (PrivateKey r)) -> [Word8] -> PrivateKey r
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString -> Maybe (PrivateKey r)
forall (r :: KeyRole).
ByteString -> ByteString -> Maybe (PrivateKey r)
BLS.rawDeserialisePrivateKey ByteString
"ROUNDTRIP"
(ByteString -> Maybe (PrivateKey r))
-> ([Word8] -> ByteString) -> [Word8] -> Maybe (PrivateKey r)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Word8] -> ByteString
ByteString.pack
([Word8] -> PrivateKey r) -> Gen [Word8] -> Gen (PrivateKey r)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Int -> Gen Word8 -> Gen [Word8]
forall a. Int -> Gen a -> Gen [a]
vectorOf Int
32 (forall a. Arbitrary a => Gen a
arbitrary @Word8)
genSignature :: forall r. BLS.HasBLSContext r => Proxy r -> Gen (BLS.Signature r)
genSignature :: forall (r :: KeyRole).
HasBLSContext r =>
Proxy r -> Gen (Signature r)
genSignature Proxy r
_ = do
key <- Proxy r -> Gen (PrivateKey r)
forall (r :: KeyRole). Proxy r -> Gen (PrivateKey r)
genPrivateKey (forall {k} (t :: k). Proxy t
forall (t :: KeyRole). Proxy t
Proxy @r)
msg <- fromString @ByteString <$> arbitrary
pure $ BLS.signWithRole key msg
genVoteEligibilityProof :: Bool -> Gen V1.PerasVoteEligibilityProof
genVoteEligibilityProof :: Bool -> Gen PerasVoteEligibilityProof
genVoteEligibilityProof Bool
shouldGenNonPersistent = do
[(Int, Gen PerasVoteEligibilityProof)]
-> Gen PerasVoteEligibilityProof
forall a. HasCallStack => [(Int, Gen a)] -> Gen a
frequency
[
( Int
4
, PerasVoteEligibilityProof -> Gen PerasVoteEligibilityProof
forall a. a -> Gen a
forall (f :: * -> *) a. Applicative f => a -> f a
pure PerasVoteEligibilityProof
V1.PersistentPerasVoteEligibilityProof
)
,
( if Bool
shouldGenNonPersistent then Int
1 else Int
0
, VRFOutput PerasBLSCrypto -> PerasVoteEligibilityProof
V1.NonPersistentPerasVoteEligibilityProof
(VRFOutput PerasBLSCrypto -> PerasVoteEligibilityProof)
-> (Signature VRF -> VRFOutput PerasBLSCrypto)
-> Signature VRF
-> PerasVoteEligibilityProof
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Signature VRF -> VRFOutput PerasBLSCrypto
PerasBLSCryptoVRFOutput
(Signature VRF -> PerasVoteEligibilityProof)
-> Gen (Signature VRF) -> Gen PerasVoteEligibilityProof
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Proxy VRF -> Gen (Signature VRF)
forall (r :: KeyRole).
HasBLSContext r =>
Proxy r -> Gen (Signature r)
genSignature (forall {k} (t :: k). Proxy t
forall (t :: KeyRole). Proxy t
Proxy @BLS.VRF)
)
]
genVoters :: Bool -> Gen V1.PerasCertVoters
genVoters :: Bool -> Gen PerasCertVoters
genVoters Bool
shouldGenNonPersistent = do
numVoters <-
(Int -> Gen Word16) -> Gen Word16
forall a. (Int -> Gen a) -> Gen a
sized ((Int -> Gen Word16) -> Gen Word16)
-> (Int -> Gen Word16) -> Gen Word16
forall a b. (a -> b) -> a -> b
$ \Int
size ->
(Word16 -> Word16) -> Gen Word16 -> Gen Word16
forall a b. (a -> b) -> Gen a -> Gen b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Word16 -> Word16 -> Word16
forall a. Num a => a -> a -> a
+ Word16
1) (Gen Word16 -> Gen Word16) -> Gen Word16 -> Gen Word16
forall a b. (a -> b) -> a -> b
$
forall a. Random a => (a, a) -> Gen a
choose @Word16 (Word16
0, Int -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
size Word16 -> Word16 -> Word16
forall a. Num a => a -> a -> a
* Word16
10)
numPersistentVoters <-
case shouldGenNonPersistent of
Bool
True -> (Word16, Word16) -> Gen Word16
forall a. Random a => (a, a) -> Gen a
choose (Word16
0, Word16
numVoters)
Bool
False -> Word16 -> Gen Word16
forall a. a -> Gen a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Word16
numVoters
persistentVoters <-
if numPersistentVoters == 0
then pure []
else forM [0 .. numPersistentVoters - 1] $ \Word16
i -> do
let proof :: PerasVoteEligibilityProof
proof = PerasVoteEligibilityProof
V1.PersistentPerasVoteEligibilityProof
(PerasSeatIndex, PerasVoteEligibilityProof)
-> Gen (PerasSeatIndex, PerasVoteEligibilityProof)
forall a. a -> Gen a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Word16 -> PerasSeatIndex
PerasSeatIndex Word16
i, PerasVoteEligibilityProof
proof)
nonPersistentVoters <-
if numPersistentVoters == numVoters
then pure []
else forM [numPersistentVoters .. numVoters - 1] $ \Word16
i -> do
proof <-
VRFOutput PerasBLSCrypto -> PerasVoteEligibilityProof
V1.NonPersistentPerasVoteEligibilityProof
(VRFOutput PerasBLSCrypto -> PerasVoteEligibilityProof)
-> (Signature VRF -> VRFOutput PerasBLSCrypto)
-> Signature VRF
-> PerasVoteEligibilityProof
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Signature VRF -> VRFOutput PerasBLSCrypto
PerasBLSCryptoVRFOutput
(Signature VRF -> PerasVoteEligibilityProof)
-> Gen (Signature VRF) -> Gen PerasVoteEligibilityProof
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Proxy VRF -> Gen (Signature VRF)
forall (r :: KeyRole).
HasBLSContext r =>
Proxy r -> Gen (Signature r)
genSignature (forall {k} (t :: k). Proxy t
forall (t :: KeyRole). Proxy t
Proxy @BLS.VRF)
pure (PerasSeatIndex i, proof)
voters <-
fmap (snd . fmap catMaybes)
. mapAccumM
( \Bool
canDrop (PerasSeatIndex
i, PerasVoteEligibilityProof
proof) -> do
voter <-
[(Int, Gen (Maybe (PerasSeatIndex, PerasVoteEligibilityProof)))]
-> Gen (Maybe (PerasSeatIndex, PerasVoteEligibilityProof))
forall a. HasCallStack => [(Int, Gen a)] -> Gen a
frequency
[ (Int
75, Maybe (PerasSeatIndex, PerasVoteEligibilityProof)
-> Gen (Maybe (PerasSeatIndex, PerasVoteEligibilityProof))
forall a. a -> Gen a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ((PerasSeatIndex, PerasVoteEligibilityProof)
-> Maybe (PerasSeatIndex, PerasVoteEligibilityProof)
forall a. a -> Maybe a
Just (PerasSeatIndex
i, PerasVoteEligibilityProof
proof)))
, (if Bool
canDrop then Int
25 else Int
0, Maybe (PerasSeatIndex, PerasVoteEligibilityProof)
-> Gen (Maybe (PerasSeatIndex, PerasVoteEligibilityProof))
forall a. a -> Gen a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe (PerasSeatIndex, PerasVoteEligibilityProof)
forall a. Maybe a
Nothing)
]
pure
( canDrop || voter == Nothing
, voter
)
)
False
$ persistentVoters <> nonPersistentVoters
pure $
V1.PerasCertVoters (NEMap.fromList (NonEmpty.fromList voters))
genPerasVote :: Bool -> Gen (V1.PerasVote tag)
genPerasVote :: forall tag. Bool -> Gen (PerasVote tag)
genPerasVote Bool
shouldGenNonPersistent = do
pvRoundNo <- Gen PerasRoundNo
genRoundNo
pvBoostedBlock <- genBoostedBlock
pvSeatIndex <- genSeatIndex
pvEligibilityProof <- genVoteEligibilityProof shouldGenNonPersistent
pvSignature <-
PerasBLSCryptoVoteSignature
<$> genSignature (Proxy @BLS.SIGN)
pure
V1.PerasVote
{ V1.pvRoundNo
, V1.pvBoostedBlock
, V1.pvSeatIndex
, V1.pvEligibilityProof
, V1.pvSignature
}
genPerasCert :: Bool -> Gen (V1.PerasCert tag)
genPerasCert :: forall tag. Bool -> Gen (PerasCert tag)
genPerasCert Bool
shouldGenNonPersistent = do
pcRoundNo <- Gen PerasRoundNo
genRoundNo
pcBoostedBlock <- genBoostedBlock
pcVoters <- genVoters shouldGenNonPersistent
pcSignature <-
PerasBLSCryptoAggregateVoteSignature
<$> genSignature (Proxy @BLS.SIGN)
pure
V1.PerasCert
{ V1.pcRoundNo
, V1.pcBoostedBlock
, V1.pcVoters
, V1.pcSignature
}
tabulatePerasCert :: V1.PerasCert tag -> Property -> Property
tabulatePerasCert :: forall tag. PerasCert tag -> Property -> Property
tabulatePerasCert PerasCert tag
cert =
((Property -> Property)
-> (Property -> Property) -> Property -> Property)
-> (Property -> Property)
-> [Property -> Property]
-> Property
-> Property
forall a b. (a -> b -> b) -> b -> [a] -> b
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr (((Property -> Property)
-> (Property -> Property) -> Property -> Property)
-> (Property -> Property)
-> (Property -> Property)
-> Property
-> Property
forall a b c. (a -> b -> c) -> b -> a -> c
flip (Property -> Property)
-> (Property -> Property) -> Property -> Property
forall b c a. (b -> c) -> (a -> b) -> a -> c
(.)) Property -> Property
forall a. a -> a
id ([Property -> Property] -> Property -> Property)
-> [Property -> Property] -> Property -> Property
forall a b. (a -> b) -> a -> b
$
[ [Char] -> [[Char]] -> Property -> Property
forall prop.
Testable prop =>
[Char] -> [[Char]] -> prop -> Property
tabulate
[Char]
"Number of voters"
[Int -> Int -> [Char] -> [Char]
mkBucket Int
100 Int
numVoters [Char]
" voters"]
, [Char] -> [[Char]] -> Property -> Property
forall prop.
Testable prop =>
[Char] -> [[Char]] -> prop -> Property
tabulate
[Char]
"Proportion of persistent voters"
[Int -> Int -> [Char] -> [Char]
mkBucket Int
10 Int
persistentVotersRatio [Char]
"%"]
]
where
numVoters :: Int
numVoters =
NEMap PerasSeatIndex PerasVoteEligibilityProof -> Int
forall a. NEMap PerasSeatIndex a -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length
(NEMap PerasSeatIndex PerasVoteEligibilityProof -> Int)
-> (PerasCert tag
-> NEMap PerasSeatIndex PerasVoteEligibilityProof)
-> PerasCert tag
-> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PerasCertVoters -> NEMap PerasSeatIndex PerasVoteEligibilityProof
PerasCertVoters
-> NE (Map PerasSeatIndex PerasVoteEligibilityProof)
V1.unPerasCertVoters
(PerasCertVoters -> NEMap PerasSeatIndex PerasVoteEligibilityProof)
-> (PerasCert tag -> PerasCertVoters)
-> PerasCert tag
-> NEMap PerasSeatIndex PerasVoteEligibilityProof
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PerasCert tag -> PerasCertVoters
forall blk. PerasCert blk -> PerasCertVoters
V1.pcVoters
(PerasCert tag -> Int) -> PerasCert tag -> Int
forall a b. (a -> b) -> a -> b
$ PerasCert tag
cert
numPersistentVoters :: Int
numPersistentVoters =
[PerasVoteEligibilityProof] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length
([PerasVoteEligibilityProof] -> Int)
-> (PerasCert tag -> [PerasVoteEligibilityProof])
-> PerasCert tag
-> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (PerasVoteEligibilityProof -> Bool)
-> [PerasVoteEligibilityProof] -> [PerasVoteEligibilityProof]
forall a. (a -> Bool) -> [a] -> [a]
filter (PerasVoteEligibilityProof -> PerasVoteEligibilityProof -> Bool
forall a. Eq a => a -> a -> Bool
== PerasVoteEligibilityProof
V1.PersistentPerasVoteEligibilityProof)
([PerasVoteEligibilityProof] -> [PerasVoteEligibilityProof])
-> (PerasCert tag -> [PerasVoteEligibilityProof])
-> PerasCert tag
-> [PerasVoteEligibilityProof]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NonEmpty PerasVoteEligibilityProof -> [PerasVoteEligibilityProof]
forall a. NonEmpty a -> [a]
NonEmpty.toList
(NonEmpty PerasVoteEligibilityProof -> [PerasVoteEligibilityProof])
-> (PerasCert tag -> NonEmpty PerasVoteEligibilityProof)
-> PerasCert tag
-> [PerasVoteEligibilityProof]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NEMap PerasSeatIndex PerasVoteEligibilityProof
-> NonEmpty PerasVoteEligibilityProof
forall k a. NEMap k a -> NonEmpty a
NEMap.elems
(NEMap PerasSeatIndex PerasVoteEligibilityProof
-> NonEmpty PerasVoteEligibilityProof)
-> (PerasCert tag
-> NEMap PerasSeatIndex PerasVoteEligibilityProof)
-> PerasCert tag
-> NonEmpty PerasVoteEligibilityProof
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PerasCertVoters -> NEMap PerasSeatIndex PerasVoteEligibilityProof
PerasCertVoters
-> NE (Map PerasSeatIndex PerasVoteEligibilityProof)
V1.unPerasCertVoters
(PerasCertVoters -> NEMap PerasSeatIndex PerasVoteEligibilityProof)
-> (PerasCert tag -> PerasCertVoters)
-> PerasCert tag
-> NEMap PerasSeatIndex PerasVoteEligibilityProof
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PerasCert tag -> PerasCertVoters
forall blk. PerasCert blk -> PerasCertVoters
V1.pcVoters
(PerasCert tag -> Int) -> PerasCert tag -> Int
forall a b. (a -> b) -> a -> b
$ PerasCert tag
cert
persistentVotersRatio :: Int
persistentVotersRatio
| Int
numVoters Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 = Int
0
| Bool
otherwise = Int
numPersistentVoters Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
100 Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
numVoters
tabulatePerasVote :: V1.PerasVote tag -> Property -> Property
tabulatePerasVote :: forall tag. PerasVote tag -> Property -> Property
tabulatePerasVote PerasVote tag
vote =
((Property -> Property)
-> (Property -> Property) -> Property -> Property)
-> (Property -> Property)
-> [Property -> Property]
-> Property
-> Property
forall a b. (a -> b -> b) -> b -> [a] -> b
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr (((Property -> Property)
-> (Property -> Property) -> Property -> Property)
-> (Property -> Property)
-> (Property -> Property)
-> Property
-> Property
forall a b c. (a -> b -> c) -> b -> a -> c
flip (Property -> Property)
-> (Property -> Property) -> Property -> Property
forall b c a. (b -> c) -> (a -> b) -> a -> c
(.)) Property -> Property
forall a. a -> a
id ([Property -> Property] -> Property -> Property)
-> [Property -> Property] -> Property -> Property
forall a b. (a -> b) -> a -> b
$
[ [Char] -> [[Char]] -> Property -> Property
forall prop.
Testable prop =>
[Char] -> [[Char]] -> prop -> Property
tabulate
[Char]
"Voter type"
[[Char]
voterType]
]
where
voterType :: [Char]
voterType =
case PerasVote tag -> PerasVoteEligibilityProof
forall blk. PerasVote blk -> PerasVoteEligibilityProof
V1.pvEligibilityProof PerasVote tag
vote of
PerasVoteEligibilityProof
V1.PersistentPerasVoteEligibilityProof -> [Char]
"persistent"
V1.NonPersistentPerasVoteEligibilityProof VRFOutput PerasBLSCrypto
_ -> [Char]
"non-persistent"