use crate::types::{Epoch, Epocher, Height, Round};
use commonware_utils::sync::Mutex;
use std::sync::Arc;
pub(crate) type LastBuilt<B> = Arc<Mutex<Option<(Round, B)>>>;
#[inline]
fn is_at_epoch_boundary<ES: Epocher>(epocher: &ES, block_height: Height, epoch: Epoch) -> bool {
epocher.last(epoch).is_some_and(|last| last == block_height)
}
#[inline]
pub(crate) fn is_valid_reproposal_at_verify<ES: Epocher>(
epocher: &ES,
block_height: Height,
epoch: Epoch,
) -> bool {
is_at_epoch_boundary(epocher, block_height, epoch)
}
#[inline]
pub(crate) fn is_inferred_reproposal_at_certify<ES: Epocher>(
epocher: &ES,
block_height: Height,
embedded_round: Round,
certify_round: Round,
) -> bool {
is_at_epoch_boundary(epocher, block_height, embedded_round.epoch())
&& certify_round.view() > embedded_round.view()
&& certify_round.epoch() == embedded_round.epoch()
}
#[inline]
pub(crate) fn is_block_in_expected_epoch<ES: Epocher>(
epocher: &ES,
block_height: Height,
expected_epoch: Epoch,
) -> bool {
epocher
.containing(block_height)
.is_some_and(|bounds| bounds.epoch() == expected_epoch)
}
#[inline]
pub(crate) fn has_contiguous_height(parent_height: Height, block_height: Height) -> bool {
parent_height.next() == block_height
}
#[cfg(test)]
mod tests {
use super::*;
use crate::types::{FixedEpocher, View};
use commonware_utils::NZU64;
#[test]
fn test_is_valid_reproposal_at_verify() {
let epocher = FixedEpocher::new(NZU64!(10));
assert!(is_valid_reproposal_at_verify(
&epocher,
Height::new(9),
Epoch::new(0)
));
assert!(!is_valid_reproposal_at_verify(
&epocher,
Height::new(8),
Epoch::new(0)
));
assert!(!is_valid_reproposal_at_verify(
&epocher,
Height::new(0),
Epoch::new(u64::MAX)
));
}
#[test]
fn test_is_inferred_reproposal_at_certify() {
let epocher = FixedEpocher::new(NZU64!(10));
let embedded = Round::new(Epoch::new(0), View::new(9));
assert!(is_inferred_reproposal_at_certify(
&epocher,
Height::new(9),
embedded,
Round::new(Epoch::new(0), View::new(10)),
));
assert!(!is_inferred_reproposal_at_certify(
&epocher,
Height::new(9),
embedded,
Round::new(Epoch::new(0), View::new(9)),
));
assert!(!is_inferred_reproposal_at_certify(
&epocher,
Height::new(9),
embedded,
Round::new(Epoch::new(1), View::new(10)),
));
assert!(!is_inferred_reproposal_at_certify(
&epocher,
Height::new(8),
Round::new(Epoch::new(0), View::new(8)),
Round::new(Epoch::new(0), View::new(9)),
));
}
#[test]
fn test_is_block_in_expected_epoch() {
let epocher = FixedEpocher::new(NZU64!(10));
assert!(is_block_in_expected_epoch(
&epocher,
Height::new(7),
Epoch::new(0)
));
assert!(!is_block_in_expected_epoch(
&epocher,
Height::new(7),
Epoch::new(1)
));
assert!(!is_block_in_expected_epoch(
&epocher,
Height::new(u64::MAX),
Epoch::new(0)
));
}
#[test]
fn test_has_contiguous_height() {
assert!(has_contiguous_height(Height::new(6), Height::new(7)));
assert!(!has_contiguous_height(Height::new(6), Height::new(8)));
}
}