Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vote: Complete vote keeper #39

Merged
merged 18 commits into from
Nov 7, 2023
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Split vote crate into more modules
romac committed Nov 2, 2023
commit c7891fb531884ef065909634b0f4aff83e093cf0
2 changes: 1 addition & 1 deletion Code/consensus/src/executor.rs
Original file line number Diff line number Diff line change
@@ -11,9 +11,9 @@ use malachite_common::{
use malachite_round::events::Event as RoundEvent;
use malachite_round::message::Message as RoundMessage;
use malachite_round::state::State as RoundState;
use malachite_vote::count::Threshold;
use malachite_vote::keeper::Message as VoteMessage;
use malachite_vote::keeper::VoteKeeper;
use malachite_vote::Threshold;

/// Messages that can be received and broadcast by the consensus executor.
#[derive(Clone, Debug, PartialEq, Eq)]
4 changes: 2 additions & 2 deletions Code/test/tests/round_votes.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use malachite_common::Round;
use malachite_vote::count::Threshold;
use malachite_vote::RoundVotes;
use malachite_vote::round_votes::RoundVotes;
use malachite_vote::Threshold;

use malachite_test::{Address, Height, TestContext, ValueId, Vote};

3 changes: 2 additions & 1 deletion Code/test/tests/vote_count.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#![allow(clippy::bool_assert_comparison)]

use malachite_vote::count::{Threshold, VoteCount};
use malachite_vote::count::VoteCount;
use malachite_vote::Threshold;

#[test]
fn vote_count_nil() {
103 changes: 5 additions & 98 deletions Code/vote/src/count.rs
Original file line number Diff line number Diff line change
@@ -1,51 +1,11 @@
use alloc::collections::BTreeMap;
use alloc::collections::BTreeSet;

// TODO: Introduce newtype
// QUESTION: Over what type? i64?
pub type Weight = u64;
use crate::value_weights::ValuesWeights;
use crate::{Threshold, Weight};

/// A value and the weight of votes for it.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ValuesWeights<Value> {
value_weights: BTreeMap<Value, Weight>,
}

impl<Value> ValuesWeights<Value> {
pub fn new() -> ValuesWeights<Value> {
ValuesWeights {
value_weights: BTreeMap::new(),
}
}

/// Add weight to the value and return the new weight.
pub fn add(&mut self, value: Value, weight: Weight) -> Weight
where
Value: Ord,
{
let entry = self.value_weights.entry(value).or_insert(0);
*entry += weight; // FIXME: Deal with overflows
*entry
}

/// Return the weight of the value, or 0 if it is not present.
pub fn get(&self, value: &Value) -> Weight
where
Value: Ord,
{
self.value_weights.get(value).copied().unwrap_or(0)
}

/// Return the sum of the weights of all values.
pub fn sum(&self) -> Weight {
self.value_weights.values().sum() // FIXME: Deal with overflows
}
}

impl<Value> Default for ValuesWeights<Value> {
fn default() -> Self {
Self::new()
}
/// Returns whether or note `value > (2/3)*total`.
fn is_quorum(value: Weight, total: Weight) -> bool {
3 * value > 2 * total
}

/// VoteCount tallys votes of the same type.
@@ -155,64 +115,11 @@ impl<Address, Value> VoteCount<Address, Value> {
}
}

//-------------------------------------------------------------------------
// Round votes
//-------------------------------------------------------------------------

// Thresh represents the different quorum thresholds.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Threshold<ValueId> {
/// No quorum has been reached yet
Unreached,
/// Qorum of votes but not for the same value
Any,
/// Quorum for nil
Nil,
/// Quorum for a value
Value(ValueId),
}

/// Returns whether or note `value > (2/3)*total`.
fn is_quorum(value: Weight, total: Weight) -> bool {
3 * value > 2 * total
}

