Skip to content

Commit

Permalink
Merge branch 'main' into async-get-value-new-event
Browse files Browse the repository at this point in the history
  • Loading branch information
romac committed Nov 24, 2023
2 parents 2e390cb + 2a7862b commit feee5a6
Show file tree
Hide file tree
Showing 10 changed files with 717 additions and 432 deletions.
2 changes: 1 addition & 1 deletion Code/common/src/vote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ where
fn round(&self) -> Round;

/// Get a reference to the value being voted for.
fn value(&self) -> Option<&<Ctx::Value as Value>::Id>;
fn value(&self) -> &Option<<Ctx::Value as Value>::Id>;

/// Take ownership of the value being voted for.
fn take_value(self) -> Option<<Ctx::Value as Value>::Id>;
Expand Down
29 changes: 20 additions & 9 deletions Code/driver/src/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use malachite_round::state::State as RoundState;
use malachite_vote::keeper::Message as VoteMessage;
use malachite_vote::keeper::VoteKeeper;
use malachite_vote::Threshold;
use malachite_vote::ThresholdParams;

use crate::event::Event;
use crate::message::Message;
Expand Down Expand Up @@ -45,7 +46,10 @@ where
validator_set: Ctx::ValidatorSet,
address: Ctx::Address,
) -> Self {
let votes = VoteKeeper::new(validator_set.total_voting_power());
let votes = VoteKeeper::new(
validator_set.total_voting_power(),
ThresholdParams::default(), // TODO: Make this configurable
);

Self {
ctx,
Expand All @@ -57,6 +61,14 @@ where
}
}

pub fn height(&self) -> &Ctx::Height {
&self.round_state.height
}

pub fn round(&self) -> Round {
self.round_state.round
}

pub fn get_proposer(&self, round: Round) -> Result<&Ctx::Validator, Error<Ctx>> {
let address = self
.proposer_selector
Expand All @@ -77,9 +89,7 @@ where
};

let msg = match round_msg {
RoundMessage::NewRound(round) => {
Message::NewRound(self.round_state.height.clone(), round)
}
RoundMessage::NewRound(round) => Message::NewRound(self.height().clone(), round),

RoundMessage::Proposal(proposal) => {
// sign the proposal
Expand Down Expand Up @@ -215,11 +225,12 @@ where
));
}

let round = signed_vote.vote.round();
let vote_round = signed_vote.vote.round();
let current_round = self.round();

let Some(vote_msg) = self
.votes
.apply_vote(signed_vote.vote, validator.voting_power())
let Some(vote_msg) =
self.votes
.apply_vote(signed_vote.vote, validator.voting_power(), current_round)
else {
return Ok(None);
};
Expand All @@ -233,7 +244,7 @@ where
VoteMessage::SkipRound(r) => RoundEvent::SkipRound(r),
};

self.apply_event(round, round_event)
self.apply_event(vote_round, round_event)
}

