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, Documenter)]
21pub struct Configuration {
22 #[example = "`cardano-cli`"]
24 pub cardano_cli_path: PathBuf,
25
26 #[example = "`/tmp/cardano.sock`"]
29 pub cardano_node_socket_path: PathBuf,
30
31 #[example = "`testnet` or `mainnet` or `devnet`"]
33 pub network: String,
34
35 #[example = "`1097911063` or `42`"]
38 pub network_magic: Option<u64>,
39
40 pub network_security_parameter: BlockNumber,
43
44 pub preload_security_parameter: BlockNumber,
47
48 #[example = "`https://aggregator.pre-release-preview.api.mithril.network/aggregator`"]
50 pub aggregator_endpoint: String,
51
52 pub relay_endpoint: Option<String>,
54
55 #[example = "`pool1pxaqe80sqpde7902er5kf6v0c7y0sv6d5g676766v2h829fvs3x`"]
59 pub party_id: Option<PartyId>,
60
61 #[example = "`60000`"]
63 pub run_interval: u64,
64
65 pub db_directory: PathBuf,
67
68 #[example = "`./mithril-signer/stores`"]
70 pub data_stores_directory: PathBuf,
71
72 pub store_retention_limit: Option<usize>,
74
75 pub kes_secret_key_path: Option<PathBuf>,
77
78 pub operational_certificate_path: Option<PathBuf>,
80
81 pub disable_digests_cache: bool,
83
84 pub reset_digests_cache: bool,
88
89 pub era_reader_adapter_type: EraReaderAdapterType,
91
92 pub era_reader_adapter_params: Option<String>,
94
95 pub enable_metrics_server: bool,
97
98 pub metrics_server_ip: String,
100
101 pub metrics_server_port: u16,
103
104 pub allow_unparsable_block: bool,
108
109 pub enable_transaction_pruning: bool,
113
114 pub transactions_import_block_chunk_size: BlockNumber,
118
119 pub cardano_transactions_block_streamer_max_roll_forwards_per_poll: usize,
121
122 pub preloading_refresh_interval_in_seconds: u64,
124}
125
126impl Configuration {
127 #[doc(hidden)]
129 pub fn new_sample<P: Into<PartyId>>(party_id: P) -> Self {
130 let party_id: PartyId = party_id.into();
131 let signer_temp_dir = tests_setup::setup_temp_directory_for_signer(&party_id, false);
132 Self {
133 aggregator_endpoint: "http://0.0.0.0:8000".to_string(),
134 relay_endpoint: None,
135 cardano_cli_path: PathBuf::new(),
136 cardano_node_socket_path: PathBuf::new(),
137 db_directory: PathBuf::new(),
138 network: "devnet".to_string(),
139 network_magic: Some(42),
140 network_security_parameter: BlockNumber(2160),
141 preload_security_parameter: BlockNumber(30),
142 party_id: Some(party_id),
143 run_interval: 5000,
144 data_stores_directory: PathBuf::new(),
145 store_retention_limit: None,
146 kes_secret_key_path: signer_temp_dir.as_ref().map(|dir| dir.join("kes.sk")),
147 operational_certificate_path: signer_temp_dir
148 .as_ref()
149 .map(|dir| dir.join("opcert.cert")),
150 disable_digests_cache: false,
151 reset_digests_cache: false,
152 era_reader_adapter_type: EraReaderAdapterType::Bootstrap,
153 era_reader_adapter_params: None,
154 enable_metrics_server: true,
155 metrics_server_ip: "0.0.0.0".to_string(),
156 metrics_server_port: 9090,
157 allow_unparsable_block: false,
158 enable_transaction_pruning: false,
159 transactions_import_block_chunk_size: BlockNumber(1000),
160 cardano_transactions_block_streamer_max_roll_forwards_per_poll: 1000,
161 preloading_refresh_interval_in_seconds: 60,
162 }
163 }
164
165 pub fn get_network(&self) -> StdResult<CardanoNetwork> {
167 CardanoNetwork::from_code(self.network.clone(), self.network_magic).with_context(|| {
168 format!(
169 "Could not read Network '{}' from configuration.",
170 &self.network
171 )
172 })
173 }
174
175 pub fn get_sqlite_file(&self, sqlite_file_name: &str) -> StdResult<PathBuf> {
178 let store_dir = &self.data_stores_directory;
179
180 if !store_dir.exists() {
181 std::fs::create_dir_all(store_dir).with_context(|| {
182 format!(
183 "Could not create directory '{}' for Sqlite3 file.",
184 store_dir.display()
185 )
186 })?;
187 }
188
189 Ok(self.data_stores_directory.join(sqlite_file_name))
190 }
191
192 pub fn build_era_reader_adapter(
194 &self,
195 chain_observer: Arc<dyn ChainObserver>,
196 ) -> StdResult<Arc<dyn EraReaderAdapter>> {
197 EraReaderAdapterBuilder::new(
198 &self.era_reader_adapter_type,
199 &self.era_reader_adapter_params,
200 )
201 .build(chain_observer)
202 .with_context(|| {
203 format!(
204 "Configuration: can not create era reader for adapter '{}'.",
205 &self.era_reader_adapter_type
206 )
207 })
208 }
209}
210
211#[derive(Debug, Clone, DocumenterDefault)]
213pub struct DefaultConfiguration {
214 pub era_reader_adapter_type: String,
216
217 pub metrics_server_ip: String,
219
220 pub metrics_server_port: u16,
222
223 pub network_security_parameter: u64,
225
226 pub enable_transaction_pruning: bool,
228
229 pub preload_security_parameter: u64,
231
232 pub transactions_import_block_chunk_size: u64,
234
235 pub cardano_transactions_block_streamer_max_roll_forwards_per_poll: u32,
237}
238
239impl DefaultConfiguration {
240 fn namespace() -> String {
241 "default configuration".to_string()
242 }
243}
244
245impl Default for DefaultConfiguration {
246 fn default() -> Self {
247 Self {
248 era_reader_adapter_type: "bootstrap".to_string(),
249 metrics_server_ip: "0.0.0.0".to_string(),
250 metrics_server_port: 9090,
251 network_security_parameter: 2160, preload_security_parameter: 1000,
253 enable_transaction_pruning: true,
254 transactions_import_block_chunk_size: 1500,
255 cardano_transactions_block_streamer_max_roll_forwards_per_poll: 10000,
256 }
257 }
258}
259
260impl Source for DefaultConfiguration {
261 fn clone_into_box(&self) -> Box<dyn Source + Send + Sync> {
262 Box::new(self.clone())
263 }
264
265 fn collect(&self) -> Result<Map<String, Value>, ConfigError> {
266 let mut result = Map::new();
267 let namespace = DefaultConfiguration::namespace();
268 let myself = self.clone();
269
270 register_config_value!(result, &namespace, myself.era_reader_adapter_type);
271 register_config_value!(result, &namespace, myself.metrics_server_ip);
272 register_config_value!(result, &namespace, myself.metrics_server_port);
273 register_config_value!(result, &namespace, myself.network_security_parameter);
274 register_config_value!(result, &namespace, myself.preload_security_parameter);
275 register_config_value!(result, &namespace, myself.enable_transaction_pruning);
276 register_config_value!(
277 result,
278 &namespace,
279 myself.transactions_import_block_chunk_size
280 );
281 register_config_value!(
282 result,
283 &namespace,
284 myself.cardano_transactions_block_streamer_max_roll_forwards_per_poll
285 );
286
287 Ok(result)
288 }
289}