cat_gateway/settings/
chain_follower.rs

1//! Command line and environment variable settings for the service
2
3use 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
10/// Default chain to follow.
11const DEFAULT_NETWORK: NetworkFromStr = NetworkFromStr::Mainnet;
12
13/// Default number of sync tasks (must be in the range 1 to 256 inclusive.)
14const DEFAULT_SYNC_TASKS: u16 = 16;
15
16/// Maximum number of sync tasks (must be in the range 1 to 256 inclusive.)
17const MAX_SYNC_TASKS: u16 = 256;
18
19/// Default number of slots each sync task will process at one time.
20/// This default is just over one week worth of data where 1 slot == 1 second.
21const DEFAULT_SYNC_MAX_SLOTS: u64 = 700_000;
22/// Minimum the number of slots each sync task will process at one time can be set to.
23/// Note: This is just the setting minimum, a sync task may sync as few as a 1 slot.
24const MIN_SYNC_MAX_SLOTS: u64 = 10_000;
25/// Maximum the number of slots each sync task will process at one time can be set to.
26const MAX_SYNC_MAX_SLOTS: u64 = 100_000_000;
27
28/// Maximum number of DL Connections (must be in the range 1 to 256 inclusive.)
29const MAX_DL_CONNECTIONS: usize = 256;
30
31/// Maximum DL Chunk Size in MB (must be in the range 1 to 256 inclusive.)
32const MAX_DL_CHUNK_SIZE: usize = 256;
33
34/// Maximum DL Chunk Queue Ahead (must be in the range 1 to 256 inclusive.)
35const MAX_DL_CHUNK_QUEUE_AHEAD: usize = 256;
36
37/// Maximum DL Chunk Connect/Data Timeout in seconds (0 = Disabled).
38const MAX_DL_TIMEOUT: u64 = 300;
39
40/// Number of bytes in a Megabyte
41const ONE_MEGABYTE: usize = 1_048_576;
42
43/// A default devnet genesis key.
44const DEFAULT_DEVNET_GENESIS_KEY: &str = "5b33322c3235332c3138362c3230312c3137372c31312c3131372c3133352c3138372c3136372c3138312c3138382c32322c35392c3230362c3130352c3233312c3135302c3231352c33302c37382c3231322c37362c31362c3235322c3138302c37322c3133342c3133372c3234372c3136312c36385d";
45
46/// A default devnet Cardano networking magic number.
47const DEFAULT_DEVNET_MAGIC: u64 = 42;
48
49/// A default devnet Cardano networking identifier.
50const DEFAULT_DEVNET_NETWORK_ID: u64 = 42;
51
52/// A default devnet byron epoch length.
53const DEFAULT_DEVNET_BYRON_EPOCH_LENGTH: u32 = 100_000;
54
55/// A default devnet byron slot length.
56const DEFAULT_DEVNET_BYRON_SLOT_LENGTH: u32 = 1000;
57
58/// A default devnet byron known slot.
59const DEFAULT_DEVNET_BYRON_KNOWN_SLOT: u64 = 0;
60
61/// A default devnet byron known time.
62const DEFAULT_DEVNET_BYRON_KNOWN_TIME: u64 = 1_564_010_416;
63
64/// A default devnet byron known hash.
65const DEFAULT_DEVNET_BYRON_KNOWN_HASH: &str =
66    "8f8602837f7c6f8b8867dd1cbc1842cf51a27eaed2c70ef48325d00f8efb320f";
67
68/// A default devnet shelley epoch length.
69const DEFAULT_DEVNET_SHELLEY_EPOCH_LENGTH: u32 = 100;
70
71/// A default devnet shelley slot length.
72const DEFAULT_DEVNET_SHELLEY_SLOT_LENGTH: u32 = 1;
73
74/// A default devnet shelley known slot.
75const DEFAULT_DEVNET_SHELLEY_KNOWN_SLOT: u64 = 1_598_400;
76
77/// A default devnet shelley known hash.
78const DEFAULT_DEVNET_SHELLEY_KNOWN_HASH: &str =
79    "02b1c561715da9e540411123a6135ee319b02f60b9a11a603d3305556c04329f";
80
81/// A default devnet shelley known time.
82const DEFAULT_DEVNET_SHELLEY_KNOWN_TIME: u64 = 1_595_967_616;
83
84/// Configuration for the chain follower.
85#[derive(Clone)]
86pub(crate) struct EnvVars {
87    /// The Blockchain we sync from.
88    pub(crate) chain: Network,
89
90    /// The maximum number of sync tasks.
91    pub(crate) sync_tasks: u16,
92
93    /// The maximum number of slots a sync task will process at once.
94    pub(crate) sync_chunk_max_slots: u64,
95
96    /// The Mithril Downloader Configuration.
97    pub(crate) dl_config: DlConfig,
98}
99
100#[derive(strum::EnumString, strum::VariantNames, strum::Display)]
101#[strum(ascii_case_insensitive)]
102enum NetworkFromStr {
103    /// Mainnet
104    Mainnet,
105    /// Preprod
106    Preprod,
107    /// Preview
108    Preview,
109    /// Devnet
110    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    /// Create a config for a cassandra cluster, identified by a default namespace.
225    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    /// Log the configuration of this Chain Follower
318    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}