Skip to content

Commit

Permalink
test(consensus): update sm tests
Browse files Browse the repository at this point in the history
  • Loading branch information
asmaastarkware committed Jul 28, 2024
1 parent 1e92acd commit 0e1c4fb
Showing 1 changed file with 123 additions and 25 deletions.
148 changes: 123 additions & 25 deletions crates/sequencing/papyrus_consensus/src/state_machine_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ use crate::state_machine::{StateMachine, StateMachineEvent};
use crate::types::ValidatorId;

lazy_static! {
static ref VALIDATOR_ID: ValidatorId = 1_u32.into();
static ref PROPOSER_ID: ValidatorId = 0_u32.into();
static ref VALIDATOR_ID: ValidatorId = 1_u32.into();
}

const BLOCK_HASH: Option<BlockHash> = Some(BlockHash(Felt::ONE));
Expand Down Expand Up @@ -97,27 +97,125 @@ fn validator_receives_votes_first() {
);
assert!(events.is_empty(), "{:?}", events);
}
// TODO(Asmaa): Add this test when we support NIL votes.
// #[test]
// fn buffer_events_during_get_proposal() {
// let mut state_machine = StateMachine::new(*PROPOSER_ID, 4);
// let leader_fn = |_: Round| *PROPOSER_ID;
// let mut events = state_machine.start(&leader_fn);
// assert_eq!(events.pop_front().unwrap(), StateMachineEvent::GetProposal(None, 0));
// assert!(events.is_empty(), "{:?}", events);

// // TODO(matan): When we support NIL votes, we should send them. Real votes without the
// proposal // doesn't make sense.
// events.append(&mut state_machine.handle_event(StateMachineEvent::Proposal(BLOCK_HASH,
// ROUND))); events.append(&mut
// state_machine.handle_event(StateMachineEvent::Prevote(BLOCK_HASH, ROUND))); events.append(&
// mut state_machine.handle_event(StateMachineEvent::Prevote(BLOCK_HASH, ROUND))); events.
// append(&mut state_machine.handle_event(StateMachineEvent::Prevote(BLOCK_HASH, ROUND)));
// assert!(events.is_empty(), "{:?}", events);

// // Node finishes building the proposal.
// events = state_machine.handle_event(StateMachineEvent::GetProposal(None, 0));
// assert_eq!(events.pop_front().unwrap(), StateMachineEvent::Prevote(BLOCK_HASH, ROUND));
// assert_eq!(events.pop_front().unwrap(), StateMachineEvent::Precommit(BLOCK_HASH, ROUND));
// assert!(events.is_empty(), "{:?}", events);
// }

#[test_case(BLOCK_HASH ; "valid_proposal")]
#[test_case(None ; "invalid_proposal")]
fn buffer_events_during_get_proposal(vote: Option<BlockHash>) {
let mut state_machine = StateMachine::new(*PROPOSER_ID, 4);
let leader_fn = |_: Round| *PROPOSER_ID;
let mut events = state_machine.start(&leader_fn);
assert_eq!(events.pop_front().unwrap(), StateMachineEvent::GetProposal(None, 0));
assert!(events.is_empty(), "{:?}", events);

events.append(
&mut state_machine.handle_event(StateMachineEvent::Prevote(vote, ROUND), &leader_fn),
);
events.append(
&mut state_machine.handle_event(StateMachineEvent::Prevote(vote, ROUND), &leader_fn),
);
events.append(
&mut state_machine.handle_event(StateMachineEvent::Prevote(vote, ROUND), &leader_fn),
);
assert!(events.is_empty(), "{:?}", events);

// Node finishes building the proposal.
events =
state_machine.handle_event(StateMachineEvent::GetProposal(BLOCK_HASH, ROUND), &leader_fn);
assert_eq!(events.pop_front().unwrap(), StateMachineEvent::Proposal(BLOCK_HASH, ROUND));
assert_eq!(events.pop_front().unwrap(), StateMachineEvent::Prevote(BLOCK_HASH, ROUND));
assert_eq!(events.pop_front().unwrap(), StateMachineEvent::Precommit(vote, ROUND));
assert!(events.is_empty(), "{:?}", events);
}

