1#![cfg_attr(not(test), warn(unused_crate_dependencies))]
4#![cfg_attr(docsrs, feature(doc_cfg))]
5
6pub(crate) mod alias;
7mod args;
8pub(crate) mod config;
9pub mod consensus;
10pub(crate) mod dkg;
11pub(crate) mod epoch;
12pub mod metrics;
13
14pub(crate) mod subblocks;
15
16use std::net::SocketAddr;
17
18use commonware_cryptography::ed25519::{PrivateKey, PublicKey};
19use commonware_p2p::authenticated::lookup;
20use commonware_runtime::Metrics as _;
21use eyre::{OptionExt, WrapErr as _, eyre};
22use tempo_commonware_node_config::SigningShare;
23use tempo_node::TempoFullNode;
24
25use crate::config::{
26 BOUNDARY_CERT_CHANNEL_IDENT, BOUNDARY_CERT_LIMIT, BROADCASTER_CHANNEL_IDENT, BROADCASTER_LIMIT,
27 DKG_CHANNEL_IDENT, DKG_LIMIT, MARSHAL_CHANNEL_IDENT, MARSHAL_LIMIT, PEERSETS_TO_TRACK,
28 PENDING_CHANNEL_IDENT, PENDING_LIMIT, RECOVERED_CHANNEL_IDENT, RECOVERED_LIMIT,
29 RESOLVER_CHANNEL_IDENT, RESOLVER_LIMIT, SUBBLOCKS_CHANNEL_IDENT, SUBBLOCKS_LIMIT,
30};
31
32pub use args::Args;
33
34pub async fn run_consensus_stack(
35 context: &commonware_runtime::tokio::Context,
36 config: Args,
37 execution_node: TempoFullNode,
38) -> eyre::Result<()> {
39 let share = config
40 .signing_share
41 .as_ref()
42 .map(|share| {
43 SigningShare::read_from_file(share).wrap_err_with(|| {
44 format!(
45 "failed reading private bls12-381 key share from file `{}`",
46 share.display()
47 )
48 })
49 })
50 .transpose()?
51 .map(|signing_share| signing_share.into_inner());
52
53 let signing_key = config
54 .signing_key()?
55 .ok_or_eyre("required option `consensus.signing-key` not set")?;
56
57 let (mut network, oracle) = instantiate_network(
58 context,
59 signing_key.clone().into_inner(),
60 config.listen_address,
61 config.mailbox_size,
62 config.max_message_size_bytes,
63 config.allow_unregistered_handshakes,
64 )
65 .await
66 .wrap_err("failed to start network")?;
67
68 let message_backlog = config.message_backlog;
69 let pending = network.register(PENDING_CHANNEL_IDENT, PENDING_LIMIT, message_backlog);
70 let recovered = network.register(RECOVERED_CHANNEL_IDENT, RECOVERED_LIMIT, message_backlog);
71 let resolver = network.register(RESOLVER_CHANNEL_IDENT, RESOLVER_LIMIT, message_backlog);
72 let broadcaster = network.register(
73 BROADCASTER_CHANNEL_IDENT,
74 BROADCASTER_LIMIT,
75 message_backlog,
76 );
77 let marshal = network.register(MARSHAL_CHANNEL_IDENT, MARSHAL_LIMIT, message_backlog);
78 let dkg = network.register(DKG_CHANNEL_IDENT, DKG_LIMIT, message_backlog);
79 let boundary_certificates = network.register(
80 BOUNDARY_CERT_CHANNEL_IDENT,
81 BOUNDARY_CERT_LIMIT,
82 message_backlog,
83 );
84 let subblocks = network.register(SUBBLOCKS_CHANNEL_IDENT, SUBBLOCKS_LIMIT, message_backlog);
85
86 let fee_recipient = config
87 .fee_recipient
88 .ok_or_eyre("required option `consensus.fee-recipient` not set")?;
89
90 let consensus_engine = crate::consensus::engine::Builder {
91 context: context.with_label("engine"),
92
93 fee_recipient,
94
95 execution_node: Some(execution_node),
96 blocker: oracle.clone(),
97 peer_manager: oracle.clone(),
98 partition_prefix: "engine".into(),
100 signer: signing_key.into_inner(),
101 share,
102 mailbox_size: config.mailbox_size,
103 deque_size: config.deque_size,
104
105 time_to_propose: config.wait_for_proposal.try_into().wrap_err(
106 "failed converting argument wait-for-proposal to regular duration; \
107 was it negative or chosen too large?",
108 )?,
109 time_to_collect_notarizations: config.wait_for_notarizations.try_into().wrap_err(
110 "failed converting argument wait-for-notarizations to regular \
111 duration; was it negative or chosen too large",
112 )?,
113 time_to_retry_nullify_broadcast: config.wait_to_rebroadcast_nullify.try_into().wrap_err(
114 "failed converting argument wait-to-rebroadcast-nullify to regular \
115 duration; was it negative or chosen too large",
116 )?,
117 time_for_peer_response: config.wait_for_peer_response.try_into().wrap_err(
118 "failed converting argument wait-for-peer-response to regular \
119 duration; was it negative or chosen too large",
120 )?,
121 views_to_track: config.views_to_track,
122 views_until_leader_skip: config.inactive_views_until_leader_skip,
123 new_payload_wait_time: config.time_to_build_proposal.try_into().wrap_err(
124 "failed converting argument time-to-build-proposal to regular \
125 duration; was it negative or chosen too large",
126 )?,
127 time_to_build_subblock: config.time_to_build_subblock.try_into().wrap_err(
128 "failed converting argument time-to-build-subblock to regular \
129 duration; was it negative or chosen too large",
130 )?,
131 subblock_broadcast_interval: config.subblock_broadcast_interval.try_into().wrap_err(
132 "failed converting argument subblock-broadcast-interval to regular \
133 duration; was it negative or chosen too large",
134 )?,
135 }
136 .try_init()
137 .await
138 .wrap_err("failed initializing consensus engine")?;
139
140 let (network, consensus_engine) = (
141 network.start(),
142 consensus_engine.start(
143 pending,
144 recovered,
145 resolver,
146 broadcaster,
147 marshal,
148 dkg,
149 boundary_certificates,
150 subblocks,
151 ),
152 );
153
154 tokio::select! {
155 ret = network => {
156 ret.map_err(eyre::Report::from)
157 .and_then(|()| Err(eyre!("exited unexpectedly")))
158 .wrap_err("network task failed")
159 }
160
161 ret = consensus_engine => {
162 ret.map_err(eyre::Report::from)
163 .and_then(|ret| ret.and_then(|()| Err(eyre!("exited unexpectedly"))))
164 .wrap_err("consensus engine task failed")
165 }
166 }
167}
168
169async fn instantiate_network(
170 context: &commonware_runtime::tokio::Context,
171 signing_key: PrivateKey,
172 listen_addr: SocketAddr,
173 mailbox_size: usize,
174 max_message_size: usize,
175 allow_unregistered_handshakes: bool,
176) -> eyre::Result<(
177 lookup::Network<commonware_runtime::tokio::Context, PrivateKey>,
178 lookup::Oracle<PublicKey>,
179)> {
180 let p2p_namespace = commonware_utils::union_unique(crate::config::NAMESPACE, b"_P2P");
183 let p2p_cfg = lookup::Config {
184 mailbox_size,
185 tracked_peer_sets: PEERSETS_TO_TRACK,
186 attempt_unregistered_handshakes: allow_unregistered_handshakes,
187 ..lookup::Config::local(signing_key, &p2p_namespace, listen_addr, max_message_size)
188 };
189
190 Ok(lookup::Network::new(context.with_label("network"), p2p_cfg))
191}