Skip to content

Commit

Permalink
fix(code/core-consensus): Verify vote extension on precommits (#820)
Browse files Browse the repository at this point in the history
  • Loading branch information
romac authored Jan 30, 2025
1 parent e8bf0a8 commit b17d82c
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 1 deletion.
54 changes: 54 additions & 0 deletions code/crates/core-consensus/src/handle/vote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,12 +107,14 @@ where
{
let consensus_height = state.driver.height();
let vote_height = signed_vote.height();
let vote_round = signed_vote.round();
let validator_address = signed_vote.validator_address();

let Some(validator_set) = get_validator_set(co, state, signed_vote.height()).await? else {
debug!(
consensus.height = %consensus_height,
vote.height = %vote_height,
vote.round = %vote_round,
validator = %validator_address,
"Received vote for height without known validator set, dropping"
);
Expand All @@ -124,6 +126,7 @@ where
warn!(
consensus.height = %consensus_height,
vote.height = %vote_height,
vote.round = %vote_round,
validator = %validator_address,
"Received vote from unknown validator"
);
Expand All @@ -136,12 +139,63 @@ where
warn!(
consensus.height = %consensus_height,
vote.height = %vote_height,
vote.round = %vote_round,
validator = %validator_address,
"Received vote with invalid signature: {}", PrettyVote::<Ctx>(&signed_vote.message)
);

return Ok(false);
}

verify_vote_extension(co, state, signed_vote, validator).await
}

async fn verify_vote_extension<Ctx>(
co: &Co<Ctx>,
state: &State<Ctx>,
vote: &SignedVote<Ctx>,
validator: &Ctx::Validator,
) -> Result<bool, Error<Ctx>>
where
Ctx: Context,
{
let VoteType::Precommit = vote.vote_type() else {
return Ok(true);
};

let NilOrVal::Val(value_id) = vote.value().as_ref() else {
return Ok(true);
};

let Some(extension) = vote.extension() else {
return Ok(true);
};

let result = perform!(
co,
Effect::VerifyVoteExtension(
vote.height(),
vote.round(),
value_id.clone(),
extension.clone(),
validator.public_key().clone(),
Default::default()
),
Resume::VoteExtensionValidity(result) => result
);

if let Err(e) = result {
warn!(
consensus.height = %state.driver.height(),
vote.height = %vote.height(),
vote.round = %vote.round(),
validator = %validator.address(),
"Received vote with invalid extension: {}, reason: {e}",
PrettyVote::<Ctx>(&vote.message)
);

return Ok(false);
}

Ok(true)
}
5 changes: 4 additions & 1 deletion code/crates/core-consensus/src/types.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use derive_where::derive_where;
use thiserror::Error;

use malachitebft_core_types::{
Context, Proposal, Round, Signature, SignedProposal, SignedVote, Validity, Vote,
Expand Down Expand Up @@ -69,8 +70,10 @@ pub struct ProposedValue<Ctx: Context> {
pub validity: Validity,
}

#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq, Error)]
pub enum VoteExtensionError {
#[error("Invalid vote extension signature")]
InvalidSignature,
#[error("Invalid vote extension")]
InvalidVoteExtension,
}

0 comments on commit b17d82c

Please sign in to comment.