Skip to content

Commit

Permalink
Merge branch 'main' into hvanz/votekeeper-sum-types
Browse files Browse the repository at this point in the history
  • Loading branch information
hvanz committed Dec 7, 2023
2 parents e6f0d22 + b8e0f9c commit fd8f39c
Show file tree
Hide file tree
Showing 10 changed files with 449 additions and 183 deletions.
53 changes: 35 additions & 18 deletions Code/driver/src/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use malachite_vote::ThresholdParams;

use crate::input::Input;
use crate::output::Output;
use crate::proposals::Proposals;
use crate::Error;
use crate::ProposerSelector;
use crate::Validity;
Expand All @@ -33,6 +34,7 @@ where

pub votes: VoteKeeper<Ctx>,
pub round_state: RoundState<Ctx>,
pub proposals: Proposals<Ctx>,
}

impl<Ctx> Driver<Ctx>
Expand All @@ -57,6 +59,7 @@ where
validator_set,
votes,
round_state: RoundState::default(),
proposals: Proposals::new(),
}
}

Expand Down Expand Up @@ -162,11 +165,14 @@ where
return Ok(None);
}

self.proposals.insert(proposal.clone());

let polka_for_pol = self.votes.is_threshold_met(
&proposal.pol_round(),
VoteType::Prevote,
Threshold::Value(proposal.value().id()),
);

let polka_previous = proposal.pol_round().is_defined()
&& polka_for_pol
&& proposal.pol_round() < self.round_state.round;
Expand All @@ -181,7 +187,7 @@ where
// L32
return self.apply_input(
proposal.round(),
RoundInput::InvalidProposalAndPolkaPrevious(proposal.clone()),
RoundInput::InvalidProposalAndPolkaPrevious(proposal),
);
} else {
return Ok(None);
Expand All @@ -201,13 +207,12 @@ where
) {
return self.apply_input(
proposal.round(),
RoundInput::ProposalAndPrecommitValue(proposal.clone()),
RoundInput::ProposalAndPrecommitValue(proposal),
);
}

// If the proposal is for a different round drop the proposal
// TODO - this check is also done in the round state machine, decide where to do it
if self.round_state.round != proposal.round() {
// If the proposal is for a different round, drop the proposal
if self.round() != proposal.round() {
return Ok(None);
}

Expand All @@ -216,26 +221,28 @@ where
VoteType::Prevote,
Threshold::Value(proposal.value().id()),
);

let polka_current = polka_for_current && self.round_state.step >= Step::Prevote;

// L36
if polka_current {
return self.apply_input(
proposal.round(),
RoundInput::ProposalAndPolkaCurrent(proposal.clone()),
RoundInput::ProposalAndPolkaCurrent(proposal),
);
}

// L28
if polka_previous {
if self.round_state.step == Step::Propose && polka_previous {
// TODO: Check proposal vr is equal to threshold vr
return self.apply_input(
proposal.round(),
RoundInput::ProposalAndPolkaPrevious(proposal.clone()),
RoundInput::ProposalAndPolkaPrevious(proposal),
);
}

// TODO - Caller needs to store the proposal (valid or not) as the quorum (polka or commits) may be met later
self.apply_input(proposal.round(), RoundInput::Proposal(proposal.clone()))
self.apply_input(proposal.round(), RoundInput::Proposal(proposal))
}

