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::{turbo_downloader::DlConfig, ChainSyncConfig, Network};
6use tracing::info;
7
8use super::str_env_var::StringEnvVar;
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/// Configuration for the chain follower.
44#[derive(Clone)]
45pub(crate) struct EnvVars {
46    /// The Blockchain we sync from.
47    pub(crate) chain: Network,
48
49    /// The maximum number of sync tasks.
50    pub(crate) sync_tasks: u16,
51
52    /// The maximum number of slots a sync task will process at once.
53    pub(crate) sync_chunk_max_slots: u64,
54
55    /// The Mithril Downloader Configuration.
56    pub(crate) dl_config: DlConfig,
57}
58
59#[derive(strum::EnumString, strum::VariantNames, strum::Display)]
60#[strum(ascii_case_insensitive)]
61enum NetworkFromStr {
62    /// Mainnet
63    Mainnet,
64    /// Preprod
65    Preprod,
66    /// Preview
67    Preview,
68    /// Devnet
69    Devnet,
70}
71
72impl From<NetworkFromStr> for Network {
73    fn from(value: NetworkFromStr) -> Self {
74        match value {
75            NetworkFromStr::Mainnet => Self::Mainnet,
76            NetworkFromStr::Preprod => Self::Preprod,
77            NetworkFromStr::Preview => Self::Preview,
78            NetworkFromStr::Devnet => Self::Devnet {
79                genesis_key: "5b33322c3235332c3138362c3230312c3137372c31312c3131372c3133352c3138372c3136372c3138312c3138382c32322c35392c3230362c3130352c3233312c3135302c3231352c33302c37382c3231322c37362c31362c3235322c3138302c37322c3133342c3133372c3234372c3136312c36385d",
80                magic: 42,
81                network_id: 0,
82                byron_epoch_length: 100_000,
83                byron_slot_length: 1000,
84                byron_known_slot: 0,
85                byron_known_time: 1_564_010_416,
86                byron_known_hash: "8f8602837f7c6f8b8867dd1cbc1842cf51a27eaed2c70ef48325d00f8efb320f",
87                shelley_epoch_length: 100,
88                shelley_slot_length: 1,
89                shelley_known_slot: 1_598_400,
90                shelley_known_hash: "02b1c561715da9e540411123a6135ee319b02f60b9a11a603d3305556c04329f",
91                shelley_known_time: 1_595_967_616,
92            },
93        }
94    }
95}
96
97impl EnvVars {
98    /// Create a config for a cassandra cluster, identified by a default namespace.
99    pub(super) fn new() -> Self {
100        let chain = StringEnvVar::new_as_enum("CHAIN_NETWORK", DEFAULT_NETWORK, false).into();
101
102        let sync_tasks: u16 = StringEnvVar::new_as_int(
103            "CHAIN_FOLLOWER_SYNC_TASKS",
104            DEFAULT_SYNC_TASKS,
105            1,
106            MAX_SYNC_TASKS,
107        );
108
109        let sync_slots: u64 = StringEnvVar::new_as_int(
110            "CHAIN_FOLLOWER_SYNC_MAX_SLOTS",
111            DEFAULT_SYNC_MAX_SLOTS,
112            MIN_SYNC_MAX_SLOTS,
113            MAX_SYNC_MAX_SLOTS,
114        );
115
116        let cfg = ChainSyncConfig::default_for(chain);
117        let mut dl_config = cfg.mithril_cfg.dl_config.clone().unwrap_or_default();
118
119        let workers = StringEnvVar::new_as_int(
120            "CHAIN_FOLLOWER_DL_CONNECTIONS",
121            dl_config.workers,
122            1,
123            MAX_DL_CONNECTIONS,
124        );
125        dl_config = dl_config.with_workers(workers);
126
127        let default_dl_chunk_size = min(1, dl_config.chunk_size / ONE_MEGABYTE);
128
129        let chunk_size = StringEnvVar::new_as_int(
130            "CHAIN_FOLLOWER_DL_CHUNK_SIZE",
131            default_dl_chunk_size,
132            1,
133            MAX_DL_CHUNK_SIZE,
134        )
135        .checked_mul(ONE_MEGABYTE)
136        .unwrap_or_else(|| {
137            info!("Too big 'CHAIN_FOLLOWER_DL_CHUNK_SIZE' value, default value {default_dl_chunk_size} is used");
138            default_dl_chunk_size
139        });
140        dl_config = dl_config.with_chunk_size(chunk_size);
141
142        let queue_ahead = StringEnvVar::new_as_int(
143            "CHAIN_FOLLOWER_DL_QUEUE_AHEAD",
144            dl_config.queue_ahead,
145            1,
146            MAX_DL_CHUNK_QUEUE_AHEAD,
147        );
148        dl_config = dl_config.with_queue_ahead(queue_ahead);
149
150        let default_dl_connect_timeout = match dl_config.connection_timeout {
151            Some(timeout) => timeout.as_secs(),
152            None => 0,
153        };
154        let dl_connect_timeout = StringEnvVar::new_as_int(
155            "CHAIN_FOLLOWER_DL_CONNECT_TIMEOUT",
156            default_dl_connect_timeout,
157            0,
158            MAX_DL_TIMEOUT,
159        );
160        if dl_connect_timeout == 0 {
161            dl_config.connection_timeout = None;
162        } else {
163            dl_config = dl_config.with_connection_timeout(Duration::from_secs(dl_connect_timeout));
164        }
165
166        let default_dl_data_timeout = match dl_config.data_read_timeout {
167            Some(timeout) => timeout.as_secs(),
168            None => 0,
169        };
170        let dl_data_timeout = StringEnvVar::new_as_int(
171            "CHAIN_FOLLOWER_DL_DATA_TIMEOUT",
172            default_dl_data_timeout,
173            0,
174            MAX_DL_TIMEOUT,
175        );
176        if dl_connect_timeout == 0 {
177            dl_config.data_read_timeout = None;
178        } else {
179            dl_config = dl_config.with_data_read_timeout(Duration::from_secs(dl_data_timeout));
180        }
181
182        Self {
183            chain,
184            sync_tasks,
185            sync_chunk_max_slots: sync_slots,
186            dl_config,
187        }
188    }
189
190    /// Log the configuration of this Chain Follower
191    pub(crate) fn log(&self) {
192        info!(
193            chain = self.chain.to_string(),
194            sync_tasks = self.sync_tasks,
195            dl_config = ?self.dl_config,
196            "Chain Follower Configuration"
197        );
198    }
199}