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, StringEnvVarParams};
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) chain: Network,
89
90 pub(crate) sync_tasks: u16,
92
93 pub(crate) sync_chunk_max_slots: u64,
95
96 pub(crate) dl_config: DlConfig,
98}
99
100#[derive(strum::EnumString, strum::VariantNames, strum::Display)]
101#[strum(ascii_case_insensitive)]
102enum NetworkFromStr {
103 Mainnet,
105 Preprod,
107 Preview,
109 Devnet,
111}
112
113impl From<NetworkFromStr> for Network {
114 #[allow(clippy::too_many_lines)]
115 fn from(value: NetworkFromStr) -> Self {
116 match value {
117 NetworkFromStr::Mainnet => Self::Mainnet,
118 NetworkFromStr::Preprod => Self::Preprod,
119 NetworkFromStr::Preview => Self::Preview,
120 NetworkFromStr::Devnet => {
121 let genesis_key = StringEnvVar::new(
122 "CHAIN_FOLLOWER_DEVNET_GENESIS_KEY",
123 StringEnvVarParams::Plain(
124 "DEFAULT_DEVNET_GENESIS_KEY".into(),
125 DEFAULT_DEVNET_GENESIS_KEY.to_string().into(),
126 ),
127 );
128 let magic = StringEnvVar::new_as_int(
129 "CHAIN_FOLLOWER_DEVNET_MAGIC",
130 DEFAULT_DEVNET_MAGIC,
131 0,
132 u64::MAX,
133 );
134 let network_id = StringEnvVar::new_as_int(
135 "CHAIN_FOLLOWER_DEVNET_NETWORK_ID",
136 DEFAULT_DEVNET_NETWORK_ID,
137 0,
138 u64::MAX,
139 );
140 let byron_epoch_length = StringEnvVar::new_as_int(
141 "CHAIN_FOLLOWER_DEVNET_BYRON_EPOCH_LENGTH",
142 DEFAULT_DEVNET_BYRON_EPOCH_LENGTH,
143 0,
144 u32::MAX,
145 );
146 let byron_slot_length = StringEnvVar::new_as_int(
147 "CHAIN_FOLLOWER_DEVNET_BYRON_SLOT_LENGTH",
148 DEFAULT_DEVNET_BYRON_SLOT_LENGTH,
149 0,
150 u32::MAX,
151 );
152 let byron_known_slot = StringEnvVar::new_as_int(
153 "CHAIN_FOLLOWER_DEVNET_BYRON_KNOWN_SLOT",
154 DEFAULT_DEVNET_BYRON_KNOWN_SLOT,
155 0,
156 u64::MAX,
157 );
158 let byron_known_hash = StringEnvVar::new(
159 "CHAIN_FOLLOWER_DEVNET_BYRON_KNOWN_HASH",
160 StringEnvVarParams::Plain(
161 "DEFAULT_DEVNET_BYRON_KNOWN_HASH".into(),
162 DEFAULT_DEVNET_BYRON_KNOWN_HASH.to_string().into(),
163 ),
164 );
165 let byron_known_time = StringEnvVar::new_as_int(
166 "CHAIN_FOLLOWER_DEVNET_BYRON_KNOWN_TIME",
167 DEFAULT_DEVNET_BYRON_KNOWN_TIME,
168 0,
169 u64::MAX,
170 );
171 let shelley_epoch_length = StringEnvVar::new_as_int(
172 "CHAIN_FOLLOWER_DEVNET_SHELLEY_EPOCH_LENGTH",
173 DEFAULT_DEVNET_SHELLEY_EPOCH_LENGTH,
174 0,
175 u32::MAX,
176 );
177 let shelley_slot_length = StringEnvVar::new_as_int(
178 "CHAIN_FOLLOWER_DEVNET_SHELLEY_SLOT_LENGTH",
179 DEFAULT_DEVNET_SHELLEY_SLOT_LENGTH,
180 0,
181 u32::MAX,
182 );
183 let shelley_known_slot = StringEnvVar::new_as_int(
184 "CHAIN_FOLLOWER_DEVNET_SHELLEY_KNOWN_SLOT",
185 DEFAULT_DEVNET_SHELLEY_KNOWN_SLOT,
186 0,
187 u64::MAX,
188 );
189 let shelley_known_hash = StringEnvVar::new(
190 "CHAIN_FOLLOWER_DEVNET_SHELLEY_KNOWN_HASH",
191 StringEnvVarParams::Plain(
192 "DEFAULT_DEVNET_SHELLEY_KNOWN_HASH".into(),
193 DEFAULT_DEVNET_SHELLEY_KNOWN_HASH.to_string().into(),
194 ),
195 );
196 let shelley_known_time = StringEnvVar::new_as_int(
197 "CHAIN_FOLLOWER_DEVNET_SHELLEY_KNOWN_TIME",
198 DEFAULT_DEVNET_SHELLEY_KNOWN_TIME,
199 0,
200 u64::MAX,
201 );
202
203 Self::Devnet {
204 genesis_key: genesis_key.as_string(),
205 magic,
206 network_id,
207 byron_epoch_length,
208 byron_slot_length,
209 byron_known_slot,
210 byron_known_hash: byron_known_hash.as_string(),
211 byron_known_time,
212 shelley_epoch_length,
213 shelley_slot_length,
214 shelley_known_slot,
215 shelley_known_hash: shelley_known_hash.as_string(),
216 shelley_known_time,
217 }
218 },
219 }
220 }
221}
222
223impl EnvVars {
224 pub(super) fn new() -> Self {
226 let chain: Network =
227 StringEnvVar::new_as_enum("CHAIN_NETWORK", DEFAULT_NETWORK, false).into();
228
229 let sync_tasks: u16 = StringEnvVar::new_as_int(
230 "CHAIN_FOLLOWER_SYNC_TASKS",
231 DEFAULT_SYNC_TASKS,
232 1,
233 MAX_SYNC_TASKS,
234 );
235
236 let sync_slots: u64 = StringEnvVar::new_as_int(
237 "CHAIN_FOLLOWER_SYNC_MAX_SLOTS",
238 DEFAULT_SYNC_MAX_SLOTS,
239 MIN_SYNC_MAX_SLOTS,
240 MAX_SYNC_MAX_SLOTS,
241 );
242
243 let cfg = ChainSyncConfig::default_for(chain.clone());
244 let mut dl_config = cfg.mithril_cfg.dl_config.clone().unwrap_or_default();
245
246 let workers = StringEnvVar::new_as_int(
247 "CHAIN_FOLLOWER_DL_CONNECTIONS",
248 dl_config.workers,
249 1,
250 MAX_DL_CONNECTIONS,
251 );
252 dl_config = dl_config.with_workers(workers);
253
254 let default_dl_chunk_size = min(1, dl_config.chunk_size / ONE_MEGABYTE);
255
256 let chunk_size = StringEnvVar::new_as_int(
257 "CHAIN_FOLLOWER_DL_CHUNK_SIZE",
258 default_dl_chunk_size,
259 1,
260 MAX_DL_CHUNK_SIZE,
261 )
262 .checked_mul(ONE_MEGABYTE)
263 .unwrap_or_else(|| {
264 info!("Too big 'CHAIN_FOLLOWER_DL_CHUNK_SIZE' value, default value {default_dl_chunk_size} is used");
265 default_dl_chunk_size
266 });
267 dl_config = dl_config.with_chunk_size(chunk_size);
268
269 let queue_ahead = StringEnvVar::new_as_int(
270 "CHAIN_FOLLOWER_DL_QUEUE_AHEAD",
271 dl_config.queue_ahead,
272 1,
273 MAX_DL_CHUNK_QUEUE_AHEAD,
274 );
275 dl_config = dl_config.with_queue_ahead(queue_ahead);
276
277 let default_dl_connect_timeout = match dl_config.connection_timeout {
278 Some(timeout) => timeout.as_secs(),
279 None => 0,
280 };
281 let dl_connect_timeout = StringEnvVar::new_as_int(
282 "CHAIN_FOLLOWER_DL_CONNECT_TIMEOUT",
283 default_dl_connect_timeout,
284 0,
285 MAX_DL_TIMEOUT,
286 );
287 if dl_connect_timeout == 0 {
288 dl_config.connection_timeout = None;
289 } else {
290 dl_config = dl_config.with_connection_timeout(Duration::from_secs(dl_connect_timeout));
291 }
292
293 let default_dl_data_timeout = match dl_config.data_read_timeout {
294 Some(timeout) => timeout.as_secs(),
295 None => 0,
296 };
297 let dl_data_timeout = StringEnvVar::new_as_int(
298 "CHAIN_FOLLOWER_DL_DATA_TIMEOUT",
299 default_dl_data_timeout,
300 0,
301 MAX_DL_TIMEOUT,
302 );
303 if dl_connect_timeout == 0 {
304 dl_config.data_read_timeout = None;
305 } else {
306 dl_config = dl_config.with_data_read_timeout(Duration::from_secs(dl_data_timeout));
307 }
308
309 Self {
310 chain,
311 sync_tasks,
312 sync_chunk_max_slots: sync_slots,
313 dl_config,
314 }
315 }
316
317 pub(crate) fn log(&self) {
319 info!(
320 chain = self.chain.to_string(),
321 sync_tasks = self.sync_tasks,
322 dl_config = ?self.dl_config,
323 "Chain Follower Configuration"
324 );
325 }
326}