diff --git a/vetomint/src/lib.rs b/vetomint/src/lib.rs index f1d89a41..ada62202 100644 --- a/vetomint/src/lib.rs +++ b/vetomint/src/lib.rs @@ -1,3 +1,4 @@ +mod misbehavior; mod progress; mod state; diff --git a/vetomint/src/misbehavior.rs b/vetomint/src/misbehavior.rs new file mode 100644 index 00000000..67bbc3ee --- /dev/null +++ b/vetomint/src/misbehavior.rs @@ -0,0 +1,76 @@ +use super::*; +use state::*; + +use std::collections::HashMap; + +/// Check whether there are double prevotes in target round +pub(crate) fn check_double_prevote( + state: &ConsensusState, + target_round: Round, +) -> Vec { + let mut validators_map = HashMap::new(); + let prevotes_in_target_round: Vec<_> = state + .prevotes + .iter() + .filter(|vote| vote.round == target_round) + .collect(); + + for vote in prevotes_in_target_round.iter() { + let (count, origin_proposal) = validators_map + .entry(vote.signer) + .or_insert((0, vote.proposal)); + *count += 1; + + if *count == 2 { + let byzantine_validator = vote.signer; + let double_proposal = vote.proposal; + + return vec![ConsensusResponse::ViolationReport { + violator: byzantine_validator, + misbehavior: Misbehavior::DoublePrevote { + byzantine_node: byzantine_validator, + round: target_round, + proposals: (*origin_proposal, double_proposal), + }, + }]; + } + } + + Vec::new() +} + +/// Check whether there are double precommits in target round +pub(crate) fn check_double_precommit( + state: &ConsensusState, + target_round: Round, +) -> Vec { + let mut validators_map = HashMap::new(); + let precommits_in_target_round: Vec<_> = state + .precommits + .iter() + .filter(|vote| vote.round == target_round) + .collect(); + + for vote in precommits_in_target_round.iter() { + let (count, origin_proposal) = validators_map + .entry(vote.signer) + .or_insert((0, vote.proposal)); + *count += 1; + + if *count == 2 { + let byzantine_validator = vote.signer; + let double_proposal = vote.proposal; + + return vec![ConsensusResponse::ViolationReport { + violator: byzantine_validator, + misbehavior: Misbehavior::DoublePrecommit { + byzantine_node: byzantine_validator, + round: target_round, + proposals: (*origin_proposal, double_proposal), + }, + }]; + } + } + + Vec::new() +} diff --git a/vetomint/src/progress.rs b/vetomint/src/progress.rs index 24978407..e5ff8a9e 100644 --- a/vetomint/src/progress.rs +++ b/vetomint/src/progress.rs @@ -86,6 +86,7 @@ pub(crate) fn progress( response.extend(on_4f_nil_prevote(state, round)); } response.extend(on_5f_prevote(state, round, proposal)); + response.extend(misbehavior::check_double_prevote(state, round)); response } ConsensusEvent::Precommit { @@ -104,6 +105,7 @@ pub(crate) fn progress( if let Some(proposal) = proposal { response.extend(on_4f_non_nil_precommit(state, round, proposal)); } + response.extend(misbehavior::check_double_precommit(state, round)); response } ConsensusEvent::Timer => {