diff --git a/consensus/consensus-types/src/pipeline/commit_vote.rs b/consensus/consensus-types/src/pipeline/commit_vote.rs index a7ab26d07b271..96a6bd7fde85d 100644 --- a/consensus/consensus-types/src/pipeline/commit_vote.rs +++ b/consensus/consensus-types/src/pipeline/commit_vote.rs @@ -7,7 +7,9 @@ use anyhow::Context; use aptos_crypto::{bls12381, CryptoMaterialError}; use aptos_short_hex_str::AsShortHexStr; use aptos_types::{ - block_info::BlockInfo, ledger_info::LedgerInfo, validator_signer::ValidatorSigner, + block_info::BlockInfo, + ledger_info::{LedgerInfo, SignatureWithStatus}, + validator_signer::ValidatorSigner, validator_verifier::ValidatorVerifier, }; use serde::{Deserialize, Serialize}; @@ -17,7 +19,8 @@ use std::fmt::{Debug, Display, Formatter}; pub struct CommitVote { author: Author, ledger_info: LedgerInfo, - signature: bls12381::Signature, + /// Signature on the LedgerInfo along with a status on whether the signature is verified. + signature: SignatureWithStatus, } // this is required by structured log @@ -62,7 +65,7 @@ impl CommitVote { Self { author, ledger_info, - signature, + signature: SignatureWithStatus::from(signature), } } @@ -78,6 +81,13 @@ impl CommitVote { /// Return the signature of the vote pub fn signature(&self) -> &bls12381::Signature { + self.signature.signature() + } + + /// Returns the signature along with the verification status of the signature. + // Note: SignatureWithStatus has interior mutability for verification status. + // Need to make sure the verification status is set to true only the verification is successful. + pub fn signature_with_status(&self) -> &SignatureWithStatus { &self.signature } @@ -93,7 +103,7 @@ impl CommitVote { /// and then verifies the signature. pub fn verify(&self, validator: &ValidatorVerifier) -> anyhow::Result<()> { validator - .verify(self.author(), &self.ledger_info, &self.signature) + .optimistic_verify(self.author(), &self.ledger_info, &self.signature) .context("Failed to verify Commit Vote") } diff --git a/consensus/src/pipeline/buffer_item.rs b/consensus/src/pipeline/buffer_item.rs index 4854574575abd..c16d8430c42b8 100644 --- a/consensus/src/pipeline/buffer_item.rs +++ b/consensus/src/pipeline/buffer_item.rs @@ -2,7 +2,9 @@ // Parts of the project are originally copyright © Meta Platforms, Inc. // SPDX-License-Identifier: Apache-2.0 -use crate::{pipeline::hashable::Hashable, state_replication::StateComputerCommitCallBackType}; +use crate::{ + counters, pipeline::hashable::Hashable, state_replication::StateComputerCommitCallBackType, +}; use anyhow::anyhow; use aptos_consensus_types::{ common::{Author, Round}, @@ -14,13 +16,13 @@ use aptos_executor_types::ExecutorResult; use aptos_logger::prelude::*; use aptos_reliable_broadcast::DropGuard; use aptos_types::{ - aggregate_signature::PartialSignatures, block_info::BlockInfo, - ledger_info::{LedgerInfo, LedgerInfoWithSignatures, LedgerInfoWithVerifiedSignatures}, + ledger_info::{LedgerInfo, LedgerInfoWithSignatures, LedgerInfoWithUnverifiedSignatures}, validator_verifier::ValidatorVerifier, }; use futures::future::BoxFuture; use itertools::zip_eq; +use std::collections::HashMap; use tokio::time::Instant; fn generate_commit_ledger_info( @@ -38,64 +40,24 @@ fn generate_commit_ledger_info( ) } -fn verify_signatures( - unverified_signatures: PartialSignatures, - validator: &ValidatorVerifier, +fn ledger_info_with_unverified_signatures( + unverified_votes: HashMap, commit_ledger_info: &LedgerInfo, -) -> PartialSignatures { - // Returns a valid partial signature from a set of unverified signatures. - // TODO: Validating individual signatures in expensive. Replace this with optimistic signature - // verification for BLS. Here, we can implement a tree-based batch verification technique that - // filters out invalid signature shares much faster when there are only a few of them - // (e.g., [LM07]: Finding Invalid Signatures in Pairing-Based Batches, - // by Law, Laurie and Matt, Brian J., in Cryptography and Coding, 2007). - PartialSignatures::new( - unverified_signatures - .signatures() - .iter() - .filter(|(author, sig)| validator.verify(**author, commit_ledger_info, sig).is_ok()) - .map(|(author, sig)| (*author, sig.clone())) - .collect(), - ) -} - -fn generate_executed_item_from_ordered( - commit_info: BlockInfo, - executed_blocks: Vec, - verified_signatures: PartialSignatures, - callback: StateComputerCommitCallBackType, - ordered_proof: LedgerInfoWithSignatures, - order_vote_enabled: bool, -) -> BufferItem { - debug!("{} advance to executed from ordered", commit_info); - let partial_commit_proof = LedgerInfoWithVerifiedSignatures::new( - generate_commit_ledger_info(&commit_info, &ordered_proof, order_vote_enabled), - verified_signatures, - ); - BufferItem::Executed(Box::new(ExecutedItem { - executed_blocks, - partial_commit_proof, - callback, - commit_info, - ordered_proof, - })) -} - -fn aggregate_commit_proof( - commit_ledger_info: &LedgerInfo, - verified_signatures: &PartialSignatures, - validator: &ValidatorVerifier, -) -> LedgerInfoWithSignatures { - let aggregated_sig = validator - .aggregate_signatures(verified_signatures.signatures_iter()) - .expect("Failed to generate aggregated signature"); - LedgerInfoWithSignatures::new(commit_ledger_info.clone(), aggregated_sig) +) -> LedgerInfoWithUnverifiedSignatures { + let mut li_with_sig = LedgerInfoWithUnverifiedSignatures::new(commit_ledger_info.clone()); + for vote in unverified_votes.values() { + let sig = vote.signature_with_status(); + if vote.ledger_info() == commit_ledger_info { + li_with_sig.add_signature(vote.author(), sig); + } + } + li_with_sig } // we differentiate buffer items at different stages // for better code readability pub struct OrderedItem { - pub unverified_signatures: PartialSignatures, + pub unverified_votes: HashMap, // This can happen in the fast forward sync path, where we can receive the commit proof // from peers. pub commit_proof: Option, @@ -106,7 +68,7 @@ pub struct OrderedItem { pub struct ExecutedItem { pub executed_blocks: Vec, - pub partial_commit_proof: LedgerInfoWithVerifiedSignatures, + pub partial_commit_proof: LedgerInfoWithUnverifiedSignatures, pub callback: StateComputerCommitCallBackType, pub commit_info: BlockInfo, pub ordered_proof: LedgerInfoWithSignatures, @@ -114,7 +76,7 @@ pub struct ExecutedItem { pub struct SignedItem { pub executed_blocks: Vec, - pub partial_commit_proof: LedgerInfoWithVerifiedSignatures, + pub partial_commit_proof: LedgerInfoWithUnverifiedSignatures, pub callback: StateComputerCommitCallBackType, pub commit_vote: CommitVote, pub rb_handle: Option<(Instant, DropGuard)>, @@ -146,10 +108,10 @@ impl BufferItem { ordered_blocks: Vec, ordered_proof: LedgerInfoWithSignatures, callback: StateComputerCommitCallBackType, - unverified_signatures: PartialSignatures, + unverified_votes: HashMap, ) -> Self { Self::Ordered(Box::new(OrderedItem { - unverified_signatures, + unverified_votes, commit_proof: None, callback, ordered_blocks, @@ -170,7 +132,7 @@ impl BufferItem { let OrderedItem { ordered_blocks, commit_proof, - unverified_signatures, + unverified_votes, callback, ordered_proof, } = *ordered_item; @@ -211,16 +173,11 @@ impl BufferItem { order_vote_enabled, ); - let verified_signatures = - verify_signatures(unverified_signatures, validator, &commit_ledger_info); - if (validator.check_voting_power(verified_signatures.signatures().keys(), true)) - .is_ok() - { - let commit_proof = aggregate_commit_proof( - &commit_ledger_info, - &verified_signatures, - validator, - ); + let mut partial_commit_proof = ledger_info_with_unverified_signatures( + unverified_votes, + &commit_ledger_info, + ); + if let Ok(commit_proof) = partial_commit_proof.aggregate_and_verify(validator) { debug!( "{} advance to aggregated from ordered", commit_proof.commit_info() @@ -231,14 +188,13 @@ impl BufferItem { callback, })) } else { - generate_executed_item_from_ordered( - commit_info, + Self::Executed(Box::new(ExecutedItem { executed_blocks, - verified_signatures, + partial_commit_proof, callback, + commit_info, ordered_proof, - order_vote_enabled, - ) + })) } } }, @@ -294,7 +250,7 @@ impl BufferItem { partial_commit_proof: local_commit_proof, .. } = *signed_item; - assert_eq!(local_commit_proof.commit_info(), commit_proof.commit_info(),); + assert_eq!(local_commit_proof.commit_info(), commit_proof.commit_info()); debug!( "{} advance to aggregated with commit decision", commit_proof.commit_info() @@ -348,43 +304,50 @@ impl BufferItem { pub fn try_advance_to_aggregated(self, validator: &ValidatorVerifier) -> Self { match self { Self::Signed(signed_item) => { - if validator - .check_voting_power(signed_item.partial_commit_proof.signatures().keys(), true) + if signed_item + .partial_commit_proof + .check_voting_power(validator, true) .is_ok() { - Self::Aggregated(Box::new(AggregatedItem { - executed_blocks: signed_item.executed_blocks, - commit_proof: aggregate_commit_proof( - signed_item.partial_commit_proof.ledger_info(), - signed_item.partial_commit_proof.partial_sigs(), - validator, - ), - callback: signed_item.callback, - })) - } else { - Self::Signed(signed_item) + let _time = counters::VERIFY_MSG + .with_label_values(&["commit_vote_aggregate_and_verify"]) + .start_timer(); + if let Ok(commit_proof) = signed_item + .partial_commit_proof + .clone() + .aggregate_and_verify(validator) + { + return Self::Aggregated(Box::new(AggregatedItem { + executed_blocks: signed_item.executed_blocks, + commit_proof, + callback: signed_item.callback, + })); + } } + Self::Signed(signed_item) }, - Self::Executed(executed_item) => { - if validator - .check_voting_power( - executed_item.partial_commit_proof.signatures().keys(), - true, - ) + Self::Executed(mut executed_item) => { + if executed_item + .partial_commit_proof + .check_voting_power(validator, true) .is_ok() { - Self::Aggregated(Box::new(AggregatedItem { - executed_blocks: executed_item.executed_blocks, - commit_proof: aggregate_commit_proof( - executed_item.partial_commit_proof.ledger_info(), - executed_item.partial_commit_proof.partial_sigs(), - validator, - ), - callback: executed_item.callback, - })) - } else { - Self::Executed(executed_item) + let _time = counters::VERIFY_MSG + .with_label_values(&["commit_vote_aggregate_and_verify"]) + .start_timer(); + + if let Ok(commit_proof) = executed_item + .partial_commit_proof + .aggregate_and_verify(validator) + { + return Self::Aggregated(Box::new(AggregatedItem { + executed_blocks: executed_item.executed_blocks, + commit_proof, + callback: executed_item.callback, + })); + } } + Self::Executed(executed_item) }, _ => self, } @@ -417,7 +380,7 @@ impl BufferItem { pub fn add_signature_if_matched(&mut self, vote: CommitVote) -> anyhow::Result<()> { let target_commit_info = vote.commit_info(); let author = vote.author(); - let signature = vote.signature().clone(); + let signature = vote.signature_with_status(); match self { Self::Ordered(ordered) => { if ordered @@ -429,9 +392,7 @@ impl BufferItem { // when advancing to executed item, we will check if the sigs are valid. // each author at most stores a single sig for each item, // so an adversary will not be able to flood our memory. - ordered - .unverified_signatures - .add_signature(author, signature); + ordered.unverified_votes.insert(author, vote); return Ok(()); } }, @@ -497,3 +458,310 @@ impl BufferItem { } } } + +#[cfg(test)] +mod test { + use super::*; + use aptos_consensus_types::{block::Block, block_data::BlockData}; + use aptos_crypto::HashValue; + use aptos_executor_types::StateComputeResult; + use aptos_types::{ + aggregate_signature::AggregateSignature, + ledger_info::LedgerInfo, + validator_signer::ValidatorSigner, + validator_verifier::{ValidatorConsensusInfo, ValidatorVerifier}, + }; + use std::collections::{BTreeMap, HashMap}; + + fn create_validators() -> (Vec, ValidatorVerifier) { + const NUM_SIGNERS: u8 = 7; + let validator_signers: Vec = (0..NUM_SIGNERS) + .map(|i| ValidatorSigner::random([i; 32])) + .collect(); + let mut validator_infos = vec![]; + + for validator in validator_signers.iter() { + validator_infos.push(ValidatorConsensusInfo::new( + validator.author(), + validator.public_key(), + 1, + )); + } + + let mut validator_verifier = + ValidatorVerifier::new_with_quorum_voting_power(validator_infos, 5) + .expect("Incorrect quorum size."); + validator_verifier.set_optimistic_sig_verification_flag(true); + (validator_signers, validator_verifier) + } + + fn create_pipelined_block() -> PipelinedBlock { + PipelinedBlock::new( + Block::new_for_testing( + HashValue::random(), + BlockData::dummy_with_validator_txns(vec![]), + None, + ), + vec![], + StateComputeResult::new_dummy(), + ) + } + + fn create_valid_commit_votes( + validator_signers: Vec, + ledger_info: LedgerInfo, + ) -> Vec { + let mut commit_votes = vec![]; + for validator in validator_signers.iter() { + let commit_vote = + CommitVote::new(validator.author(), ledger_info.clone(), validator).unwrap(); + commit_votes.push(commit_vote); + } + commit_votes + } + + #[test] + fn test_buffer_item_happy_path_1() { + let (validator_signers, validator_verifier) = create_validators(); + let pipelined_block = create_pipelined_block(); + let block_info = pipelined_block.block_info(); + let ledger_info = LedgerInfo::new(block_info.clone(), HashValue::zero()); + let ordered_proof = + LedgerInfoWithSignatures::new(ledger_info.clone(), AggregateSignature::empty()); + let commit_votes = + create_valid_commit_votes(validator_signers.clone(), ledger_info.clone()); + let mut partial_signatures = BTreeMap::new(); + partial_signatures.insert( + validator_signers[0].author(), + commit_votes[0].signature().clone(), + ); + partial_signatures.insert( + validator_signers[1].author(), + commit_votes[1].signature().clone(), + ); + partial_signatures.insert( + validator_signers[2].author(), + commit_votes[2].signature().clone(), + ); + partial_signatures.insert( + validator_signers[3].author(), + commit_votes[3].signature().clone(), + ); + partial_signatures.insert( + validator_signers[4].author(), + commit_votes[4].signature().clone(), + ); + let li_with_sig = validator_verifier + .aggregate_signatures(partial_signatures.iter()) + .unwrap(); + let commit_proof = LedgerInfoWithSignatures::new(ledger_info.clone(), li_with_sig); + + let mut cached_commit_votes = HashMap::new(); + cached_commit_votes.insert(commit_votes[0].author(), commit_votes[0].clone()); + cached_commit_votes.insert(commit_votes[1].author(), commit_votes[1].clone()); + let mut ordered_item = BufferItem::new_ordered( + vec![pipelined_block.clone()], + ordered_proof.clone(), + Box::new(move |_, _| {}), + cached_commit_votes, + ); + + ordered_item + .add_signature_if_matched(commit_votes[2].clone()) + .unwrap(); + ordered_item + .add_signature_if_matched(commit_votes[3].clone()) + .unwrap(); + + let mut executed_item = ordered_item.advance_to_executed_or_aggregated( + vec![pipelined_block.clone()], + &validator_verifier, + None, + true, + ); + + match executed_item { + BufferItem::Executed(ref executed_item_inner) => { + assert_eq!(executed_item_inner.executed_blocks, vec![ + pipelined_block.clone() + ]); + assert_eq!(executed_item_inner.commit_info, block_info); + assert_eq!( + executed_item_inner + .partial_commit_proof + .all_voters() + .count(), + 4 + ); + assert_eq!(executed_item_inner.ordered_proof, ordered_proof); + }, + _ => panic!("Expected executed item."), + } + + executed_item + .add_signature_if_matched(commit_votes[4].clone()) + .unwrap(); + let aggregated_item = executed_item.try_advance_to_aggregated(&validator_verifier); + match aggregated_item { + BufferItem::Aggregated(aggregated_item_inner) => { + assert_eq!(aggregated_item_inner.executed_blocks, vec![pipelined_block]); + assert_eq!(aggregated_item_inner.commit_proof, commit_proof); + }, + _ => panic!("Expected aggregated item."), + } + } + + // This tests the case where some of the commit votes are not correct + #[test] + fn test_buffer_item_bad_path_1() { + let (validator_signers, validator_verifier) = create_validators(); + let pipelined_block = create_pipelined_block(); + let block_info = pipelined_block.block_info(); + let ledger_info = LedgerInfo::new(block_info.clone(), HashValue::zero()); + let ordered_proof = + LedgerInfoWithSignatures::new(ledger_info.clone(), AggregateSignature::empty()); + let mut commit_votes = + create_valid_commit_votes(validator_signers.clone(), ledger_info.clone()); + + // Corrupting commit_votes[3], commit_votes[5] + commit_votes[3] = CommitVote::new_with_signature( + validator_signers[3].author(), + ledger_info.clone(), + bls12381::Signature::dummy_signature(), + ); + commit_votes[5] = CommitVote::new_with_signature( + validator_signers[5].author(), + ledger_info.clone(), + bls12381::Signature::dummy_signature(), + ); + + let mut partial_signatures = BTreeMap::new(); + partial_signatures.insert( + validator_signers[0].author(), + commit_votes[0].signature().clone(), + ); + partial_signatures.insert( + validator_signers[1].author(), + commit_votes[1].signature().clone(), + ); + partial_signatures.insert( + validator_signers[2].author(), + commit_votes[2].signature().clone(), + ); + partial_signatures.insert( + validator_signers[4].author(), + commit_votes[4].signature().clone(), + ); + partial_signatures.insert( + validator_signers[6].author(), + commit_votes[6].signature().clone(), + ); + let li_with_sig = validator_verifier + .aggregate_signatures(partial_signatures.iter()) + .unwrap(); + let commit_proof = LedgerInfoWithSignatures::new(ledger_info.clone(), li_with_sig); + + let mut cached_commit_votes = HashMap::new(); + cached_commit_votes.insert(commit_votes[0].author(), commit_votes[0].clone()); + cached_commit_votes.insert(commit_votes[1].author(), commit_votes[1].clone()); + let mut ordered_item = BufferItem::new_ordered( + vec![pipelined_block.clone()], + ordered_proof.clone(), + Box::new(move |_, _| {}), + cached_commit_votes, + ); + + ordered_item + .add_signature_if_matched(commit_votes[2].clone()) + .unwrap(); + ordered_item + .add_signature_if_matched(commit_votes[3].clone()) + .unwrap(); + + assert_eq!(validator_verifier.pessimistic_verify_set().len(), 0); + let mut executed_item = ordered_item.advance_to_executed_or_aggregated( + vec![pipelined_block.clone()], + &validator_verifier, + None, + true, + ); + + match executed_item { + BufferItem::Executed(ref executed_item_inner) => { + assert_eq!(executed_item_inner.executed_blocks, vec![ + pipelined_block.clone() + ]); + assert_eq!(executed_item_inner.commit_info, block_info); + assert_eq!( + executed_item_inner + .partial_commit_proof + .all_voters() + .count(), + 4 + ); + assert_eq!(executed_item_inner.ordered_proof, ordered_proof); + }, + _ => panic!("Expected executed item."), + } + + executed_item + .add_signature_if_matched(commit_votes[4].clone()) + .unwrap(); + + let mut executed_item = executed_item.try_advance_to_aggregated(&validator_verifier); + match executed_item { + BufferItem::Executed(ref executed_item_inner) => { + assert_eq!(executed_item_inner.executed_blocks, vec![ + pipelined_block.clone() + ]); + assert_eq!(executed_item_inner.commit_info, block_info); + assert_eq!( + executed_item_inner + .partial_commit_proof + .all_voters() + .count(), + 4, // Commit_votes[3] is not correct and will be removed from the partial_commit_proof + ); + assert_eq!(executed_item_inner.ordered_proof, ordered_proof); + }, + _ => panic!("Expected executed item."), + } + assert_eq!(validator_verifier.pessimistic_verify_set().len(), 1); + + executed_item + .add_signature_if_matched(commit_votes[5].clone()) + .unwrap(); + + let mut executed_item = executed_item.try_advance_to_aggregated(&validator_verifier); + match executed_item { + BufferItem::Executed(ref executed_item_inner) => { + assert_eq!(executed_item_inner.executed_blocks, vec![ + pipelined_block.clone() + ]); + assert_eq!(executed_item_inner.commit_info, block_info); + assert_eq!( + executed_item_inner + .partial_commit_proof + .all_voters() + .count(), + 4, // Commit_votes[5] is not correct and will be removed from the partial_commit_proof + ); + assert_eq!(executed_item_inner.ordered_proof, ordered_proof); + }, + _ => panic!("Expected executed item."), + } + assert_eq!(validator_verifier.pessimistic_verify_set().len(), 2); + + executed_item + .add_signature_if_matched(commit_votes[6].clone()) + .unwrap(); + let aggregated_item = executed_item.try_advance_to_aggregated(&validator_verifier); + match aggregated_item { + BufferItem::Aggregated(aggregated_item_inner) => { + assert_eq!(aggregated_item_inner.executed_blocks, vec![pipelined_block]); + assert_eq!(aggregated_item_inner.commit_proof, commit_proof); + }, + _ => panic!("Expected aggregated item."), + } + } +} diff --git a/consensus/src/pipeline/buffer_manager.rs b/consensus/src/pipeline/buffer_manager.rs index 38d5aa8578893..4b7d2e9712ddf 100644 --- a/consensus/src/pipeline/buffer_manager.rs +++ b/consensus/src/pipeline/buffer_manager.rs @@ -31,17 +31,18 @@ use aptos_consensus_types::{ pipeline::commit_vote::CommitVote, pipelined_block::PipelinedBlock, }; -use aptos_crypto::HashValue; +use aptos_crypto::{bls12381, HashValue}; use aptos_executor_types::ExecutorResult; use aptos_logger::prelude::*; use aptos_network::protocols::{rpc::error::RpcError, wire::handshake::v1::ProtocolId}; use aptos_reliable_broadcast::{DropGuard, ReliableBroadcast}; use aptos_time_service::TimeService; use aptos_types::{ - account_address::AccountAddress, aggregate_signature::PartialSignatures, - epoch_change::EpochChangeProof, epoch_state::EpochState, ledger_info::LedgerInfoWithSignatures, + account_address::AccountAddress, epoch_change::EpochChangeProof, epoch_state::EpochState, + ledger_info::LedgerInfoWithSignatures, }; use bytes::Bytes; +use fail::fail_point; use futures::{ channel::{ mpsc::{unbounded, UnboundedReceiver, UnboundedSender}, @@ -209,7 +210,6 @@ impl BufferManager { .max_delay(Duration::from_secs(5)); let (tx, rx) = unbounded(); - Self { author, @@ -259,7 +259,6 @@ impl BufferManager { back_pressure_enabled, highest_committed_round, latest_round: highest_committed_round, - consensus_observer_config, consensus_publisher, @@ -415,23 +414,18 @@ impl BufferManager { .await .expect("Failed to send execution schedule request"); - let mut unverified_signatures = PartialSignatures::empty(); + let mut unverified_votes = HashMap::new(); if let Some(block) = ordered_blocks.last() { if let Some(votes) = self.pending_commit_votes.remove(&block.round()) { - votes - .values() - .filter(|vote| vote.commit_info().id() == block.id()) - .for_each(|vote| { - unverified_signatures.add_signature(vote.author(), vote.signature().clone()) - }); + for (_, vote) in votes { + if vote.commit_info().id() == block.id() { + unverified_votes.insert(vote.author(), vote); + } + } } } - let item = BufferItem::new_ordered( - ordered_blocks, - ordered_proof, - callback, - unverified_signatures, - ); + let item = + BufferItem::new_ordered(ordered_blocks, ordered_proof, callback, unverified_votes); self.buffer.push_back(item); } @@ -704,6 +698,17 @@ impl BufferManager { } } + fn generate_commit_message(commit_vote: CommitVote) -> CommitMessage { + fail_point!("consensus::create_invalid_commit_vote", |_| { + CommitMessage::Vote(CommitVote::new_with_signature( + commit_vote.author(), + commit_vote.ledger_info().clone(), + bls12381::Signature::dummy_signature(), + )) + }); + CommitMessage::Vote(commit_vote) + } + /// If the signing response is successful, advance the item to Signed and broadcast commit votes. async fn process_signing_response(&mut self, response: SigningResponse) { let SigningResponse { @@ -733,7 +738,7 @@ impl BufferManager { let mut signed_item = item.advance_to_signed(self.author, signature); let signed_item_mut = signed_item.unwrap_signed_mut(); let commit_vote = signed_item_mut.commit_vote.clone(); - let commit_vote = CommitMessage::Vote(commit_vote); + let commit_vote = Self::generate_commit_message(commit_vote); signed_item_mut.rb_handle = self .do_reliable_broadcast(commit_vote) .map(|handle| (Instant::now(), handle)); diff --git a/testsuite/smoke-test/src/consensus/consensus_fault_tolerance.rs b/testsuite/smoke-test/src/consensus/consensus_fault_tolerance.rs index 834e82a7c8daf..dc640d98146da 100644 --- a/testsuite/smoke-test/src/consensus/consensus_fault_tolerance.rs +++ b/testsuite/smoke-test/src/consensus/consensus_fault_tolerance.rs @@ -244,6 +244,11 @@ async fn test_faulty_votes() { "consensus::create_invalid_order_vote".to_string(), format!("{}%return", 50), ), + ( + (cycle + 2) % num_validators, + "consensus::create_invalid_commit_vote".to_string(), + format!("{}%return", 50), + ), ], true, )