fn apply_vote(
Expand Down Expand Up @@ -300,20 +307,29 @@ where

let data = Info::new(input_round, &self.address, proposer.address());

// Multiplex the input with the round state.
// Multiplex the event with the round state.
let mux_input = match input {
RoundInput::PolkaValue(value_id) => match round_state.proposal {
Some(ref proposal) if proposal.value().id() == value_id => {
RoundInput::PolkaValue(value_id) => {
let proposal = self.proposals.find(&value_id, |p| p.round() == input_round);

if let Some(proposal) = proposal {
assert_eq!(proposal.value().id(), value_id);
RoundInput::ProposalAndPolkaCurrent(proposal.clone())
} else {
RoundInput::PolkaAny
}
_ => RoundInput::PolkaAny,
},
RoundInput::PrecommitValue(value_id) => match round_state.proposal {
Some(ref proposal) if proposal.value().id() == value_id => {
}

RoundInput::PrecommitValue(value_id) => {
let proposal = self.proposals.find(&value_id, |p| p.round() == input_round);

if let Some(proposal) = proposal {
assert_eq!(proposal.value().id(), value_id);
RoundInput::ProposalAndPrecommitValue(proposal.clone())
} else {
RoundInput::PrecommitAny
}
_ => RoundInput::PrecommitAny,
},
}

_ => input,
};
Expand All @@ -339,6 +355,7 @@ where
.field("address", &self.address)
.field("validator_set", &self.validator_set)
.field("votes", &self.votes)
.field("proposals", &self.proposals.proposals)
.field("round_state", &self.round_state)
.finish()
}
Expand Down
1 change: 1 addition & 0 deletions Code/driver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ mod driver;
mod error;
mod input;
mod output;
mod proposals;
mod proposer;
mod util;

Expand Down
48 changes: 48 additions & 0 deletions Code/driver/src/proposals.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
use alloc::collections::BTreeMap;
use alloc::vec::Vec;

use malachite_common::ValueId;
use malachite_common::{Context, Proposal, Value};

/// Stores proposals at each round, indexed by their value id.
pub struct Proposals<Ctx>
where
Ctx: Context,
{
pub(crate) proposals: BTreeMap<ValueId<Ctx>, Vec<Ctx::Proposal>>,
}

impl<Ctx> Proposals<Ctx>
where
Ctx: Context,
{
pub fn new() -> Self {
Self {
proposals: BTreeMap::new(),
}
}

pub fn insert(&mut self, proposal: Ctx::Proposal) {
let value_id = proposal.value().id();
self.proposals.entry(value_id).or_default().push(proposal);
}

pub fn find(
&self,
value_id: &ValueId<Ctx>,
p: impl Fn(&Ctx::Proposal) -> bool,
) -> Option<&Ctx::Proposal> {
self.proposals
.get(value_id)
.and_then(|proposals| proposals.iter().find(|proposal| p(proposal)))
}
}

impl<Ctx> Default for Proposals<Ctx>
where
Ctx: Context,
{
fn default() -> Self {
Self::new()
}
}
120 changes: 119 additions & 1 deletion Code/round/src/input.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use core::fmt;

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

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Input<Ctx>
where
Ctx: Context,
Expand Down Expand Up @@ -73,3 +74,120 @@ where
/// L65
TimeoutPrecommit,
}

impl<Ctx: Context> Clone for Input<Ctx> {
#[cfg_attr(coverage_nightly, coverage(off))]
fn clone(&self) -> Self {
match self {
Input::NewRound => Input::NewRound,
Input::ProposeValue(value) => Input::ProposeValue(value.clone()),
Input::Proposal(proposal) => Input::Proposal(proposal.clone()),
Input::InvalidProposal => Input::InvalidProposal,
Input::ProposalAndPolkaPrevious(proposal) => {
Input::ProposalAndPolkaPrevious(proposal.clone())
}
Input::InvalidProposalAndPolkaPrevious(proposal) => {
Input::InvalidProposalAndPolkaPrevious(proposal.clone())
}
Input::PolkaValue(value_id) => Input::PolkaValue(value_id.clone()),
Input::PolkaAny => Input::PolkaAny,
Input::PolkaNil => Input::PolkaNil,
Input::ProposalAndPolkaCurrent(proposal) => {
Input::ProposalAndPolkaCurrent(proposal.clone())
}
Input::PrecommitAny => Input::PrecommitAny,
Input::ProposalAndPrecommitValue(proposal) => {
Input::ProposalAndPrecommitValue(proposal.clone())
}
Input::PrecommitValue(value_id) => Input::PrecommitValue(value_id.clone()),
Input::SkipRound(round) => Input::SkipRound(*round),
Input::TimeoutPropose => Input::TimeoutPropose,
Input::TimeoutPrevote => Input::TimeoutPrevote,
Input::TimeoutPrecommit => Input::TimeoutPrecommit,
}
}
}

impl<Ctx: Context> PartialEq for Input<Ctx> {
#[cfg_attr(coverage_nightly, coverage(off))]
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Input::NewRound, Input::NewRound) => true,
(Input::ProposeValue(value), Input::ProposeValue(other_value)) => value == other_value,
(Input::Proposal(proposal), Input::Proposal(other_proposal)) => {
proposal == other_proposal
}
(Input::InvalidProposal, Input::InvalidProposal) => true,
(
Input::ProposalAndPolkaPrevious(proposal),
Input::ProposalAndPolkaPrevious(other_proposal),
) => proposal == other_proposal,
(
Input::InvalidProposalAndPolkaPrevious(proposal),
Input::InvalidProposalAndPolkaPrevious(other_proposal),
) => proposal == other_proposal,
(Input::PolkaValue(value_id), Input::PolkaValue(other_value_id)) => {
value_id == other_value_id
}
(Input::PolkaAny, Input::PolkaAny) => true,
(Input::PolkaNil, Input::PolkaNil) => true,
(
Input::ProposalAndPolkaCurrent(proposal),
Input::ProposalAndPolkaCurrent(other_proposal),
) => proposal == other_proposal,
(Input::PrecommitAny, Input::PrecommitAny) => true,
(
Input::ProposalAndPrecommitValue(proposal),
Input::ProposalAndPrecommitValue(other_proposal),
) => proposal == other_proposal,
(Input::PrecommitValue(value_id), Input::PrecommitValue(other_value_id)) => {
value_id == other_value_id
}
(Input::SkipRound(round), Input::SkipRound(other_round)) => round == other_round,
(Input::TimeoutPropose, Input::TimeoutPropose) => true,
(Input::TimeoutPrevote, Input::TimeoutPrevote) => true,
(Input::TimeoutPrecommit, Input::TimeoutPrecommit) => true,
_ => false,
}
}
}

