Skip to content

Commit 5f08fb8

Browse files
apollo_consensus: use Vote in Prevote/Precommit SMEvent
1 parent ac3b58a commit 5f08fb8

File tree

4 files changed

+261
-126
lines changed

4 files changed

+261
-126
lines changed

crates/apollo_consensus/src/single_height_consensus.rs

Lines changed: 26 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -240,38 +240,38 @@ impl SingleHeightConsensus {
240240
| StateMachineEvent::TimeoutPrecommit(_round) => {
241241
self.handle_timeout(context, event).await
242242
}
243-
StateMachineEvent::Prevote(_proposal_id, round) => {
243+
StateMachineEvent::Prevote(vote) => {
244244
let Some(last_vote) = &self.last_prevote else {
245245
return Err(ConsensusError::InternalInconsistency(
246246
"No prevote to send".to_string(),
247247
));
248248
};
249-
if last_vote.round > round {
249+
if last_vote.round > vote.round {
250250
// Only replay the newest prevote.
251251
return Ok(ShcReturn::Tasks(Vec::new()));
252252
}
253253
trace_every_n_sec!(REBROADCAST_LOG_PERIOD_SECS, "Rebroadcasting {last_vote:?}");
254254
context.broadcast(last_vote.clone()).await?;
255255
Ok(ShcReturn::Tasks(vec![ShcTask::Prevote(
256256
self.timeouts.get_prevote_timeout(0),
257-
event,
257+
StateMachineEvent::Prevote(last_vote.clone()),
258258
)]))
259259
}
260-
StateMachineEvent::Precommit(_proposal_id, round) => {
260+
StateMachineEvent::Precommit(vote) => {
261261
let Some(last_vote) = &self.last_precommit else {
262262
return Err(ConsensusError::InternalInconsistency(
263263
"No precommit to send".to_string(),
264264
));
265265
};
266-
if last_vote.round > round {
266+
if last_vote.round > vote.round {
267267
// Only replay the newest precommit.
268268
return Ok(ShcReturn::Tasks(Vec::new()));
269269
}
270270
trace_every_n_sec!(REBROADCAST_LOG_PERIOD_SECS, "Rebroadcasting {last_vote:?}");
271271
context.broadcast(last_vote.clone()).await?;
272272
Ok(ShcReturn::Tasks(vec![ShcTask::Precommit(
273273
self.timeouts.get_precommit_timeout(0),
274-
event,
274+
StateMachineEvent::Precommit(last_vote.clone()),
275275
)]))
276276
}
277277
StateMachineEvent::Proposal(proposal_id, round, valid_round) => {
@@ -350,14 +350,10 @@ impl SingleHeightConsensus {
350350
}
351351

352352
let (votes, sm_vote) = match vote.vote_type {
353-
VoteType::Prevote => (
354-
&mut self.prevotes,
355-
StateMachineEvent::Prevote(vote.proposal_commitment, vote.round),
356-
),
357-
VoteType::Precommit => (
358-
&mut self.precommits,
359-
StateMachineEvent::Precommit(vote.proposal_commitment, vote.round),
360-
),
353+
VoteType::Prevote => (&mut self.prevotes, StateMachineEvent::Prevote(vote.clone())),
354+
VoteType::Precommit => {
355+
(&mut self.precommits, StateMachineEvent::Precommit(vote.clone()))
356+
}
361357
};
362358

363359
match votes.entry((vote.round, vote.voter)) {
@@ -407,27 +403,11 @@ impl SingleHeightConsensus {
407403
StateMachineEvent::Decision(proposal_id, round) => {
408404
return self.handle_state_machine_decision(proposal_id, round).await;
409405
}
410-
StateMachineEvent::Prevote(proposal_id, round) => {
411-
ret_val.extend(
412-
self.handle_state_machine_vote(
413-
context,
414-
proposal_id,
415-
round,
416-
VoteType::Prevote,
417-
)
418-
.await?,
419-
);
406+
StateMachineEvent::Prevote(vote) => {
407+
ret_val.extend(self.handle_state_machine_vote(context, vote).await?);
420408
}
421-
StateMachineEvent::Precommit(proposal_id, round) => {
422-
ret_val.extend(
423-
self.handle_state_machine_vote(
424-
context,
425-
proposal_id,
426-
round,
427-
VoteType::Precommit,
428-
)
429-
.await?,
430-
);
409+
StateMachineEvent::Precommit(vote) => {
410+
ret_val.extend(self.handle_state_machine_vote(context, vote).await?);
431411
}
432412
StateMachineEvent::TimeoutPropose(round) => {
433413
ret_val.push(ShcTask::TimeoutPropose(
@@ -520,42 +500,34 @@ impl SingleHeightConsensus {
520500
async fn handle_state_machine_vote<ContextT: ConsensusContext>(
521501
&mut self,
522502
context: &mut ContextT,
523-
proposal_id: Option<ProposalCommitment>,
524-
round: Round,
525-
vote_type: VoteType,
503+
vote: Vote,
526504
) -> Result<Vec<ShcTask>, ConsensusError> {
527-
let prevote_timeout = self.timeouts.get_prevote_timeout(round);
528-
let precommit_timeout = self.timeouts.get_precommit_timeout(round);
529-
let (votes, last_vote, task) = match vote_type {
505+
let prevote_timeout = self.timeouts.get_prevote_timeout(vote.round);
506+
let precommit_timeout = self.timeouts.get_precommit_timeout(vote.round);
507+
let (votes, last_vote, task) = match vote.vote_type {
530508
VoteType::Prevote => (
531509
&mut self.prevotes,
532510
&mut self.last_prevote,
533-
ShcTask::Prevote(prevote_timeout, StateMachineEvent::Prevote(proposal_id, round)),
511+
ShcTask::Prevote(prevote_timeout, StateMachineEvent::Prevote(vote.clone())),
534512
),
535513
VoteType::Precommit => (
536514
&mut self.precommits,
537515
&mut self.last_precommit,
538-
ShcTask::Precommit(
539-
precommit_timeout,
540-
StateMachineEvent::Precommit(proposal_id, round),
541-
),
516+
ShcTask::Precommit(precommit_timeout, StateMachineEvent::Precommit(vote.clone())),
542517
),
543518
};
544-
let vote = Vote {
545-
vote_type,
546-
height: self.state_machine.height().0,
547-
round,
548-
proposal_commitment: proposal_id,
549-
voter: self.state_machine.validator_id(),
550-
};
551-
if let Some(old) = votes.insert((round, self.state_machine.validator_id()), vote.clone()) {
519+
// Ensure the voter matches this node.
520+
assert_eq!(vote.voter, self.state_machine.validator_id());
521+
if let Some(old) =
522+
votes.insert((vote.round, self.state_machine.validator_id()), vote.clone())
523+
{
552524
return Err(ConsensusError::InternalInconsistency(format!(
553525
"State machine should not send repeat votes: old={old:?}, new={vote:?}"
554526
)));
555527
}
556528
*last_vote = match last_vote {
557529
None => Some(vote.clone()),
558-
Some(last_vote) if round > last_vote.round => Some(vote.clone()),
530+
Some(last_vote) if vote.round > last_vote.round => Some(vote.clone()),
559531
Some(_) => {
560532
// According to the Tendermint paper, the state machine should only vote for its
561533
// current round. It should monotonically increase its round. It should only vote

crates/apollo_consensus/src/single_height_consensus_test.rs

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -42,19 +42,16 @@ fn get_proposal_init_for_height(height: BlockNumber) -> ProposalInit {
4242
ProposalInit { height, ..*PROPOSAL_INIT }
4343
}
4444

45-
fn prevote_task(block_felt: Option<Felt>, round: u32) -> ShcTask {
45+
fn prevote_task(block_felt: Option<Felt>, round: u32, voter: ValidatorId) -> ShcTask {
4646
let duration = TIMEOUTS.get_prevote_timeout(round);
47-
ShcTask::Prevote(
48-
duration,
49-
StateMachineEvent::Prevote(block_felt.map(ProposalCommitment), round),
50-
)
47+
ShcTask::Prevote(duration, StateMachineEvent::Prevote(prevote(block_felt, 0, round, voter)))
5148
}
5249

53-
fn precommit_task(block_felt: Option<Felt>, round: u32) -> ShcTask {
50+
fn precommit_task(block_felt: Option<Felt>, round: u32, voter: ValidatorId) -> ShcTask {
5451
let duration = TIMEOUTS.get_precommit_timeout(round);
5552
ShcTask::Precommit(
5653
duration,
57-
StateMachineEvent::Precommit(block_felt.map(ProposalCommitment), round),
54+
StateMachineEvent::Precommit(precommit(block_felt, 0, round, voter)),
5855
)
5956
}
6057

@@ -115,7 +112,7 @@ async fn proposer() {
115112
assert_eq!(*shc_ret.as_tasks().unwrap()[0].as_build_proposal().unwrap().0, 0);
116113
assert_eq!(
117114
shc.handle_event(&mut context, StateMachineEvent::GetProposal(Some(BLOCK.id), 0)).await,
118-
Ok(ShcReturn::Tasks(vec![prevote_task(Some(BLOCK.id.0), 0)]))
115+
Ok(ShcReturn::Tasks(vec![prevote_task(Some(BLOCK.id.0), 0, *PROPOSER_ID)]))
119116
);
120117
assert_eq!(
121118
shc.handle_vote(&mut context, prevote(Some(BLOCK.id.0), 0, 0, *VALIDATOR_ID_1)).await,
@@ -130,7 +127,10 @@ async fn proposer() {
130127
// The Node got a Prevote quorum.
131128
assert_eq!(
132129
shc.handle_vote(&mut context, prevote(Some(BLOCK.id.0), 0, 0, *VALIDATOR_ID_2)).await,
133-
Ok(ShcReturn::Tasks(vec![timeout_prevote_task(0), precommit_task(Some(BLOCK.id.0), 0),]))
130+
Ok(ShcReturn::Tasks(vec![
131+
timeout_prevote_task(0),
132+
precommit_task(Some(BLOCK.id.0), 0, *PROPOSER_ID)
133+
]))
134134
);
135135

136136
let precommits = vec![
@@ -194,7 +194,7 @@ async fn validator(repeat_proposal: bool) {
194194
);
195195
assert_eq!(
196196
shc.handle_event(&mut context, VALIDATE_PROPOSAL_EVENT.clone()).await,
197-
Ok(ShcReturn::Tasks(vec![prevote_task(Some(BLOCK.id.0), 0)]))
197+
Ok(ShcReturn::Tasks(vec![prevote_task(Some(BLOCK.id.0), 0, *VALIDATOR_ID_1)]))
198198
);
199199
if repeat_proposal {
200200
// Send the same proposal again, which should be ignored (no expectations).
@@ -215,7 +215,10 @@ async fn validator(repeat_proposal: bool) {
215215
assert_eq!(
216216
shc.handle_vote(&mut context, prevote(Some(BLOCK.id.0), HEIGHT.0, 0, *VALIDATOR_ID_2))
217217
.await,
218-
Ok(ShcReturn::Tasks(vec![timeout_prevote_task(0), precommit_task(Some(BLOCK.id.0), 0)]))
218+
Ok(ShcReturn::Tasks(vec![
219+
timeout_prevote_task(0),
220+
precommit_task(Some(BLOCK.id.0), 0, *VALIDATOR_ID_1)
221+
]))
219222
);
220223

221224
let precommits = vec![
@@ -272,7 +275,7 @@ async fn vote_twice(same_vote: bool) {
272275
);
273276
assert_eq!(
274277
shc.handle_event(&mut context, VALIDATE_PROPOSAL_EVENT.clone()).await,
275-
Ok(ShcReturn::Tasks(vec![prevote_task(Some(BLOCK.id.0), 0)]))
278+
Ok(ShcReturn::Tasks(vec![prevote_task(Some(BLOCK.id.0), 0, *VALIDATOR_ID_1)]))
276279
);
277280

278281
let res =
@@ -290,7 +293,10 @@ async fn vote_twice(same_vote: bool) {
290293
// The Node got a Prevote quorum.
291294
assert_eq!(
292295
res,
293-
Ok(ShcReturn::Tasks(vec![timeout_prevote_task(0), precommit_task(Some(BLOCK.id.0), 0),]))
296+
Ok(ShcReturn::Tasks(vec![
297+
timeout_prevote_task(0),
298+
precommit_task(Some(BLOCK.id.0), 0, *VALIDATOR_ID_1),
299+
]))
294300
);
295301

296302
let first_vote = precommit(Some(BLOCK.id.0), HEIGHT.0, 0, *PROPOSER_ID);
@@ -345,7 +351,7 @@ async fn rebroadcast_votes() {
345351
assert_eq!(*shc_ret.as_tasks().unwrap()[0].as_build_proposal().unwrap().0, 0);
346352
assert_eq!(
347353
shc.handle_event(&mut context, StateMachineEvent::GetProposal(Some(BLOCK.id), 0)).await,
348-
Ok(ShcReturn::Tasks(vec![prevote_task(Some(BLOCK.id.0), 0)]))
354+
Ok(ShcReturn::Tasks(vec![prevote_task(Some(BLOCK.id.0), 0, *PROPOSER_ID)]))
349355
);
350356
assert_eq!(
351357
shc.handle_vote(&mut context, prevote(Some(BLOCK.id.0), 0, 0, *VALIDATOR_ID_1)).await,
@@ -362,12 +368,19 @@ async fn rebroadcast_votes() {
362368
// The Node got a Prevote quorum.
363369
assert_eq!(
364370
shc.handle_vote(&mut context, prevote(Some(BLOCK.id.0), 0, 0, *VALIDATOR_ID_2)).await,
365-
Ok(ShcReturn::Tasks(vec![timeout_prevote_task(0), precommit_task(Some(BLOCK.id.0), 0),]))
371+
Ok(ShcReturn::Tasks(vec![
372+
timeout_prevote_task(0),
373+
precommit_task(Some(BLOCK.id.0), 0, *PROPOSER_ID),
374+
]))
366375
);
367376
// Re-broadcast vote.
368377
assert_eq!(
369-
shc.handle_event(&mut context, StateMachineEvent::Precommit(Some(BLOCK.id), 0)).await,
370-
Ok(ShcReturn::Tasks(vec![precommit_task(Some(BLOCK.id.0), 0),]))
378+
shc.handle_event(
379+
&mut context,
380+
StateMachineEvent::Precommit(precommit(Some(BLOCK.id.0), 0, 0, *PROPOSER_ID))
381+
)
382+
.await,
383+
Ok(ShcReturn::Tasks(vec![precommit_task(Some(BLOCK.id.0), 0, *PROPOSER_ID),]))
371384
);
372385
}
373386

@@ -410,7 +423,10 @@ async fn repropose() {
410423
// The Node got a Prevote quorum, and set valid proposal.
411424
assert_eq!(
412425
shc.handle_vote(&mut context, prevote(Some(BLOCK.id.0), 0, 0, *VALIDATOR_ID_2)).await,
413-
Ok(ShcReturn::Tasks(vec![timeout_prevote_task(0), precommit_task(Some(BLOCK.id.0), 0),]))
426+
Ok(ShcReturn::Tasks(vec![
427+
timeout_prevote_task(0),
428+
precommit_task(Some(BLOCK.id.0), 0, *PROPOSER_ID),
429+
]))
414430
);
415431
// Advance to the next round.
416432
let precommits = vec![

0 commit comments

Comments
 (0)