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_cli_helper::register_config_value;
8use mithril_common::{
9 chain_observer::ChainObserver,
10 crypto_helper::tests_setup,
11 entities::{BlockNumber, PartyId},
12 era::{
13 adapters::{EraReaderAdapterBuilder, EraReaderAdapterType},
14 EraReaderAdapter,
15 },
16 CardanoNetwork, StdResult,
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 = "`/tmp/cardano.sock`"]
41 pub cardano_node_socket_path: PathBuf,
42
43 #[example = "`testnet` or `mainnet` or `devnet`"]
45 pub network: String,
46
47 #[example = "`1097911063` or `42`"]
50 pub network_magic: Option<u64>,
51
52 pub network_security_parameter: BlockNumber,
55
56 pub preload_security_parameter: BlockNumber,
59
60 #[example = "`https://aggregator.pre-release-preview.api.mithril.network/aggregator`"]
62 pub aggregator_endpoint: String,
63
64 pub relay_endpoint: Option<String>,
66
67 #[example = "`pool1pxaqe80sqpde7902er5kf6v0c7y0sv6d5g676766v2h829fvs3x`"]
71 pub party_id: Option<PartyId>,
72
73 #[example = "`60000`"]
75 pub run_interval: u64,
76
77 pub db_directory: PathBuf,
79
80 #[example = "`./mithril-signer/stores`"]
82 pub data_stores_directory: PathBuf,
83
84 pub store_retention_limit: Option<usize>,
86
87 pub kes_secret_key_path: Option<PathBuf>,
89
90 pub operational_certificate_path: Option<PathBuf>,
92
93 pub disable_digests_cache: bool,
95
96 pub reset_digests_cache: bool,
100
101 pub era_reader_adapter_type: EraReaderAdapterType,
103
104 pub era_reader_adapter_params: Option<String>,
106
107 pub enable_metrics_server: bool,
109
110 pub metrics_server_ip: String,
112
113 pub metrics_server_port: u16,
115
116 pub allow_unparsable_block: bool,
120
121 pub enable_transaction_pruning: bool,
125
126 pub transactions_import_block_chunk_size: BlockNumber,
130
131 pub cardano_transactions_block_streamer_max_roll_forwards_per_poll: usize,
133
134 pub preloading_refresh_interval_in_seconds: u64,
136
137 #[example = "`{ retry_attempts: 3, retry_delay_ms: 2000, delayer_delay_ms: 10000 }`"]
139 pub signature_publisher_config: SignaturePublisherConfig,
140}
141
142impl Configuration {
143 #[doc(hidden)]
145 pub fn new_sample<P: Into<PartyId>>(party_id: P) -> Self {
146 let party_id: PartyId = party_id.into();
147 let signer_temp_dir = tests_setup::setup_temp_directory_for_signer(&party_id, false);
148 Self {
149 aggregator_endpoint: "http://0.0.0.0:8000".to_string(),
150 relay_endpoint: None,
151 cardano_cli_path: PathBuf::new(),
152 cardano_node_socket_path: PathBuf::new(),
153 db_directory: PathBuf::new(),
154 network: "devnet".to_string(),
155 network_magic: Some(42),
156 network_security_parameter: BlockNumber(2160),
157 preload_security_parameter: BlockNumber(30),
158 party_id: Some(party_id),
159 run_interval: 5000,
160 data_stores_directory: PathBuf::new(),
161 store_retention_limit: None,
162 kes_secret_key_path: signer_temp_dir.as_ref().map(|dir| dir.join("kes.sk")),
163 operational_certificate_path: signer_temp_dir
164 .as_ref()
165 .map(|dir| dir.join("opcert.cert")),
166 disable_digests_cache: false,
167 reset_digests_cache: false,
168 era_reader_adapter_type: EraReaderAdapterType::Bootstrap,
169 era_reader_adapter_params: None,
170 enable_metrics_server: true,
171 metrics_server_ip: "0.0.0.0".to_string(),
172 metrics_server_port: 9090,
173 allow_unparsable_block: false,
174 enable_transaction_pruning: false,
175 transactions_import_block_chunk_size: BlockNumber(1000),
176 cardano_transactions_block_streamer_max_roll_forwards_per_poll: 1000,
177 preloading_refresh_interval_in_seconds: 60,
178 signature_publisher_config: SignaturePublisherConfig {
179 retry_attempts: 1,
180 retry_delay_ms: 1,
181 delayer_delay_ms: 1,
182 },
183 }
184 }
185
186 pub fn get_network(&self) -> StdResult<CardanoNetwork> {
188 CardanoNetwork::from_code(self.network.clone(), self.network_magic).with_context(|| {
189 format!(
190 "Could not read Network '{}' from configuration.",
191 &self.network
192 )
193 })
194 }
195
196 pub fn get_sqlite_file(&self, sqlite_file_name: &str) -> StdResult<PathBuf> {
199 let store_dir = &self.data_stores_directory;
200
201 if !store_dir.exists() {
202 std::fs::create_dir_all(store_dir).with_context(|| {
203 format!(
204 "Could not create directory '{}' for Sqlite3 file.",
205 store_dir.display()
206 )
207 })?;
208 }
209
210 Ok(self.data_stores_directory.join(sqlite_file_name))
211 }
212
213 pub fn build_era_reader_adapter(
215 &self,
216 chain_observer: Arc<dyn ChainObserver>,
217 ) -> StdResult<Arc<dyn EraReaderAdapter>> {
218 EraReaderAdapterBuilder::new(
219 &self.era_reader_adapter_type,
220 &self.era_reader_adapter_params,
221 )
222 .build(chain_observer)
223 .with_context(|| {
224 format!(
225 "Configuration: can not create era reader for adapter '{}'.",
226 &self.era_reader_adapter_type
227 )
228 })
229 }
230}
231
232#[derive(Debug, Clone, DocumenterDefault)]
234pub struct DefaultConfiguration {
235 pub era_reader_adapter_type: String,
237
238 pub metrics_server_ip: String,
240
241 pub metrics_server_port: u16,
243
244 pub network_security_parameter: u64,
246
247 pub enable_transaction_pruning: bool,
249
250 pub preload_security_parameter: u64,
252
253 pub transactions_import_block_chunk_size: u64,
255
256 pub cardano_transactions_block_streamer_max_roll_forwards_per_poll: u32,
258}
259
260impl DefaultConfiguration {
261 fn namespace() -> String {
262 "default configuration".to_string()
263 }
264}
265
266impl Default for DefaultConfiguration {
267 fn default() -> Self {
268 Self {
269 era_reader_adapter_type: "bootstrap".to_string(),
270 metrics_server_ip: "0.0.0.0".to_string(),
271 metrics_server_port: 9090,
272 network_security_parameter: 2160, preload_security_parameter: 1000,
274 enable_transaction_pruning: true,
275 transactions_import_block_chunk_size: 1500,
276 cardano_transactions_block_streamer_max_roll_forwards_per_poll: 10000,
277 }
278 }
279}
280
281impl Source for DefaultConfiguration {
282 fn clone_into_box(&self) -> Box<dyn Source + Send + Sync> {
283 Box::new(self.clone())
284 }
285
286 fn collect(&self) -> Result<Map<String, Value>, ConfigError> {
287 let mut result = Map::new();
288 let namespace = DefaultConfiguration::namespace();
289 let myself = self.clone();
290
291 register_config_value!(result, &namespace, myself.era_reader_adapter_type);
292 register_config_value!(result, &namespace, myself.metrics_server_ip);
293 register_config_value!(result, &namespace, myself.metrics_server_port);
294 register_config_value!(result, &namespace, myself.network_security_parameter);
295 register_config_value!(result, &namespace, myself.preload_security_parameter);
296 register_config_value!(result, &namespace, myself.enable_transaction_pruning);
297 register_config_value!(
298 result,
299 &namespace,
300 myself.transactions_import_block_chunk_size
301 );
302 register_config_value!(
303 result,
304 &namespace,
305 myself.cardano_transactions_block_streamer_max_roll_forwards_per_poll
306 );
307
308 Ok(result)
309 }
310}