#[cfg(test)]
#[allow(clippy::bool_assert_comparison)]
mod tests {
use super::*;

#[test]
fn values_weights() {
let mut vw = ValuesWeights::new();

assert_eq!(vw.get(&None), 0);
assert_eq!(vw.get(&Some(1)), 0);

assert_eq!(vw.add(None, 1), 1);
assert_eq!(vw.get(&None), 1);
assert_eq!(vw.get(&Some(1)), 0);

assert_eq!(vw.add(Some(1), 1), 1);
assert_eq!(vw.get(&None), 1);
assert_eq!(vw.get(&Some(1)), 1);

assert_eq!(vw.add(None, 1), 2);
assert_eq!(vw.get(&None), 2);
assert_eq!(vw.get(&Some(1)), 1);

assert_eq!(vw.add(Some(1), 1), 2);
assert_eq!(vw.get(&None), 2);
assert_eq!(vw.get(&Some(1)), 2);

assert_eq!(vw.add(Some(2), 1), 1);
assert_eq!(vw.get(&None), 2);
assert_eq!(vw.get(&Some(1)), 2);
assert_eq!(vw.get(&Some(2)), 1);

// FIXME: Test for and deal with overflows
}

#[test]
fn vote_count_nil() {
let mut vc = VoteCount::new(4);
6 changes: 2 additions & 4 deletions Code/vote/src/keeper.rs
Original file line number Diff line number Diff line change
@@ -2,10 +2,8 @@ use alloc::collections::BTreeMap;

use malachite_common::{Context, Round, ValueId, Vote, VoteType};

use crate::{
count::{Threshold, Weight},
RoundVotes,
};
use crate::round_votes::RoundVotes;
use crate::{Threshold, Weight};

/// Messages emitted by the vote keeper
#[derive(Clone, Debug, PartialEq, Eq)]
61 changes: 18 additions & 43 deletions Code/vote/src/lib.rs
Original file line number Diff line number Diff line change
@@ -14,47 +14,22 @@ extern crate alloc;

pub mod count;
pub mod keeper;

use malachite_common::{Context, Round, ValueId, Vote, VoteType};

use crate::count::{Threshold, VoteCount, Weight};

/// Tracks all the votes for a single round
#[derive(Clone, Debug)]
pub struct RoundVotes<Ctx>
where
Ctx: Context,
{
pub height: Ctx::Height,
pub round: Round,

pub prevotes: VoteCount<Ctx::Address, ValueId<Ctx>>,
pub precommits: VoteCount<Ctx::Address, ValueId<Ctx>>,
}

impl<Ctx> RoundVotes<Ctx>
where
Ctx: Context,
{
pub fn new(height: Ctx::Height, round: Round, total: Weight) -> Self {
RoundVotes {
height,
round,
prevotes: VoteCount::new(total),
precommits: VoteCount::new(total),
}
}

pub fn add_vote(&mut self, vote: Ctx::Vote, weight: Weight) -> Threshold<ValueId<Ctx>> {
match vote.vote_type() {
VoteType::Prevote => {
self.prevotes
.add(vote.validator_address().clone(), vote.take_value(), weight)
}
VoteType::Precommit => {
self.precommits
.add(vote.validator_address().clone(), vote.take_value(), weight)
}
}
}
pub mod round_votes;
pub mod value_weights;

// TODO: Introduce newtype
// QUESTION: Over what type? i64?
pub type Weight = u64;

/// Represents the different quorum thresholds.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Threshold<ValueId> {
/// No quorum has been reached yet
Unreached,
/// Qorum of votes but not for the same value
Any,
/// Quorum for nil
Nil,
/// Quorum for a value
Value(ValueId),
}
44 changes: 44 additions & 0 deletions Code/vote/src/round_votes.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use malachite_common::{Context, Round, ValueId, Vote, VoteType};

use crate::count::VoteCount;
use crate::{Threshold, Weight};

/// Tracks all the votes for a single round
#[derive(Clone, Debug)]
pub struct RoundVotes<Ctx>
where
Ctx: Context,
{
pub height: Ctx::Height,
pub round: Round,

pub prevotes: VoteCount<Ctx::Address, ValueId<Ctx>>,
pub precommits: VoteCount<Ctx::Address, ValueId<Ctx>>,
}

impl<Ctx> RoundVotes<Ctx>
where
Ctx: Context,
{
pub fn new(height: Ctx::Height, round: Round, total: Weight) -> Self {
RoundVotes {
height,
round,
prevotes: VoteCount::new(total),
precommits: VoteCount::new(total),
}
}

pub fn add_vote(&mut self, vote: Ctx::Vote, weight: Weight) -> Threshold<ValueId<Ctx>> {
match vote.vote_type() {
VoteType::Prevote => {
self.prevotes
.add(vote.validator_address().clone(), vote.take_value(), weight)
}
VoteType::Precommit => {
self.precommits
.add(vote.validator_address().clone(), vote.take_value(), weight)
}
}
}
}
82 changes: 82 additions & 0 deletions Code/vote/src/value_weights.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
use alloc::collections::BTreeMap;

use crate::Weight;

/// A value and the weight of votes for it.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ValuesWeights<Value> {
value_weights: BTreeMap<Value, Weight>,
}

impl<Value> ValuesWeights<Value> {
pub fn new() -> ValuesWeights<Value> {
ValuesWeights {
value_weights: BTreeMap::new(),
}
}

/// Add weight to the value and return the new weight.
pub fn add(&mut self, value: Value, weight: Weight) -> Weight
where
Value: Ord,
{
let entry = self.value_weights.entry(value).or_insert(0);
*entry += weight; // FIXME: Deal with overflows
*entry
}

/// Return the weight of the value, or 0 if it is not present.
pub fn get(&self, value: &Value) -> Weight
where
Value: Ord,
{
self.value_weights.get(value).copied().unwrap_or(0)
}

/// Return the sum of the weights of all values.
pub fn sum(&self) -> Weight {
self.value_weights.values().sum() // FIXME: Deal with overflows
}
}

impl<Value> Default for ValuesWeights<Value> {
fn default() -> Self {
Self::new()
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn values_weights() {
let mut vw = ValuesWeights::new();

assert_eq!(vw.get(&None), 0);
assert_eq!(vw.get(&Some(1)), 0);

assert_eq!(vw.add(None, 1), 1);
assert_eq!(vw.get(&None), 1);
assert_eq!(vw.get(&Some(1)), 0);

assert_eq!(vw.add(Some(1), 1), 1);
assert_eq!(vw.get(&None), 1);
assert_eq!(vw.get(&Some(1)), 1);

assert_eq!(vw.add(None, 1), 2);
assert_eq!(vw.get(&None), 2);
assert_eq!(vw.get(&Some(1)), 1);

assert_eq!(vw.add(Some(1), 1), 2);
assert_eq!(vw.get(&None), 2);
assert_eq!(vw.get(&Some(1)), 2);

assert_eq!(vw.add(Some(2), 1), 1);
assert_eq!(vw.get(&None), 2);
assert_eq!(vw.get(&Some(1)), 2);
assert_eq!(vw.get(&Some(2)), 1);

// FIXME: Test for and deal with overflows
}
}