Skip to content

Commit

Permalink
Merge branch 'romac/rust-state-machine' into romac/get-value
Browse files Browse the repository at this point in the history
  • Loading branch information
romac committed Nov 7, 2023
2 parents fa2211c + 52d51a4 commit 1c047e6
Show file tree
Hide file tree
Showing 18 changed files with 873 additions and 386 deletions.
3 changes: 2 additions & 1 deletion Code/common/src/round.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use core::cmp;
/// Can be either:
/// - `Round::Nil` (ie. `-1`)
/// - `Round::Some(r)` where `r >= 0`
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum Round {
/// No round, ie. `-1`
Nil,
Expand All @@ -17,6 +17,7 @@ pub enum Round {
impl Round {
/// The initial, zero round.
pub const INITIAL: Round = Round::new(0);
pub const NIL: Round = Round::new(-1);

/// Create a new round.
///
Expand Down
2 changes: 1 addition & 1 deletion Code/common/src/validator_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pub type VotingPower = u64;
/// TODO: Keep this trait or just add the bounds to Consensus::Address?
pub trait Address
where
Self: Clone + Debug + PartialEq + Eq,
Self: Clone + Debug + Eq + Ord,
{
}

Expand Down
61 changes: 39 additions & 22 deletions Code/consensus/src/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand All @@ -36,6 +36,7 @@ where
Vote(SignedVote<Ctx>),
Decide(Round, Ctx::Value),
ScheduleTimeout(Timeout),
NewRound(Round),
}

pub trait Client<Ctx>
Expand All @@ -52,14 +53,14 @@ where
Ctx: Context,
Client: self::Client<Ctx>,
{
client: Client,
height: Ctx::Height,
private_key: Secret<PrivateKey<Ctx>>,
address: Ctx::Address,
validator_set: Ctx::ValidatorSet,
round: Round,
votes: VoteKeeper<Ctx>,
round_states: BTreeMap<Round, RoundState<Ctx>>,
pub client: Client,
pub height: Ctx::Height,
pub private_key: Secret<PrivateKey<Ctx>>,
pub address: Ctx::Address,
pub validator_set: Ctx::ValidatorSet,
pub round: Round,
pub votes: VoteKeeper<Ctx>,
pub round_states: BTreeMap<Round, RoundState<Ctx>>,
}

impl<Ctx, Client> Executor<Ctx, Client>
Expand All @@ -74,19 +75,15 @@ where
private_key: PrivateKey<Ctx>,
address: Ctx::Address,
) -> Self {
let votes = VoteKeeper::new(
height.clone(),
Round::INITIAL,
validator_set.total_voting_power(),
);
let votes = VoteKeeper::new(validator_set.total_voting_power());

Self {
client,
height,
private_key: Secret::new(private_key),
address,
validator_set,
round: Round::INITIAL,
round: Round::NIL,
votes,
round_states: BTreeMap::new(),
}
Expand All @@ -108,13 +105,9 @@ where

match round_msg {
RoundMessage::NewRound(round) => {
// TODO: check if we are the proposer

// XXX: Check if there is an existing state?
self.round_states
.insert(round, RoundState::default().new_round(round));

None
assert!(self.round < round);
Some(Message::NewRound(round))
}

RoundMessage::Proposal(proposal) => {
Expand Down Expand Up @@ -157,6 +150,11 @@ where
RoundEvent::NewRound
};

assert!(self.round < round);
self.round_states
.insert(round, RoundState::default().new_round(round));
self.round = round;

self.apply_event(round, event)
}

Expand Down Expand Up @@ -235,6 +233,7 @@ where
VoteMessage::PolkaValue(v) => RoundEvent::PolkaValue(v),
VoteMessage::PrecommitAny => RoundEvent::PrecommitAny,
VoteMessage::PrecommitValue(v) => RoundEvent::PrecommitValue(v),
VoteMessage::SkipRound(r) => RoundEvent::SkipRound(r),
};

self.apply_event(round, round_event)
Expand All @@ -257,8 +256,26 @@ where

let data = RoundData::new(round, &self.height, &self.address);

// Multiplex the event with the round state.
let mux_event = match event {
RoundEvent::PolkaValue(value_id) => match round_state.proposal {
Some(ref proposal) if proposal.value().id() == value_id => {
RoundEvent::ProposalAndPolkaCurrent(proposal.clone())
}
_ => RoundEvent::PolkaAny,
},
RoundEvent::PrecommitValue(value_id) => match round_state.proposal {
Some(ref proposal) if proposal.value().id() == value_id => {
RoundEvent::ProposalAndPrecommitValue(proposal.clone())
}
_ => RoundEvent::PrecommitAny,
},

_ => event,
};

// Apply the event to the round state machine
let transition = round_state.apply_event(&data, event);
let transition = round_state.apply_event(&data, mux_event);

// Update state
self.round_states.insert(round, transition.next_state);
Expand Down
31 changes: 17 additions & 14 deletions Code/round/src/events.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
use malachite_common::{Context, ValueId};
use malachite_common::{Context, Round, ValueId};

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Event<Ctx>
where
Ctx: Context,
{
NewRound, // Start a new round, not as proposer.
NewRoundProposer(Ctx::Value), // Start a new round and propose the Value.
Proposal(Ctx::Proposal), // Receive a proposal with possible polka round.
ProposalInvalid, // Receive an invalid proposal.
PolkaAny, // Receive +2/3 prevotes for anything.
PolkaNil, // Receive +2/3 prevotes for nil.
PolkaValue(ValueId<Ctx>), // Receive +2/3 prevotes for Value.
PrecommitAny, // Receive +2/3 precommits for anything.
PrecommitValue(ValueId<Ctx>), // Receive +2/3 precommits for Value.
RoundSkip, // Receive +1/3 votes from a higher round.
TimeoutPropose, // Timeout waiting for proposal.
TimeoutPrevote, // Timeout waiting for prevotes.
TimeoutPrecommit, // Timeout waiting for precommits.
NewRound, // Start a new round, not as proposer.L20
NewRoundProposer(Ctx::Value), // Start a new round and propose the Value.L14
Proposal(Ctx::Proposal), // Receive a proposal. L22 + L23 (valid)
ProposalAndPolkaPrevious(Ctx::Proposal), // Recieved a proposal and a polka value from a previous round. L28 + L29 (valid)
ProposalInvalid, // Receive an invalid proposal. L26 + L32 (invalid)
PolkaValue(ValueId<Ctx>), // Receive +2/3 prevotes for valueId. L44
PolkaAny, // Receive +2/3 prevotes for anything. L34
PolkaNil, // Receive +2/3 prevotes for nil. L44
ProposalAndPolkaCurrent(Ctx::Proposal), // Receive +2/3 prevotes for Value in current round. L36
PrecommitAny, // Receive +2/3 precommits for anything. L47
ProposalAndPrecommitValue(Ctx::Proposal), // Receive +2/3 precommits for Value. L49
PrecommitValue(ValueId<Ctx>), // Receive +2/3 precommits for ValueId. L51
SkipRound(Round), // Receive +1/3 messages from a higher round. OneCorrectProcessInHigherRound, L55
TimeoutPropose, // Timeout waiting for proposal. L57
TimeoutPrevote, // Timeout waiting for prevotes. L61
TimeoutPrecommit, // Timeout waiting for precommits. L65
}
17 changes: 1 addition & 16 deletions Code/round/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,25 +76,10 @@ where
..self
}
}

pub fn next_step(self) -> Self {
let step = match self.step {
Step::NewRound => Step::Propose,
Step::Propose => Step::Prevote,
Step::Prevote => Step::Precommit,
_ => self.step,
};

pub fn with_step(self, step: Step) -> Self {
Self { step, ..self }
}

pub fn commit_step(self) -> Self {
Self {
step: Step::Commit,
..self
}
}

pub fn set_locked(self, value: Ctx::Value) -> Self {
Self {
locked: Some(RoundValue::new(value, self.round)),
Expand Down
Loading

0 comments on commit 1c047e6

Please sign in to comment.