1use std::{cmp::min, time::Duration};
4
5use cardano_chain_follower::{ChainSyncConfig, Network, turbo_downloader::DlConfig};
6use tracing::info;
7
8use super::str_env_var::StringEnvVar;
9
10const DEFAULT_NETWORK: NetworkFromStr = NetworkFromStr::Mainnet;
12
13const DEFAULT_SYNC_TASKS: u16 = 16;
15
16const MAX_SYNC_TASKS: u16 = 256;
18
19const DEFAULT_SYNC_MAX_SLOTS: u64 = 700_000;
22const MIN_SYNC_MAX_SLOTS: u64 = 10_000;
25const MAX_SYNC_MAX_SLOTS: u64 = 100_000_000;
27
28const MAX_DL_CONNECTIONS: usize = 256;
30
31const MAX_DL_CHUNK_SIZE: usize = 256;
33
34const MAX_DL_CHUNK_QUEUE_AHEAD: usize = 256;
36
37const MAX_DL_TIMEOUT: u64 = 300;
39
40const ONE_MEGABYTE: usize = 1_048_576;
42
43const DEFAULT_DEVNET_GENESIS_KEY: &str = "5b33322c3235332c3138362c3230312c3137372c31312c3131372c3133352c3138372c3136372c3138312c3138382c32322c35392c3230362c3130352c3233312c3135302c3231352c33302c37382c3231322c37362c31362c3235322c3138302c37322c3133342c3133372c3234372c3136312c36385d";
45
46const DEFAULT_DEVNET_MAGIC: u64 = 42;
48
49const DEFAULT_DEVNET_NETWORK_ID: u64 = 42;
51
52const DEFAULT_DEVNET_BYRON_EPOCH_LENGTH: u32 = 100_000;
54
55const DEFAULT_DEVNET_BYRON_SLOT_LENGTH: u32 = 1000;
57
58const DEFAULT_DEVNET_BYRON_KNOWN_SLOT: u64 = 0;
60
61const DEFAULT_DEVNET_BYRON_KNOWN_TIME: u64 = 1_564_010_416;
63
64const DEFAULT_DEVNET_BYRON_KNOWN_HASH: &str =
66 "8f8602837f7c6f8b8867dd1cbc1842cf51a27eaed2c70ef48325d00f8efb320f";
67
68const DEFAULT_DEVNET_SHELLEY_EPOCH_LENGTH: u32 = 100;
70
71const DEFAULT_DEVNET_SHELLEY_SLOT_LENGTH: u32 = 1;
73
74const DEFAULT_DEVNET_SHELLEY_KNOWN_SLOT: u64 = 1_598_400;
76
77const DEFAULT_DEVNET_SHELLEY_KNOWN_HASH: &str =
79 "02b1c561715da9e540411123a6135ee319b02f60b9a11a603d3305556c04329f";
80
81const DEFAULT_DEVNET_SHELLEY_KNOWN_TIME: u64 = 1_595_967_616;
83
84#[derive(Clone)]
86pub(crate) struct EnvVars {
87 pub(crate) cfg: ChainSyncConfig,
89
90 pub(crate) sync_tasks: u16,
92
93 pub(crate) sync_chunk_max_slots: u64,
95}
96
97#[derive(strum::EnumString, strum::VariantNames, strum::Display)]
98#[strum(ascii_case_insensitive)]
99enum NetworkFromStr {
100 Mainnet,
102 Preprod,
104 Preview,
106 Devnet,
108}
109
110impl From<NetworkFromStr> for Network {
111 #[allow(clippy::too_many_lines)]
112 fn from(value: NetworkFromStr) -> Self {
113 match value {
114 NetworkFromStr::Mainnet => Self::Mainnet,
115 NetworkFromStr::Preprod => Self::Preprod,
116 NetworkFromStr::Preview => Self::Preview,
117 NetworkFromStr::Devnet => {
118 let genesis_key = StringEnvVar::new(
119 "CHAIN_FOLLOWER_DEVNET_GENESIS_KEY",
120 DEFAULT_DEVNET_GENESIS_KEY.into(),
121 );
122 let magic = StringEnvVar::new_as_int(
123 "CHAIN_FOLLOWER_DEVNET_MAGIC",
124 DEFAULT_DEVNET_MAGIC,
125 0,
126 u64::MAX,
127 );
128 let network_id = StringEnvVar::new_as_int(
129 "CHAIN_FOLLOWER_DEVNET_NETWORK_ID",
130 DEFAULT_DEVNET_NETWORK_ID,
131 0,
132 u64::MAX,
133 );
134 let byron_epoch_length = StringEnvVar::new_as_int(
135 "CHAIN_FOLLOWER_DEVNET_BYRON_EPOCH_LENGTH",
136 DEFAULT_DEVNET_BYRON_EPOCH_LENGTH,
137 0,
138 u32::MAX,
139 );
140 let byron_slot_length = StringEnvVar::new_as_int(
141 "CHAIN_FOLLOWER_DEVNET_BYRON_SLOT_LENGTH",
142 DEFAULT_DEVNET_BYRON_SLOT_LENGTH,
143 0,
144 u32::MAX,
145 );
146 let byron_known_slot = StringEnvVar::new_as_int(
147 "CHAIN_FOLLOWER_DEVNET_BYRON_KNOWN_SLOT",
148 DEFAULT_DEVNET_BYRON_KNOWN_SLOT,
149 0,
150 u64::MAX,
151 );
152 let byron_known_hash = StringEnvVar::new(
153 "CHAIN_FOLLOWER_DEVNET_BYRON_KNOWN_HASH",
154 DEFAULT_DEVNET_BYRON_KNOWN_HASH.into(),
155 );
156 let byron_known_time = StringEnvVar::new_as_int(
157 "CHAIN_FOLLOWER_DEVNET_BYRON_KNOWN_TIME",
158 DEFAULT_DEVNET_BYRON_KNOWN_TIME,
159 0,
160 u64::MAX,
161 );
162 let shelley_epoch_length = StringEnvVar::new_as_int(
163 "CHAIN_FOLLOWER_DEVNET_SHELLEY_EPOCH_LENGTH",
164 DEFAULT_DEVNET_SHELLEY_EPOCH_LENGTH,
165 0,
166 u32::MAX,
167 );
168 let shelley_slot_length = StringEnvVar::new_as_int(
169 "CHAIN_FOLLOWER_DEVNET_SHELLEY_SLOT_LENGTH",
170 DEFAULT_DEVNET_SHELLEY_SLOT_LENGTH,
171 0,
172 u32::MAX,
173 );
174 let shelley_known_slot = StringEnvVar::new_as_int(
175 "CHAIN_FOLLOWER_DEVNET_SHELLEY_KNOWN_SLOT",
176 DEFAULT_DEVNET_SHELLEY_KNOWN_SLOT,
177 0,
178 u64::MAX,
179 );
180 let shelley_known_hash = StringEnvVar::new(
181 "CHAIN_FOLLOWER_DEVNET_SHELLEY_KNOWN_HASH",
182 DEFAULT_DEVNET_SHELLEY_KNOWN_HASH.into(),
183 );
184 let shelley_known_time = StringEnvVar::new_as_int(
185 "CHAIN_FOLLOWER_DEVNET_SHELLEY_KNOWN_TIME",
186 DEFAULT_DEVNET_SHELLEY_KNOWN_TIME,
187 0,
188 u64::MAX,
189 );
190 Self::Devnet {
191 genesis_key: genesis_key.as_string(),
192 magic,
193 network_id,
194 byron_epoch_length,
195 byron_slot_length,
196 byron_known_slot,
197 byron_known_hash: byron_known_hash.as_string(),
198 byron_known_time,
199 shelley_epoch_length,
200 shelley_slot_length,
201 shelley_known_slot,
202 shelley_known_hash: shelley_known_hash.as_string(),
203 shelley_known_time,
204 }
205 },
206 }
207 }
208}
209
210impl EnvVars {
211 pub(super) fn new() -> Self {
213 let chain: Network =
214 StringEnvVar::new_as_enum("CHAIN_NETWORK", DEFAULT_NETWORK, false).into();
215
216 let sync_tasks: u16 = StringEnvVar::new_as_int(
217 "CHAIN_FOLLOWER_SYNC_TASKS",
218 DEFAULT_SYNC_TASKS,
219 1,
220 MAX_SYNC_TASKS,
221 );
222
223 let sync_slots: u64 = StringEnvVar::new_as_int(
224 "CHAIN_FOLLOWER_SYNC_MAX_SLOTS",
225 DEFAULT_SYNC_MAX_SLOTS,
226 MIN_SYNC_MAX_SLOTS,
227 MAX_SYNC_MAX_SLOTS,
228 );
229
230 let mut cfg = ChainSyncConfig::default_for(chain.clone());
231
232 cfg.mithril_cfg = cfg
233 .mithril_cfg
234 .with_dl_config(Self::new_mithril_dl_config());
235
236 if let Some(relay_address) =
237 StringEnvVar::new_optional("CHAIN_FOLLOWER_RELAY_ADDRESS", false)
238 {
239 cfg = cfg.relay(relay_address.as_string());
240 }
241 if let Some(mithril_aggregator_url) =
242 StringEnvVar::new_optional("CHAIN_FOLLOWER_MITHRIL_AGGREGATOR_URL", false)
243 {
244 cfg.mithril_cfg.aggregator_url = mithril_aggregator_url.as_string();
245 }
246
247 Self {
248 cfg,
249 sync_tasks,
250 sync_chunk_max_slots: sync_slots,
251 }
252 }
253
254 fn new_mithril_dl_config() -> DlConfig {
256 let mut dl_config = DlConfig::new();
257
258 let workers = StringEnvVar::new_as_int(
259 "CHAIN_FOLLOWER_DL_CONNECTIONS",
260 dl_config.workers,
261 1,
262 MAX_DL_CONNECTIONS,
263 );
264 dl_config = dl_config.with_workers(workers);
265
266 let default_dl_chunk_size = min(1, dl_config.chunk_size / ONE_MEGABYTE);
267
268 let chunk_size = StringEnvVar::new_as_int(
269 "CHAIN_FOLLOWER_DL_CHUNK_SIZE",
270 default_dl_chunk_size,
271 1,
272 MAX_DL_CHUNK_SIZE,
273 )
274 .checked_mul(ONE_MEGABYTE)
275 .unwrap_or_else(|| {
276 info!("Too big 'CHAIN_FOLLOWER_DL_CHUNK_SIZE' value, default value {default_dl_chunk_size} is used");
277 default_dl_chunk_size
278 });
279 dl_config = dl_config.with_chunk_size(chunk_size);
280
281 let queue_ahead = StringEnvVar::new_as_int(
282 "CHAIN_FOLLOWER_DL_QUEUE_AHEAD",
283 dl_config.queue_ahead,
284 1,
285 MAX_DL_CHUNK_QUEUE_AHEAD,
286 );
287 dl_config = dl_config.with_queue_ahead(queue_ahead);
288
289 let default_dl_connect_timeout = match dl_config.connection_timeout {
290 Some(timeout) => timeout.as_secs(),
291 None => 0,
292 };
293 let dl_connect_timeout = StringEnvVar::new_as_int(
294 "CHAIN_FOLLOWER_DL_CONNECT_TIMEOUT",
295 default_dl_connect_timeout,
296 0,
297 MAX_DL_TIMEOUT,
298 );
299 if dl_connect_timeout == 0 {
300 dl_config.connection_timeout = None;
301 } else {
302 dl_config = dl_config.with_connection_timeout(Duration::from_secs(dl_connect_timeout));
303 }
304
305 let default_dl_data_timeout = match dl_config.data_read_timeout {
306 Some(timeout) => timeout.as_secs(),
307 None => 0,
308 };
309 let dl_data_timeout = StringEnvVar::new_as_int(
310 "CHAIN_FOLLOWER_DL_DATA_TIMEOUT",
311 default_dl_data_timeout,
312 0,
313 MAX_DL_TIMEOUT,
314 );
315 if dl_connect_timeout == 0 {
316 dl_config.data_read_timeout = None;
317 } else {
318 dl_config = dl_config.with_data_read_timeout(Duration::from_secs(dl_data_timeout));
319 }
320 dl_config
321 }
322
323 pub(crate) fn chain(&self) -> &Network {
325 &self.cfg.chain
326 }
327
328 pub(crate) fn log(&self) {
330 info!(
331 cfg = ?self.cfg,
332 sync_tasks = self.sync_tasks,
333 "Chain Follower Configuration"
334 );
335 }
336}