use super::{
elector::Config as Elector,
types::{Activity, Context, Finalization},
};
use crate::{
types::{Epoch, ViewDelta},
CertifiableAutomaton, Epochable, Relay, Reporter, Viewable,
};
use commonware_cryptography::{certificate::Scheme, Digest};
use commonware_p2p::Blocker;
use commonware_parallel::Strategy;
use commonware_runtime::buffer::paged::CacheRef;
use rand_core::CryptoRngCore;
use std::{num::NonZeroUsize, time::Duration};
#[derive(Debug, Clone, Copy)]
pub enum ForwardingPolicy {
Disabled,
SilentVoters,
SilentLeader,
}
impl ForwardingPolicy {
pub const fn is_enabled(&self) -> bool {
!matches!(self, Self::Disabled)
}
}
#[derive(Clone, Debug)]
pub enum Floor<S: Scheme, D: Digest> {
Genesis(D),
Finalized(Finalization<S, D>),
}
impl<S: Scheme, D: Digest> Floor<S, D> {
fn assert<Rng>(&self, epoch: Epoch, rng: &mut Rng, scheme: &S, strategy: &impl Strategy)
where
Rng: CryptoRngCore,
S: super::scheme::Scheme<D>,
{
if let Self::Finalized(finalization) = self {
assert_eq!(
finalization.epoch(),
epoch,
"floor finalization must be in the configured epoch"
);
assert!(
!finalization.view().is_zero(),
"use Floor::Genesis for the genesis view"
);
assert!(
finalization.verify(rng, scheme, strategy),
"floor finalization must verify"
);
}
}
}
pub struct Config<S, L, B, D, A, R, F, T>
where
S: Scheme,
L: Elector<S>,
B: Blocker<PublicKey = S::PublicKey>,
D: Digest,
A: CertifiableAutomaton<Context = Context<D, S::PublicKey>>,
R: Relay,
F: Reporter<Activity = Activity<S, D>>,
T: Strategy,
{
pub scheme: S,
pub elector: L,
pub blocker: B,
pub automaton: A,
pub relay: R,
pub reporter: F,
pub strategy: T,
pub partition: String,
pub mailbox_size: NonZeroUsize,
pub epoch: Epoch,
pub floor: Floor<S, D>,
pub replay_buffer: NonZeroUsize,
pub write_buffer: NonZeroUsize,
pub page_cache: CacheRef,
pub leader_timeout: Duration,
pub certification_timeout: Duration,
pub timeout_retry: Duration,
pub activity_timeout: ViewDelta,
pub skip_timeout: ViewDelta,
pub fetch_timeout: Duration,
pub fetch_concurrent: NonZeroUsize,
pub forwarding: ForwardingPolicy,
}
impl<
S: Scheme,
L: Elector<S>,
B: Blocker<PublicKey = S::PublicKey>,
D: Digest,
A: CertifiableAutomaton<Context = Context<D, S::PublicKey>>,
R: Relay,
F: Reporter<Activity = Activity<S, D>>,
T: Strategy,
> Config<S, L, B, D, A, R, F, T>
{
pub fn assert<Rng>(&self, rng: &mut Rng)
where
Rng: CryptoRngCore,
S: super::scheme::Scheme<D>,
{
assert!(
!self.scheme.participants().is_empty(),
"there must be at least one participant"
);
assert!(
self.leader_timeout > Duration::default(),
"leader timeout must be greater than zero"
);
assert!(
self.certification_timeout > Duration::default(),
"certification timeout must be greater than zero"
);
assert!(
self.leader_timeout <= self.certification_timeout,
"leader timeout must be less than or equal to certification timeout"
);
assert!(
self.timeout_retry > Duration::default(),
"timeout retry broadcast must be greater than zero"
);
assert!(
!self.activity_timeout.is_zero(),
"activity timeout must be greater than zero"
);
assert!(
!self.skip_timeout.is_zero(),
"skip timeout must be greater than zero"
);
assert!(
self.skip_timeout <= self.activity_timeout,
"skip timeout must be less than or equal to activity timeout"
);
assert!(
self.fetch_timeout > Duration::default(),
"fetch timeout must be greater than zero"
);
self.floor
.assert(self.epoch, rng, &self.scheme, &self.strategy);
}
}