1use super::{
2 actors::{batcher, resolver, voter},
3 config::{Config, SkipPolicy},
4 elector::{self, Elector as _},
5 types::{Activity, Context},
6};
7use crate::{
8 CertifiableAutomaton, Relay, Reporter,
9 simplex::{Lookahead, Plan, scheme::Scheme},
10};
11use commonware_cryptography::Digest;
12use commonware_macros::select;
13use commonware_p2p::{Blocker, Receiver, Sender};
14use commonware_parallel::Strategy;
15use commonware_runtime::{Clock, ContextCell, Handle, Metrics, Spawner, Storage, spawn_cell};
16use rand_core::CryptoRng;
17use tracing::debug;
18
19pub struct Engine<
21 E: Clock + CryptoRng + Spawner + Storage + Metrics,
22 S: Scheme<D>,
23 L: elector::Config<S>,
24 B: Blocker<PublicKey = S::PublicKey>,
25 D: Digest,
26 A: CertifiableAutomaton<Context = Context<D, S::PublicKey>, Digest = D>,
27 R: Relay<Digest = D, PublicKey = S::PublicKey, Plan = Plan<S::PublicKey>>,
28 F: Reporter<Activity = Activity<S, D>>,
29 T: Strategy,
30> {
31 context: ContextCell<E>,
32
33 voter: voter::Actor<E, S, L::Elector, B, D, A, R, F>,
34 voter_mailbox: voter::Mailbox<S, D>,
35
36 batcher: batcher::Actor<E, S, B, D, F, R, T>,
37 batcher_mailbox: batcher::Mailbox<S, D>,
38
39 resolver: resolver::Actor<E, S, B, D, T>,
40 resolver_mailbox: resolver::Mailbox<S, D>,
41}
42
43impl<
44 E: Clock + CryptoRng + Spawner + Storage + Metrics,
45 S: Scheme<D>,
46 L: elector::Config<S>,
47 B: Blocker<PublicKey = S::PublicKey>,
48 D: Digest,
49 A: CertifiableAutomaton<Context = Context<D, S::PublicKey>, Digest = D>,
50 R: Relay<Digest = D, PublicKey = S::PublicKey, Plan = Plan<S::PublicKey>>,
51 F: Reporter<Activity = Activity<S, D>>,
52 T: Strategy,
53> Engine<E, S, L, B, D, A, R, F, T>
54{
55 pub fn new(mut context: E, cfg: Config<S, L, B, D, A, R, F, T>) -> Self {
57 cfg.assert(&mut context);
59 let skip_budget = match cfg.skip {
60 SkipPolicy::Disabled => 0,
61 SkipPolicy::Enabled { budget, .. } => budget.resolve(cfg.scheme.participants().len()),
62 };
63 let elector = cfg.elector.build(cfg.scheme.participants());
64 let terms = elector.terms();
65 let term_length = terms.length();
66 if let Some(stall_timeout) = terms.stall_timeout() {
67 assert!(
68 stall_timeout > cfg.certification_timeout,
69 "stall timeout must be greater than certification timeout"
70 );
71 }
72
73 let (batcher, batcher_mailbox) = batcher::Actor::new(
75 context.child("batcher"),
76 batcher::Config {
77 scheme: cfg.scheme.clone(),
78 blocker: cfg.blocker.clone(),
79 reporter: cfg.reporter.clone(),
80 track_historical_votes: cfg.track_historical_votes,
81 relay: cfg.relay.clone(),
82 strategy: cfg.strategy.clone(),
83 epoch: cfg.epoch,
84 mailbox_size: cfg.mailbox_size,
85 view_retention: cfg.view_retention,
86 skip: cfg.skip,
87 lookahead: Lookahead::new(&terms),
88 forward: cfg.forward,
89 floor: cfg.floor.view(),
90 },
91 );
92
93 let (voter, voter_mailbox) = voter::Actor::new(
95 context.child("voter"),
96 voter::Config {
97 scheme: cfg.scheme.clone(),
98 elector,
99 blocker: cfg.blocker.clone(),
100 automaton: cfg.automaton,
101 relay: cfg.relay,
102 reporter: cfg.reporter,
103 partition: cfg.partition,
104 mailbox_size: cfg.mailbox_size,
105 epoch: cfg.epoch,
106 floor: cfg.floor,
107 leader_timeout: cfg.leader_timeout,
108 certification_timeout: cfg.certification_timeout,
109 timeout_retry: cfg.timeout_retry,
110 skip_budget,
111 view_retention: cfg.view_retention,
112 replay_buffer: cfg.replay_buffer,
113 write_buffer: cfg.write_buffer,
114 page_cache: cfg.page_cache,
115 },
116 );
117
118 let (resolver, resolver_mailbox) = resolver::Actor::new(
120 context.child("resolver"),
121 resolver::Config {
122 blocker: cfg.blocker,
123 scheme: cfg.scheme,
124 strategy: cfg.strategy,
125 mailbox_size: cfg.mailbox_size,
126 epoch: cfg.epoch,
127 fetch_timeout: cfg.fetch_timeout,
128 fetch_retry_delay: cfg.fetch_retry_delay,
129 term_length,
130 },
131 );
132
133 Self {
135 context: ContextCell::new(context),
136
137 voter,
138 voter_mailbox,
139
140 batcher,
141 batcher_mailbox,
142
143 resolver,
144 resolver_mailbox,
145 }
146 }
147
148 pub fn start(
191 mut self,
192 vote_network: (
193 impl Sender<PublicKey = S::PublicKey>,
194 impl Receiver<PublicKey = S::PublicKey>,
195 ),
196 certificate_network: (
197 impl Sender<PublicKey = S::PublicKey>,
198 impl Receiver<PublicKey = S::PublicKey>,
199 ),
200 resolver_network: (
201 impl Sender<PublicKey = S::PublicKey>,
202 impl Receiver<PublicKey = S::PublicKey>,
203 ),
204 ) -> Handle<()> {
205 spawn_cell!(
206 self.context,
207 self.run(vote_network, certificate_network, resolver_network)
208 )
209 }
210
211 async fn run(
212 self,
213 vote_network: (
214 impl Sender<PublicKey = S::PublicKey>,
215 impl Receiver<PublicKey = S::PublicKey>,
216 ),
217 certificate_network: (
218 impl Sender<PublicKey = S::PublicKey>,
219 impl Receiver<PublicKey = S::PublicKey>,
220 ),
221 resolver_network: (
222 impl Sender<PublicKey = S::PublicKey>,
223 impl Receiver<PublicKey = S::PublicKey>,
224 ),
225 ) {
226 let (vote_sender, vote_receiver) = vote_network;
229 let (certificate_sender, certificate_receiver) = certificate_network;
230 let mut batcher_task = self.batcher.start(
231 self.voter_mailbox.clone(),
232 vote_receiver,
233 certificate_receiver,
234 );
235
236 let (resolver_sender, resolver_receiver) = resolver_network;
238 let mut resolver_task =
239 self.resolver
240 .start(self.voter_mailbox, resolver_sender, resolver_receiver);
241
242 let mut voter_task = self.voter.start(
244 self.batcher_mailbox,
245 self.resolver_mailbox,
246 vote_sender,
247 certificate_sender,
248 );
249
250 let mut shutdown = self.context.stopped();
252 select! {
253 _ = &mut shutdown => {
254 debug!("context shutdown, stopping engine");
255 },
256 voter = &mut voter_task => {
257 debug!(?voter, "voter stopped, shutting down engine");
258 },
259 batcher = &mut batcher_task => {
260 debug!(?batcher, "batcher stopped, shutting down engine");
261 },
262 resolver = &mut resolver_task => {
263 debug!(?resolver, "resolver stopped, shutting down engine");
264 },
265 }
266 }
267}