consensus_core/
commit_vote_monitor.rsuse std::sync::Arc;
use parking_lot::Mutex;
use crate::{
block::{BlockAPI as _, VerifiedBlock},
commit::GENESIS_COMMIT_INDEX,
context::Context,
CommitIndex,
};
pub(crate) struct CommitVoteMonitor {
context: Arc<Context>,
highest_voted_commits: Mutex<Vec<CommitIndex>>,
}
impl CommitVoteMonitor {
pub(crate) fn new(context: Arc<Context>) -> Self {
let highest_voted_commits = Mutex::new(vec![0; context.committee.size()]);
Self {
context,
highest_voted_commits,
}
}
pub(crate) fn observe_block(&self, block: &VerifiedBlock) {
let mut highest_voted_commits = self.highest_voted_commits.lock();
for vote in block.commit_votes() {
if vote.index > highest_voted_commits[block.author()] {
highest_voted_commits[block.author()] = vote.index;
}
}
}
pub(crate) fn quorum_commit_index(&self) -> CommitIndex {
let highest_voted_commits = self.highest_voted_commits.lock();
let mut highest_voted_commits = highest_voted_commits
.iter()
.zip(self.context.committee.authorities())
.map(|(commit_index, (_, a))| (*commit_index, a.stake))
.collect::<Vec<_>>();
highest_voted_commits.sort_by(|a, b| a.cmp(b).reverse());
let mut total_stake = 0;
for (commit_index, stake) in highest_voted_commits {
total_stake += stake;
if total_stake >= self.context.committee.quorum_threshold() {
return commit_index;
}
}
GENESIS_COMMIT_INDEX
}
}
#[cfg(test)]
mod test {
use std::sync::Arc;
use super::CommitVoteMonitor;
use crate::{
block::{TestBlock, VerifiedBlock},
commit::{CommitDigest, CommitRef},
context::Context,
};
#[tokio::test]
async fn test_commit_vote_monitor() {
let context = Arc::new(Context::new_for_test(4).0);
let monitor = CommitVoteMonitor::new(context.clone());
let blocks = (0..4)
.map(|i| {
VerifiedBlock::new_for_test(
TestBlock::new(10, i)
.set_commit_votes(vec![CommitRef::new(5 + i, CommitDigest::MIN)])
.build(),
)
})
.collect::<Vec<_>>();
for b in blocks {
monitor.observe_block(&b);
}
assert_eq!(monitor.quorum_commit_index(), 6);
let blocks = (0..2)
.map(|i| {
VerifiedBlock::new_for_test(
TestBlock::new(11, i)
.set_commit_votes(vec![
CommitRef::new(6 + i, CommitDigest::MIN),
CommitRef::new(7 + i, CommitDigest::MIN),
])
.build(),
)
})
.collect::<Vec<_>>();
for b in blocks {
monitor.observe_block(&b);
}
assert_eq!(monitor.quorum_commit_index(), 7);
}
}