1use anyhow::Context;
2use config::{ConfigError, Map, Source, Value};
3#[cfg(feature = "future_dmq")]
4use mithril_dmq::DmqNetwork;
5use mithril_doc::{Documenter, DocumenterDefault, StructDoc};
6use serde::{Deserialize, Serialize};
7use std::{path::PathBuf, sync::Arc};
8
9use mithril_cardano_node_chain::chain_observer::ChainObserver;
10use mithril_cli_helper::register_config_value;
11use mithril_common::{
12 CardanoNetwork, StdResult,
13 entities::{BlockNumber, PartyId},
14};
15use mithril_era::{
16 EraReaderAdapter,
17 adapters::{EraReaderAdapterBuilder, EraReaderAdapterType},
18};
19
20#[derive(Debug, Clone, Serialize, Deserialize)]
21pub struct SignaturePublisherConfig {
22 pub retry_attempts: u8,
24
25 pub retry_delay_ms: u64,
27
28 pub delayer_delay_ms: u64,
30
31 pub skip_delayer: bool,
37}
38
39#[derive(Debug, Clone, Serialize, Deserialize, Documenter)]
41pub struct Configuration {
42 #[example = "`cardano-cli`"]
44 pub cardano_cli_path: PathBuf,
45
46 #[example = "`/ipc/node.socket`"]
48 pub cardano_node_socket_path: PathBuf,
49
50 #[example = "`/ipc/dmq.socket`"]
52 pub dmq_node_socket_path: Option<PathBuf>,
53
54 #[example = "`mainnet` or `preprod` or `devnet`"]
56 pub network: String,
57
58 #[example = "`1097911063` or `42`"]
61 pub network_magic: Option<u64>,
62
63 #[example = "`1097911063` or `42`"]
67 pub dmq_network_magic: Option<u64>,
68
69 pub network_security_parameter: BlockNumber,
72
73 pub preload_security_parameter: BlockNumber,
76
77 #[example = "`https://aggregator.pre-release-preview.api.mithril.network/aggregator`"]
79 pub aggregator_endpoint: String,
80
81 pub relay_endpoint: Option<String>,
83
84 #[example = "`pool1pxaqe80sqpde7902er5kf6v0c7y0sv6d5g676766v2h829fvs3x`"]
88 pub party_id: Option<PartyId>,
89
90 #[example = "`60000`"]
92 pub run_interval: u64,
93
94 pub db_directory: PathBuf,
96
97 #[example = "`./mithril-signer/stores`"]
99 pub data_stores_directory: PathBuf,
100
101 pub store_retention_limit: Option<usize>,
103
104 pub kes_secret_key_path: Option<PathBuf>,
106
107 pub operational_certificate_path: Option<PathBuf>,
109
110 pub disable_digests_cache: bool,
112
113 pub reset_digests_cache: bool,
117
118 pub era_reader_adapter_type: EraReaderAdapterType,
120
121 pub era_reader_adapter_params: Option<String>,
123
124 pub enable_metrics_server: bool,
126
127 pub metrics_server_ip: String,
129
130 pub metrics_server_port: u16,
132
133 pub allow_unparsable_block: bool,
137
138 pub enable_transaction_pruning: bool,
142
143 pub transactions_import_block_chunk_size: BlockNumber,
147
148 pub cardano_transactions_block_streamer_max_roll_forwards_per_poll: usize,
150
151 pub preloading_refresh_interval_in_seconds: u64,
153
154 #[example = "`{ retry_attempts: 3, retry_delay_ms: 2000, delayer_delay_ms: 10000, skip_delayer: false }`"]
156 pub signature_publisher_config: SignaturePublisherConfig,
157}
158
159impl Configuration {
160 #[doc(hidden)]
162 pub fn new_sample<P: Into<PartyId>>(party_id: P) -> Self {
163 let party_id: PartyId = party_id.into();
164 let signer_temp_dir =
165 mithril_common::test::crypto_helper::setup_temp_directory_for_signer(&party_id, false);
166 Self {
167 aggregator_endpoint: "http://0.0.0.0:8000".to_string(),
168 relay_endpoint: None,
169 cardano_cli_path: PathBuf::new(),
170 cardano_node_socket_path: PathBuf::new(),
171 dmq_node_socket_path: None,
172 db_directory: PathBuf::new(),
173 network: "devnet".to_string(),
174 network_magic: Some(42),
175 dmq_network_magic: Some(3141592),
176 network_security_parameter: BlockNumber(2160),
177 preload_security_parameter: BlockNumber(30),
178 party_id: Some(party_id),
179 run_interval: 5000,
180 data_stores_directory: PathBuf::new(),
181 store_retention_limit: None,
182 kes_secret_key_path: signer_temp_dir.as_ref().map(|dir| dir.join("kes.sk")),
183 operational_certificate_path: signer_temp_dir
184 .as_ref()
185 .map(|dir| dir.join("opcert.cert")),
186 disable_digests_cache: false,
187 reset_digests_cache: false,
188 era_reader_adapter_type: EraReaderAdapterType::Bootstrap,
189 era_reader_adapter_params: None,
190 enable_metrics_server: true,
191 metrics_server_ip: "0.0.0.0".to_string(),
192 metrics_server_port: 9090,
193 allow_unparsable_block: false,
194 enable_transaction_pruning: false,
195 transactions_import_block_chunk_size: BlockNumber(1000),
196 cardano_transactions_block_streamer_max_roll_forwards_per_poll: 1000,
197 preloading_refresh_interval_in_seconds: 60,
198 signature_publisher_config: SignaturePublisherConfig {
199 retry_attempts: 1,
200 retry_delay_ms: 1,
201 delayer_delay_ms: 1,
202 skip_delayer: false,
203 },
204 }
205 }
206
207 pub fn get_network(&self) -> StdResult<CardanoNetwork> {
209 CardanoNetwork::from_code(self.network.clone(), self.network_magic).with_context(|| {
210 format!(
211 "Could not read Network '{}' from configuration.",
212 &self.network
213 )
214 })
215 }
216
217 #[cfg(feature = "future_dmq")]
219 pub fn get_dmq_network(&self) -> StdResult<DmqNetwork> {
220 DmqNetwork::from_code(self.network.clone(), self.dmq_network_magic).with_context(|| {
221 format!(
222 "Could not read DMQ Network '{}' from configuration.",
223 &self.network
224 )
225 })
226 }
227
228 pub fn get_sqlite_file(&self, sqlite_file_name: &str) -> StdResult<PathBuf> {
231 let store_dir = &self.data_stores_directory;
232
233 if !store_dir.exists() {
234 std::fs::create_dir_all(store_dir).with_context(|| {
235 format!(
236 "Could not create directory '{}' for Sqlite3 file.",
237 store_dir.display()
238 )
239 })?;
240 }
241
242 Ok(self.data_stores_directory.join(sqlite_file_name))
243 }
244
245 pub fn build_era_reader_adapter(
247 &self,
248 chain_observer: Arc<dyn ChainObserver>,
249 ) -> StdResult<Arc<dyn EraReaderAdapter>> {
250 EraReaderAdapterBuilder::new(
251 &self.era_reader_adapter_type,
252 &self.era_reader_adapter_params,
253 )
254 .build(chain_observer)
255 .with_context(|| {
256 format!(
257 "Configuration: can not create era reader for adapter '{}'.",
258 &self.era_reader_adapter_type
259 )
260 })
261 }
262}
263
264#[derive(Debug, Clone, DocumenterDefault)]
266pub struct DefaultConfiguration {
267 pub era_reader_adapter_type: String,
269
270 pub metrics_server_ip: String,
272
273 pub metrics_server_port: u16,
275
276 pub network_security_parameter: u64,
278
279 pub enable_transaction_pruning: bool,
281
282 pub preload_security_parameter: u64,
284
285 pub transactions_import_block_chunk_size: u64,
287
288 pub cardano_transactions_block_streamer_max_roll_forwards_per_poll: u32,
290}
291
292impl DefaultConfiguration {
293 fn namespace() -> String {
294 "default configuration".to_string()
295 }
296}
297
298impl Default for DefaultConfiguration {
299 fn default() -> Self {
300 Self {
301 era_reader_adapter_type: "bootstrap".to_string(),
302 metrics_server_ip: "0.0.0.0".to_string(),
303 metrics_server_port: 9090,
304 network_security_parameter: 2160, preload_security_parameter: 1000,
306 enable_transaction_pruning: true,
307 transactions_import_block_chunk_size: 1500,
308 cardano_transactions_block_streamer_max_roll_forwards_per_poll: 10000,
309 }
310 }
311}
312
313impl Source for DefaultConfiguration {
314 fn clone_into_box(&self) -> Box<dyn Source + Send + Sync> {
315 Box::new(self.clone())
316 }
317
318 fn collect(&self) -> Result<Map<String, Value>, ConfigError> {
319 let mut result = Map::new();
320 let namespace = DefaultConfiguration::namespace();
321 let myself = self.clone();
322
323 register_config_value!(result, &namespace, myself.era_reader_adapter_type);
324 register_config_value!(result, &namespace, myself.metrics_server_ip);
325 register_config_value!(result, &namespace, myself.metrics_server_port);
326 register_config_value!(result, &namespace, myself.network_security_parameter);
327 register_config_value!(result, &namespace, myself.preload_security_parameter);
328 register_config_value!(result, &namespace, myself.enable_transaction_pruning);
329 register_config_value!(
330 result,
331 &namespace,
332 myself.transactions_import_block_chunk_size
333 );
334 register_config_value!(
335 result,
336 &namespace,
337 myself.cardano_transactions_block_streamer_max_roll_forwards_per_poll
338 );
339
340 Ok(result)
341 }
342}