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