use commonware_consensus::{
marshal::{
Identifier,
core::{Mailbox as MarshalMailbox, Variant},
},
simplex::{scheme::Scheme, types::Finalization},
types::Epoch,
};
use commonware_cryptography::Digest;
use commonware_utils::{Faults, N3f1};
use std::collections::BTreeMap;
pub(crate) struct Sample<S, D>
where
S: Scheme<D>,
D: Digest,
{
minimum_epoch: Epoch,
replies: BTreeMap<S::PublicKey, Finalization<S, D>>,
floor: Option<Finalization<S, D>>,
}
impl<S, D> Sample<S, D>
where
S: Scheme<D>,
D: Digest,
{
pub(crate) const fn new(minimum_epoch: Epoch) -> Self {
Self {
minimum_epoch,
replies: BTreeMap::new(),
floor: None,
}
}
pub(crate) const fn minimum_epoch(&self) -> Epoch {
self.minimum_epoch
}
pub(crate) const fn floor(&self) -> Option<&Finalization<S, D>> {
self.floor.as_ref()
}
pub(crate) fn pending(&self, peer: &S::PublicKey) -> bool {
self.floor.is_none() && !self.replies.contains_key(peer)
}
pub(crate) fn record(&mut self, peer: S::PublicKey, finalization: Finalization<S, D>) {
self.replies.entry(peer).or_insert(finalization);
}
pub(crate) fn reset(&mut self) {
self.replies.clear();
}
pub(crate) fn select(
&mut self,
committee_size: usize,
judgeable: impl Fn(&Finalization<S, D>) -> bool,
) -> Option<Finalization<S, D>> {
if self.floor.is_some() {
return None;
}
let (floor, replies) =
self.replies
.values()
.fold((None, 0usize), |(floor, replies), finalization| {
if !judgeable(finalization) {
return (floor, replies);
}
let floor = floor
.is_none_or(|candidate: &Finalization<S, D>| {
finalization.round() > candidate.round()
})
.then_some(finalization)
.or(floor);
(floor, replies + 1)
});
let floor = floor?;
if replies < N3f1::max_faults(committee_size) as usize + 1 {
return None;
}
self.floor = Some(floor.clone());
self.floor.clone()
}
}
pub(crate) async fn latest_finalization<S, V>(
marshal: &MarshalMailbox<S, V>,
) -> Option<Finalization<S, V::Commitment>>
where
S: Scheme<V::Commitment>,
V: Variant,
{
let (latest_height, _) = marshal.get_info(Identifier::Latest).await?;
marshal.get_finalization(latest_height).await
}