fn apply_timeout(&mut self, timeout: Timeout) -> Result<Option<RoundMessage<Ctx>>, Error<Ctx>> {
Expand Down
4 changes: 2 additions & 2 deletions Code/test/src/vote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ impl malachite_common::Vote<TestContext> for Vote {
self.round
}

fn value(&self) -> Option<&ValueId> {
self.value.as_ref()
fn value(&self) -> &Option<ValueId> {
&self.value
}

fn take_value(self) -> Option<ValueId> {
Expand Down
265 changes: 265 additions & 0 deletions Code/test/tests/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1061,3 +1061,268 @@ fn driver_steps_invalid_signature() {

assert!(matches!(output, Err(Error::InvalidVoteSignature(_, _))));
}

#[test]
fn driver_steps_skip_round_skip_threshold() {
let value = Value::new(9999);

let sel = RotateProposer::default();

let mut rng = StdRng::seed_from_u64(0x42);

let sk1 = PrivateKey::generate(&mut rng);
let sk2 = PrivateKey::generate(&mut rng);
let sk3 = PrivateKey::generate(&mut rng);

let addr1 = Address::from_public_key(&sk1.public_key());
let addr2 = Address::from_public_key(&sk2.public_key());
let addr3 = Address::from_public_key(&sk3.public_key());

let v1 = Validator::new(sk1.public_key(), 1);
let v2 = Validator::new(sk2.public_key(), 1);
let v3 = Validator::new(sk3.public_key(), 1);

// Proposer is v1, so we, v3, are not the proposer
let (my_sk, my_addr) = (sk3, addr3);

let ctx = TestContext::new(my_sk.clone());
let height = Height::new(1);

let vs = ValidatorSet::new(vec![v1.clone(), v2.clone(), v3.clone()]);
let mut driver = Driver::new(ctx, sel, vs, my_addr);

let steps = vec![
// Start round 0, we, v3, are not the proposer
TestStep {
desc: "Start round 0, we, v3, are not the proposer",
input_event: Some(Event::NewRound(height, Round::new(0))),
expected_output: Some(Message::ScheduleTimeout(Timeout::propose(Round::new(0)))),
expected_round: Round::new(0),
new_state: State {
height,
round: Round::new(0),
step: Step::Propose,
proposal: None,
locked: None,
valid: None,
},
},
// Receive a propose timeout, prevote for nil (from v3)
TestStep {
desc: "Receive a propose timeout, prevote for nil (v3)",
input_event: Some(Event::TimeoutElapsed(Timeout::propose(Round::new(0)))),
expected_output: Some(Message::Vote(
Vote::new_prevote(height, Round::new(0), None, my_addr).signed(&my_sk),
)),
expected_round: Round::new(0),
new_state: State {
height,
round: Round::new(0),
step: Step::Prevote,
proposal: None,
locked: None,
valid: None,
},
},
// Receive our own prevote v3
TestStep {
desc: "Receive our own prevote v3",
input_event: None,
expected_output: None,
expected_round: Round::new(0),
new_state: State {
height,
round: Round::new(0),
step: Step::Prevote,
proposal: None,
locked: None,
valid: None,
},
},
// v1 prevotes for its own proposal
TestStep {
desc: "v1 prevotes for its own proposal in round 1",
input_event: Some(Event::Vote(
Vote::new_prevote(height, Round::new(1), Some(value.id()), addr1).signed(&sk1),
)),
expected_output: None,
expected_round: Round::new(0),
new_state: State {
height,
round: Round::new(0),
step: Step::Prevote,
proposal: None,
locked: None,
valid: None,
},
},
// v2 prevotes for v1 proposal in round 1, expected output is to move to next round
TestStep {
desc: "v2 prevotes for v1 proposal, we get +1/3 messages from future round",
input_event: Some(Event::Vote(
Vote::new_prevote(height, Round::new(1), Some(value.id()), addr2).signed(&sk2),
)),
expected_output: Some(Message::NewRound(height, Round::new(1))),
expected_round: Round::new(1),
new_state: State {
height,
round: Round::new(1),
step: Step::NewRound,
proposal: None,
locked: None,
valid: None,
},
},
];

let mut previous_message = None;

for step in steps {
println!("Step: {}", step.desc);

let execute_message = step
.input_event
.unwrap_or_else(|| previous_message.unwrap());

let output = block_on(driver.execute(execute_message)).expect("execute succeeded");
assert_eq!(output, step.expected_output, "expected output message");

assert_eq!(driver.round(), step.expected_round, "expected round");
assert_eq!(driver.round_state, step.new_state, "new state");

previous_message = output.and_then(to_input_msg);
}
}

#[test]
fn driver_steps_skip_round_quorum_threshold() {
let value = Value::new(9999);

let sel = RotateProposer::default();

let mut rng = StdRng::seed_from_u64(0x42);

let sk1 = PrivateKey::generate(&mut rng);
let sk2 = PrivateKey::generate(&mut rng);
let sk3 = PrivateKey::generate(&mut rng);

let addr1 = Address::from_public_key(&sk1.public_key());
let addr2 = Address::from_public_key(&sk2.public_key());
let addr3 = Address::from_public_key(&sk3.public_key());

let v1 = Validator::new(sk1.public_key(), 1);
let v2 = Validator::new(sk2.public_key(), 2);
let v3 = Validator::new(sk3.public_key(), 1);

// Proposer is v1, so we, v3, are not the proposer
let (my_sk, my_addr) = (sk3, addr3);

let ctx = TestContext::new(my_sk.clone());
let height = Height::new(1);

let vs = ValidatorSet::new(vec![v1.clone(), v2.clone(), v3.clone()]);
let mut driver = Driver::new(ctx, sel, vs, my_addr);

let steps = vec![
// Start round 0, we, v3, are not the proposer
TestStep {
desc: "Start round 0, we, v3, are not the proposer",
input_event: Some(Event::NewRound(height, Round::new(0))),
expected_output: Some(Message::ScheduleTimeout(Timeout::propose(Round::new(0)))),
expected_round: Round::new(0),
new_state: State {
height,
round: Round::new(0),
step: Step::Propose,
proposal: None,
locked: None,
valid: None,
},
},
// Receive a propose timeout, prevote for nil (from v3)
TestStep {
desc: "Receive a propose timeout, prevote for nil (v3)",
input_event: Some(Event::TimeoutElapsed(Timeout::propose(Round::new(0)))),
expected_output: Some(Message::Vote(
Vote::new_prevote(height, Round::new(0), None, my_addr).signed(&my_sk),
)),
expected_round: Round::new(0),
new_state: State {
height,
round: Round::new(0),
step: Step::Prevote,
proposal: None,
locked: None,
valid: None,
},
},
// Receive our own prevote v3
TestStep {
desc: "Receive our own prevote v3",
input_event: None,
expected_output: None,
expected_round: Round::new(0),
new_state: State {
height,
round: Round::new(0),
step: Step::Prevote,
proposal: None,
locked: None,
valid: None,
},
},
// v1 prevotes for its own proposal
TestStep {
desc: "v1 prevotes for its own proposal in round 1",
input_event: Some(Event::Vote(
Vote::new_prevote(height, Round::new(1), Some(value.id()), addr1).signed(&sk1),
)),
expected_output: None,
expected_round: Round::new(0),
new_state: State {
height,
round: Round::new(0),
step: Step::Prevote,
proposal: None,
locked: None,
valid: None,
},
},
// v2 prevotes for v1 proposal in round 1, expected output is to move to next round
TestStep {
desc: "v2 prevotes for v1 proposal, we get +1/3 messages from future round",
input_event: Some(Event::Vote(
Vote::new_prevote(height, Round::new(1), Some(value.id()), addr2).signed(&sk2),
)),
expected_output: Some(Message::NewRound(height, Round::new(1))),
expected_round: Round::new(1),
new_state: State {
height,
round: Round::new(1),
step: Step::NewRound,
proposal: None,
locked: None,
valid: None,
},
},
];

let mut previous_message = None;

for step in steps {
println!("Step: {}", step.desc);

let execute_message = step
.input_event
.unwrap_or_else(|| previous_message.unwrap());

let output = block_on(driver.execute(execute_message)).expect("execute succeeded");
assert_eq!(output, step.expected_output, "expected output message");

assert_eq!(driver.round(), step.expected_round, "expected round");

assert_eq!(driver.round_state, step.new_state, "new state");

previous_message = output.and_then(to_input_msg);
}
}
Loading

0 comments on commit feee5a6

Please sign in to comment.