impl<Ctx: Context> Eq for Input<Ctx> {}

impl<Ctx> fmt::Debug for Input<Ctx>
where
Ctx: Context,
Ctx::Value: fmt::Debug,
Ctx::Proposal: fmt::Debug,
{
#[cfg_attr(coverage_nightly, coverage(off))]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Input::NewRound => write!(f, "NewRound"),
Input::ProposeValue(value) => write!(f, "ProposeValue({:?})", value),
Input::Proposal(proposal) => write!(f, "Proposal({:?})", proposal),
Input::InvalidProposal => write!(f, "InvalidProposal"),
Input::ProposalAndPolkaPrevious(proposal) => {
write!(f, "ProposalAndPolkaPrevious({:?})", proposal)
}
Input::InvalidProposalAndPolkaPrevious(proposal) => {
write!(f, "InvalidProposalAndPolkaPrevious({:?})", proposal)
}
Input::PolkaValue(value_id) => write!(f, "PolkaValue({:?})", value_id),
Input::PolkaAny => write!(f, "PolkaAny"),
Input::PolkaNil => write!(f, "PolkaNil"),
Input::ProposalAndPolkaCurrent(proposal) => {
write!(f, "ProposalAndPolkaCurrent({:?})", proposal)
}
Input::PrecommitAny => write!(f, "PrecommitAny"),
Input::ProposalAndPrecommitValue(proposal) => {
write!(f, "ProposalAndPrecommitValue({:?})", proposal)
}
Input::PrecommitValue(value_id) => write!(f, "PrecommitValue({:?})", value_id),
Input::SkipRound(round) => write!(f, "SkipRound({:?})", round),
Input::TimeoutPropose => write!(f, "TimeoutPropose"),
Input::TimeoutPrevote => write!(f, "TimeoutPrevote"),
Input::TimeoutPrecommit => write!(f, "TimeoutPrecommit"),
}
}
}
5 changes: 0 additions & 5 deletions Code/round/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ where
pub round: Round,

pub step: Step,
pub proposal: Option<Ctx::Proposal>,
pub locked: Option<RoundValue<Ctx::Value>>,
pub valid: Option<RoundValue<Ctx::Value>>,
}
Expand All @@ -52,7 +51,6 @@ where
height,
round,
step: Step::NewRound,
proposal: None,
locked: None,
valid: None,
}
Expand Down Expand Up @@ -108,7 +106,6 @@ where
height: self.height.clone(),
round: self.round,
step: self.step,
proposal: self.proposal.clone(),
locked: self.locked.clone(),
valid: self.valid.clone(),
}
Expand All @@ -125,7 +122,6 @@ where
.field("height", &self.round)
.field("round", &self.round)
.field("step", &self.step)
.field("proposal", &self.proposal)
.field("locked", &self.locked)
.field("valid", &self.valid)
.finish()
Expand All @@ -141,7 +137,6 @@ where
self.height == other.height
&& self.round == other.round
&& self.step == other.step
&& self.proposal == other.proposal
&& self.locked == other.locked
&& self.valid == other.valid
}
Expand Down
Loading

0 comments on commit fd8f39c

Please sign in to comment.