use super::{
actors::{batcher, resolver, voter},
config::{Config, SkipPolicy},
elector::{self, Elector as _},
types::{Activity, Context},
};
use crate::{
CertifiableAutomaton, Relay, Reporter,
simplex::{Lookahead, Plan, scheme::Scheme},
};
use commonware_cryptography::Digest;
use commonware_macros::select;
use commonware_p2p::{Blocker, Receiver, Sender};
use commonware_parallel::Strategy;
use commonware_runtime::{
BufferPooler, Clock, ContextCell, Handle, Metrics, Spawner, Storage, spawn_cell,
};
use rand_core::CryptoRng;
use tracing::debug;
pub struct Engine<
E: BufferPooler + Clock + CryptoRng + Spawner + Storage + Metrics,
S: Scheme<D>,
L: elector::Config<S>,
B: Blocker<PublicKey = S::PublicKey>,
D: Digest,
A: CertifiableAutomaton<Context = Context<D, S::PublicKey>, Digest = D>,
R: Relay<Digest = D, PublicKey = S::PublicKey, Plan = Plan<S::PublicKey>>,
F: Reporter<Activity = Activity<S, D>>,
T: Strategy,
> {
context: ContextCell<E>,
voter: voter::Actor<E, S, L::Elector, B, D, A, R, F>,
voter_mailbox: voter::Mailbox<S, D>,
batcher: batcher::Actor<E, S, B, D, F, R, T>,
batcher_mailbox: batcher::Mailbox<S, D>,
resolver: resolver::Actor<E, S, B, D, T>,
resolver_mailbox: resolver::Mailbox<S, D>,
}
impl<
E: BufferPooler + Clock + CryptoRng + Spawner + Storage + Metrics,
S: Scheme<D>,
L: elector::Config<S>,
B: Blocker<PublicKey = S::PublicKey>,
D: Digest,
A: CertifiableAutomaton<Context = Context<D, S::PublicKey>, Digest = D>,
R: Relay<Digest = D, PublicKey = S::PublicKey, Plan = Plan<S::PublicKey>>,
F: Reporter<Activity = Activity<S, D>>,
T: Strategy,
> Engine<E, S, L, B, D, A, R, F, T>
{
pub fn new(mut context: E, cfg: Config<S, L, B, D, A, R, F, T>) -> Self {
cfg.assert(&mut context);
let skip_budget = match cfg.skip {
SkipPolicy::Disabled => 0,
SkipPolicy::Enabled { budget, .. } => budget.resolve(cfg.scheme.participants().len()),
};
let elector = cfg.elector.build(cfg.scheme.participants());
let terms = elector.terms();
let term_length = terms.length();
if let Some(stall_timeout) = terms.stall_timeout() {
assert!(
stall_timeout > cfg.certification_timeout,
"stall timeout must be greater than certification timeout"
);
}
let (batcher, batcher_mailbox) = batcher::Actor::new(
context.child("batcher"),
batcher::Config {
scheme: cfg.scheme.clone(),
blocker: cfg.blocker.clone(),
reporter: cfg.reporter.clone(),
track_historical_votes: cfg.track_historical_votes,
relay: cfg.relay.clone(),
strategy: cfg.strategy.clone(),
epoch: cfg.epoch,
mailbox_size: cfg.mailbox_size,
view_retention: cfg.view_retention,
skip: cfg.skip,
lookahead: Lookahead::new(&terms),
forward: cfg.forward,
floor: cfg.floor.view(),
},
);
let (voter, voter_mailbox) = voter::Actor::new(
context.child("voter"),
voter::Config {
scheme: cfg.scheme.clone(),
elector,
blocker: cfg.blocker.clone(),
automaton: cfg.automaton,
relay: cfg.relay,
reporter: cfg.reporter,
partition: cfg.partition,
mailbox_size: cfg.mailbox_size,
epoch: cfg.epoch,
floor: cfg.floor,
leader_timeout: cfg.leader_timeout,
certification_timeout: cfg.certification_timeout,
timeout_retry: cfg.timeout_retry,
skip_budget,
view_retention: cfg.view_retention,
replay_buffer: cfg.replay_buffer,
write_buffer: cfg.write_buffer,
page_cache: cfg.page_cache,
},
);
let (resolver, resolver_mailbox) = resolver::Actor::new(
context.child("resolver"),
resolver::Config {
blocker: cfg.blocker,
scheme: cfg.scheme,
strategy: cfg.strategy,
mailbox_size: cfg.mailbox_size,
epoch: cfg.epoch,
fetch_timeout: cfg.fetch_timeout,
term_length,
},
);
Self {
context: ContextCell::new(context),
voter,
voter_mailbox,
batcher,
batcher_mailbox,
resolver,
resolver_mailbox,
}
}
pub fn start(
mut self,
vote_network: (
impl Sender<PublicKey = S::PublicKey>,
impl Receiver<PublicKey = S::PublicKey>,
),
certificate_network: (
impl Sender<PublicKey = S::PublicKey>,
impl Receiver<PublicKey = S::PublicKey>,
),
resolver_network: (
impl Sender<PublicKey = S::PublicKey>,
impl Receiver<PublicKey = S::PublicKey>,
),
) -> Handle<()> {
spawn_cell!(
self.context,
self.run(vote_network, certificate_network, resolver_network)
)
}
async fn run(
self,
vote_network: (
impl Sender<PublicKey = S::PublicKey>,
impl Receiver<PublicKey = S::PublicKey>,
),
certificate_network: (
impl Sender<PublicKey = S::PublicKey>,
impl Receiver<PublicKey = S::PublicKey>,
),
resolver_network: (
impl Sender<PublicKey = S::PublicKey>,
impl Receiver<PublicKey = S::PublicKey>,
),
) {
let (vote_sender, vote_receiver) = vote_network;
let (certificate_sender, certificate_receiver) = certificate_network;
let mut batcher_task = self.batcher.start(
self.voter_mailbox.clone(),
vote_receiver,
certificate_receiver,
);
let (resolver_sender, resolver_receiver) = resolver_network;
let mut resolver_task =
self.resolver
.start(self.voter_mailbox, resolver_sender, resolver_receiver);
let mut voter_task = self.voter.start(
self.batcher_mailbox,
self.resolver_mailbox,
vote_sender,
certificate_sender,
);
let mut shutdown = self.context.stopped();
select! {
_ = &mut shutdown => {
debug!("context shutdown, stopping engine");
},
voter = &mut voter_task => {
debug!(?voter, "voter stopped, shutting down engine");
},
batcher = &mut batcher_task => {
debug!(?batcher, "batcher stopped, shutting down engine");
},
resolver = &mut resolver_task => {
debug!(?resolver, "resolver stopped, shutting down engine");
},
}
}
}