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