In our current split between components we have:
- Vote aggregation =>
ValidatedPerasVotesReachingQuorum: a collection of Peras votes with the same target (round number and boosted block), with a total stake above the quorum threshold.
- Generic voting committee certificate forging =>
VotesWithSameTarget: a collection of abstract votes with the same target (election ID and candidate)
Ideally, we would want the interface between these components to be compatible, so that, when the vote aggregation component detects a quorum and produces a ValidatedPerasVotesReachingQuorum, we can grab those votes and plug them directly into the certificate forging interface expecting VotesWithSameTarget. All this while somehow enforcing the desired invariants of this collection:
- The collection is non-empty
- All the votes in the collection have the same target (election ID and candidate)
- All the votes in the collection are unique (w.r.t. some notion of uniqueness, e.g. by voter ID)
In the current state, none of the smart constructors of these data structures enforce uniqueness, leaving the room open for potential bugs related to vote equivocation (i.e., having multiple votes from the same voter, see #232).
At the same time, if these are all invariants that are already being enforced "for free" in the client code (e.g. because the vote aggregation component keeps votes in a map indexed by voter ID), then we would like to avoid having to revalidate them again before forging a certificate.
So, for this issue we need to:
- Find the best way to align these data structures and potentially merge them into one.
- Decide whether we want strict validation to happen regardless of how much we trust the client code, or
- Implement two smart constructors: one that validates things unconditionally, and an
unsafe one that turns such validation into a compiler-handled assertion we can deactivate in production after validating that the implementation indeed fulfills these invariants.
In our current split between components we have:
ValidatedPerasVotesReachingQuorum: a collection of Peras votes with the same target (round number and boosted block), with a total stake above the quorum threshold.VotesWithSameTarget: a collection of abstract votes with the same target (election ID and candidate)Ideally, we would want the interface between these components to be compatible, so that, when the vote aggregation component detects a quorum and produces a
ValidatedPerasVotesReachingQuorum, we can grab those votes and plug them directly into the certificate forging interface expectingVotesWithSameTarget. All this while somehow enforcing the desired invariants of this collection:In the current state, none of the smart constructors of these data structures enforce uniqueness, leaving the room open for potential bugs related to vote equivocation (i.e., having multiple votes from the same voter, see #232).
At the same time, if these are all invariants that are already being enforced "for free" in the client code (e.g. because the vote aggregation component keeps votes in a map indexed by voter ID), then we would like to avoid having to revalidate them again before forging a certificate.
So, for this issue we need to:
unsafeone that turns such validation into a compiler-handled assertion we can deactivate in production after validating that the implementation indeed fulfills these invariants.