#[test]
fn only_send_precommit_with_prevote_quorum_and_proposal() {
let mut state_machine = StateMachine::new(*VALIDATOR_ID, 4);
let leader_fn = |_: Round| *PROPOSER_ID;
let mut events = state_machine.start(&leader_fn);
assert!(events.is_empty(), "{:?}", events);

// Receives votes from all the other nodes first (more than minimum for a quorum).
events.append(
&mut state_machine.handle_event(StateMachineEvent::Prevote(BLOCK_HASH, ROUND), &leader_fn),
);
events.append(
&mut state_machine.handle_event(StateMachineEvent::Prevote(BLOCK_HASH, ROUND), &leader_fn),
);
events.append(
&mut state_machine.handle_event(StateMachineEvent::Prevote(BLOCK_HASH, ROUND), &leader_fn),
);
assert!(events.is_empty(), "{:?}", events);

// Finally the proposal arrives.
events = state_machine.handle_event(StateMachineEvent::Proposal(BLOCK_HASH, ROUND), &leader_fn);
assert_eq!(events.pop_front().unwrap(), StateMachineEvent::Prevote(BLOCK_HASH, ROUND));
assert_eq!(events.pop_front().unwrap(), StateMachineEvent::Precommit(BLOCK_HASH, ROUND));
assert!(events.is_empty(), "{:?}", events);
}

#[test]
fn only_decide_with_prcommit_quorum_and_proposal() {
let mut state_machine = StateMachine::new(*VALIDATOR_ID, 4);
let leader_fn = |_: Round| *PROPOSER_ID;
let mut events = state_machine.start(&leader_fn);
assert!(events.is_empty(), "{:?}", events);

// Receives votes from all the other nodes first (more than minimum for a quorum).
events.append(
&mut state_machine.handle_event(StateMachineEvent::Prevote(BLOCK_HASH, ROUND), &leader_fn),
);
events.append(
&mut state_machine.handle_event(StateMachineEvent::Prevote(BLOCK_HASH, ROUND), &leader_fn),
);
events.append(
&mut state_machine.handle_event(StateMachineEvent::Prevote(BLOCK_HASH, ROUND), &leader_fn),
);
events.append(
&mut state_machine
.handle_event(StateMachineEvent::Precommit(BLOCK_HASH, ROUND), &leader_fn),
);
events.append(
&mut state_machine
.handle_event(StateMachineEvent::Precommit(BLOCK_HASH, ROUND), &leader_fn),
);
assert!(events.is_empty(), "{:?}", events);

// Finally the proposal arrives.
events = state_machine.handle_event(StateMachineEvent::Proposal(BLOCK_HASH, ROUND), &leader_fn);
assert_eq!(events.pop_front().unwrap(), StateMachineEvent::Prevote(BLOCK_HASH, ROUND));
assert_eq!(events.pop_front().unwrap(), StateMachineEvent::Precommit(BLOCK_HASH, ROUND));
assert_eq!(
events.pop_front().unwrap(),
StateMachineEvent::Decision(BLOCK_HASH.unwrap(), ROUND)
);
assert!(events.is_empty(), "{:?}", events);
}

#[test]
fn advance_to_the_next_round() {
let mut state_machine = StateMachine::new(*VALIDATOR_ID, 4);

let leader_fn = |_: Round| *PROPOSER_ID;
let mut events = state_machine.start(&leader_fn);
assert!(events.is_empty(), "{:?}", events);

events = state_machine.handle_event(StateMachineEvent::Proposal(BLOCK_HASH, ROUND), &leader_fn);
assert_eq!(events.pop_front().unwrap(), StateMachineEvent::Prevote(BLOCK_HASH, ROUND));
events.append(
&mut state_machine.handle_event(StateMachineEvent::Precommit(None, ROUND), &leader_fn),
);
events.append(
&mut state_machine.handle_event(StateMachineEvent::Precommit(None, ROUND), &leader_fn),
);
assert_eq!(state_machine.round, ROUND);
events.append(
&mut state_machine
.handle_event(StateMachineEvent::Proposal(BLOCK_HASH, ROUND + 1), &leader_fn),
);
assert!(events.is_empty(), "{:?}", events);
events.append(
&mut state_machine.handle_event(StateMachineEvent::Precommit(None, ROUND), &leader_fn),
);
// The Node sends Prevote after advancing to the next round.
assert_eq!(events.pop_front().unwrap(), StateMachineEvent::Prevote(BLOCK_HASH, ROUND + 1));
}

0 comments on commit 0e1c4fb

Please sign in to comment.