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 crypto_helper::tests_setup,
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
31#[derive(Debug, Clone, Serialize, Deserialize, Documenter)]
33pub struct Configuration {
34 #[example = "`cardano-cli`"]
36 pub cardano_cli_path: PathBuf,
37
38 #[example = "`/ipc/node.socket`"]
40 pub cardano_node_socket_path: PathBuf,
41
42 #[example = "`/ipc/dmq.socket`"]
44 pub dmq_node_socket_path: Option<PathBuf>,
45
46 #[example = "`testnet` or `mainnet` or `devnet`"]
48 pub network: String,
49
50 #[example = "`1097911063` or `42`"]
53 pub network_magic: Option<u64>,
54
55 pub network_security_parameter: BlockNumber,
58
59 pub preload_security_parameter: BlockNumber,
62
63 #[example = "`https://aggregator.pre-release-preview.api.mithril.network/aggregator`"]
65 pub aggregator_endpoint: String,
66
67 pub relay_endpoint: Option<String>,
69
70 #[example = "`pool1pxaqe80sqpde7902er5kf6v0c7y0sv6d5g676766v2h829fvs3x`"]
74 pub party_id: Option<PartyId>,
75
76 #[example = "`60000`"]
78 pub run_interval: u64,
79
80 pub db_directory: PathBuf,
82
83 #[example = "`./mithril-signer/stores`"]
85 pub data_stores_directory: PathBuf,
86
87 pub store_retention_limit: Option<usize>,
89
90 pub kes_secret_key_path: Option<PathBuf>,
92
93 pub operational_certificate_path: Option<PathBuf>,
95
96 pub disable_digests_cache: bool,
98
99 pub reset_digests_cache: bool,
103
104 pub era_reader_adapter_type: EraReaderAdapterType,
106
107 pub era_reader_adapter_params: Option<String>,
109
110 pub enable_metrics_server: bool,
112
113 pub metrics_server_ip: String,
115
116 pub metrics_server_port: u16,
118
119 pub allow_unparsable_block: bool,
123
124 pub enable_transaction_pruning: bool,
128
129 pub transactions_import_block_chunk_size: BlockNumber,
133
134 pub cardano_transactions_block_streamer_max_roll_forwards_per_poll: usize,
136
137 pub preloading_refresh_interval_in_seconds: u64,
139
140 #[example = "`{ retry_attempts: 3, retry_delay_ms: 2000, delayer_delay_ms: 10000 }`"]
142 pub signature_publisher_config: SignaturePublisherConfig,
143}
144
145impl Configuration {
146 #[doc(hidden)]
148 pub fn new_sample<P: Into<PartyId>>(party_id: P) -> Self {
149 let party_id: PartyId = party_id.into();
150 let signer_temp_dir = tests_setup::setup_temp_directory_for_signer(&party_id, false);
151 Self {
152 aggregator_endpoint: "http://0.0.0.0:8000".to_string(),
153 relay_endpoint: None,
154 cardano_cli_path: PathBuf::new(),
155 cardano_node_socket_path: PathBuf::new(),
156 dmq_node_socket_path: None,
157 db_directory: PathBuf::new(),
158 network: "devnet".to_string(),
159 network_magic: Some(42),
160 network_security_parameter: BlockNumber(2160),
161 preload_security_parameter: BlockNumber(30),
162 party_id: Some(party_id),
163 run_interval: 5000,
164 data_stores_directory: PathBuf::new(),
165 store_retention_limit: None,
166 kes_secret_key_path: signer_temp_dir.as_ref().map(|dir| dir.join("kes.sk")),
167 operational_certificate_path: signer_temp_dir
168 .as_ref()
169 .map(|dir| dir.join("opcert.cert")),
170 disable_digests_cache: false,
171 reset_digests_cache: false,
172 era_reader_adapter_type: EraReaderAdapterType::Bootstrap,
173 era_reader_adapter_params: None,
174 enable_metrics_server: true,
175 metrics_server_ip: "0.0.0.0".to_string(),
176 metrics_server_port: 9090,
177 allow_unparsable_block: false,
178 enable_transaction_pruning: false,
179 transactions_import_block_chunk_size: BlockNumber(1000),
180 cardano_transactions_block_streamer_max_roll_forwards_per_poll: 1000,
181 preloading_refresh_interval_in_seconds: 60,
182 signature_publisher_config: SignaturePublisherConfig {
183 retry_attempts: 1,
184 retry_delay_ms: 1,
185 delayer_delay_ms: 1,
186 },
187 }
188 }
189
190 pub fn get_network(&self) -> StdResult<CardanoNetwork> {
192 CardanoNetwork::from_code(self.network.clone(), self.network_magic).with_context(|| {
193 format!(
194 "Could not read Network '{}' from configuration.",
195 &self.network
196 )
197 })
198 }
199
200 pub fn get_sqlite_file(&self, sqlite_file_name: &str) -> StdResult<PathBuf> {
203 let store_dir = &self.data_stores_directory;
204
205 if !store_dir.exists() {
206 std::fs::create_dir_all(store_dir).with_context(|| {
207 format!(
208 "Could not create directory '{}' for Sqlite3 file.",
209 store_dir.display()
210 )
211 })?;
212 }
213
214 Ok(self.data_stores_directory.join(sqlite_file_name))
215 }
216
217 pub fn build_era_reader_adapter(
219 &self,
220 chain_observer: Arc<dyn ChainObserver>,
221 ) -> StdResult<Arc<dyn EraReaderAdapter>> {
222 EraReaderAdapterBuilder::new(
223 &self.era_reader_adapter_type,
224 &self.era_reader_adapter_params,
225 )
226 .build(chain_observer)
227 .with_context(|| {
228 format!(
229 "Configuration: can not create era reader for adapter '{}'.",
230 &self.era_reader_adapter_type
231 )
232 })
233 }
234}
235
236#[derive(Debug, Clone, DocumenterDefault)]
238pub struct DefaultConfiguration {
239 pub era_reader_adapter_type: String,
241
242 pub metrics_server_ip: String,
244
245 pub metrics_server_port: u16,
247
248 pub network_security_parameter: u64,
250
251 pub enable_transaction_pruning: bool,
253
254 pub preload_security_parameter: u64,
256
257 pub transactions_import_block_chunk_size: u64,
259
260 pub cardano_transactions_block_streamer_max_roll_forwards_per_poll: u32,
262}
263
264impl DefaultConfiguration {
265 fn namespace() -> String {
266 "default configuration".to_string()
267 }
268}
269
270impl Default for DefaultConfiguration {
271 fn default() -> Self {
272 Self {
273 era_reader_adapter_type: "bootstrap".to_string(),
274 metrics_server_ip: "0.0.0.0".to_string(),
275 metrics_server_port: 9090,
276 network_security_parameter: 2160, preload_security_parameter: 1000,
278 enable_transaction_pruning: true,
279 transactions_import_block_chunk_size: 1500,
280 cardano_transactions_block_streamer_max_roll_forwards_per_poll: 10000,
281 }
282 }
283}
284
285impl Source for DefaultConfiguration {
286 fn clone_into_box(&self) -> Box<dyn Source + Send + Sync> {
287 Box::new(self.clone())
288 }
289
290 fn collect(&self) -> Result<Map<String, Value>, ConfigError> {
291 let mut result = Map::new();
292 let namespace = DefaultConfiguration::namespace();
293 let myself = self.clone();
294
295 register_config_value!(result, &namespace, myself.era_reader_adapter_type);
296 register_config_value!(result, &namespace, myself.metrics_server_ip);
297 register_config_value!(result, &namespace, myself.metrics_server_port);
298 register_config_value!(result, &namespace, myself.network_security_parameter);
299 register_config_value!(result, &namespace, myself.preload_security_parameter);
300 register_config_value!(result, &namespace, myself.enable_transaction_pruning);
301 register_config_value!(
302 result,
303 &namespace,
304 myself.transactions_import_block_chunk_size
305 );
306 register_config_value!(
307 result,
308 &namespace,
309 myself.cardano_transactions_block_streamer_max_roll_forwards_per_poll
310 );
311
312 Ok(result)
313 }
314}