mithril_signer/
configuration.rs

1use anyhow::Context;
2use config::{ConfigError, Map, Source, Value};
3use mithril_dmq::DmqNetwork;
4use mithril_doc::{Documenter, DocumenterDefault, StructDoc};
5use serde::Deserialize;
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, Deserialize)]
20pub struct SignaturePublisherConfig {
21    /// Number of retry attempts when publishing the signature
22    pub retry_attempts: u8,
23
24    /// Delay (in milliseconds) between two retry attempts when publishing the signature
25    pub retry_delay_ms: u64,
26
27    /// Delay (in milliseconds) between two separate publications done by the delayer signature publisher
28    pub delayer_delay_ms: u64,
29
30    /// Whether to skip the delayer when publishing the signature
31    pub skip_delayer: bool,
32}
33
34/// Client configuration
35#[derive(Debug, Clone, Deserialize, Documenter)]
36pub struct Configuration {
37    /// Cardano CLI tool path
38    #[example = "`cardano-cli`"]
39    pub cardano_cli_path: PathBuf,
40
41    /// Path of the socket opened by the Cardano node
42    #[example = "`/ipc/node.socket`"]
43    pub cardano_node_socket_path: PathBuf,
44
45    /// Path of the socket opened by the DMQ node
46    #[example = "`/ipc/dmq.socket`"]
47    pub dmq_node_socket_path: Option<PathBuf>,
48
49    /// Cardano network
50    #[example = "`mainnet` or `preprod` or `devnet`"]
51    pub network: String,
52
53    /// Cardano network magic number
54    /// useful for TestNet & DevNet
55    #[example = "`1097911063` or `42`"]
56    pub network_magic: Option<u64>,
57
58    /// DMQ network magic number
59    ///
60    /// useful for TestNet & DevNet
61    #[example = "`1097911063` or `42`"]
62    pub dmq_network_magic: Option<u64>,
63
64    /// Also known as `k`, it defines the number of blocks that are required for the blockchain to
65    /// be considered final, preventing any further rollback `[default: 2160]`.
66    pub network_security_parameter: BlockNumber,
67
68    /// Blocks offset, from the tip of the chain, to exclude during the Cardano transactions preload,
69    /// default to 2160.
70    #[example = "`2160`"]
71    pub preload_security_parameter: BlockNumber,
72
73    /// Aggregator endpoint
74    #[example = "`https://aggregator.pre-release-preview.api.mithril.network/aggregator`"]
75    pub aggregator_endpoint: String,
76
77    /// Relay endpoint
78    pub relay_endpoint: Option<String>,
79
80    /// Party Id
81    ///
82    /// Used only for testing when SPO pool id is not certified
83    #[example = "`pool1pxaqe80sqpde7902er5kf6v0c7y0sv6d5g676766v2h829fvs3x`"]
84    pub party_id: Option<PartyId>,
85
86    /// Run Interval
87    #[example = "`60000`"]
88    pub run_interval: u64,
89
90    /// Directory to snapshot
91    pub db_directory: PathBuf,
92
93    /// Directory to store signer data (Stakes, Protocol initializers, ...)
94    #[example = "`./mithril-signer/stores`"]
95    pub data_stores_directory: PathBuf,
96
97    /// Store retention limit. If set to None, no limit will be set.
98    pub store_retention_limit: Option<usize>,
99
100    /// File path to the KES secret key of the pool
101    pub kes_secret_key_path: Option<PathBuf>,
102
103    /// File path to the operational certificate of the pool
104    pub operational_certificate_path: Option<PathBuf>,
105
106    /// Disable immutables digests cache.
107    pub disable_digests_cache: bool,
108
109    /// If set the existing immutables digests cache will be reset.
110    ///
111    /// Will be ignored if set in conjunction with `disable_digests_cache`.
112    pub reset_digests_cache: bool,
113
114    /// Era reader adapter type
115    pub era_reader_adapter_type: EraReaderAdapterType,
116
117    /// Era reader adapter parameters
118    pub era_reader_adapter_params: Option<String>,
119
120    /// Enable metrics server (Prometheus endpoint on /metrics).
121    pub enable_metrics_server: bool,
122
123    /// Metrics HTTP Server IP.
124    pub metrics_server_ip: String,
125
126    /// Metrics HTTP Server listening port.
127    pub metrics_server_port: u16,
128
129    /// If set no error is returned in case of unparsable block and an error log is written instead.
130    ///
131    /// Will be ignored on (pre)production networks.
132    pub allow_unparsable_block: bool,
133
134    /// If set, the signer will prune the cardano transactions in database older than the
135    /// [network_security_parameter][Self::network_security_parameter] blocks after each import
136    /// `[default: true]`.
137    pub enable_transaction_pruning: bool,
138
139    /// Chunk size for importing transactions, combined with transaction pruning it reduces the
140    /// storage footprint of the signer by reducing the number of transactions stored on disk
141    /// at any given time.
142    pub transactions_import_block_chunk_size: BlockNumber,
143
144    /// The maximum number of roll forwards during a poll of the block streamer when importing transactions.
145    pub cardano_transactions_block_streamer_max_roll_forwards_per_poll: usize,
146
147    /// Minimum duration between two consecutive block streamer polls in milliseconds `[default: 400]`.
148    ///
149    /// Set this value to `0` to disable throttling.
150    pub cardano_transactions_block_streamer_throttling_interval: Option<u64>,
151
152    /// Preloading refresh interval in seconds
153    pub preloading_refresh_interval_in_seconds: u64,
154
155    /// Signature publisher configuration
156    #[example = "`{ retry_attempts: 3, retry_delay_ms: 2000, delayer_delay_ms: 10000, skip_delayer: false }`"]
157    pub signature_publisher_config: SignaturePublisherConfig,
158}
159
160impl Configuration {
161    /// Create a sample configuration mainly for tests
162    #[doc(hidden)]
163    pub fn new_sample<P: Into<PartyId>>(party_id: P) -> Self {
164        let party_id: PartyId = party_id.into();
165        let signer_temp_dir =
166            mithril_common::test::crypto_helper::setup_temp_directory_for_signer(&party_id, false);
167        Self {
168            aggregator_endpoint: "http://0.0.0.0:8000".to_string(),
169            relay_endpoint: None,
170            cardano_cli_path: PathBuf::new(),
171            cardano_node_socket_path: PathBuf::new(),
172            dmq_node_socket_path: None,
173            db_directory: PathBuf::new(),
174            network: "devnet".to_string(),
175            network_magic: Some(42),
176            dmq_network_magic: Some(3141592),
177            network_security_parameter: BlockNumber(2160),
178            preload_security_parameter: BlockNumber(30),
179            party_id: Some(party_id),
180            run_interval: 5000,
181            data_stores_directory: PathBuf::new(),
182            store_retention_limit: None,
183            kes_secret_key_path: signer_temp_dir.as_ref().map(|dir| dir.join("kes.sk")),
184            operational_certificate_path: signer_temp_dir
185                .as_ref()
186                .map(|dir| dir.join("opcert.cert")),
187            disable_digests_cache: false,
188            reset_digests_cache: false,
189            era_reader_adapter_type: EraReaderAdapterType::Bootstrap,
190            era_reader_adapter_params: None,
191            enable_metrics_server: true,
192            metrics_server_ip: "0.0.0.0".to_string(),
193            metrics_server_port: 9090,
194            allow_unparsable_block: false,
195            enable_transaction_pruning: false,
196            transactions_import_block_chunk_size: BlockNumber(1000),
197            cardano_transactions_block_streamer_max_roll_forwards_per_poll: 1000,
198            cardano_transactions_block_streamer_throttling_interval: None,
199            preloading_refresh_interval_in_seconds: 60,
200            signature_publisher_config: SignaturePublisherConfig {
201                retry_attempts: 1,
202                retry_delay_ms: 1,
203                delayer_delay_ms: 1,
204                skip_delayer: false,
205            },
206        }
207    }
208
209    /// Return the Cardano network value from the configuration.
210    pub fn get_network(&self) -> StdResult<CardanoNetwork> {
211        CardanoNetwork::from_code(self.network.clone(), self.network_magic).with_context(|| {
212            format!(
213                "Could not read Network '{}' from configuration.",
214                &self.network
215            )
216        })
217    }
218
219    /// Return the DMQ network value from the configuration.
220    pub fn get_dmq_network(&self) -> StdResult<DmqNetwork> {
221        DmqNetwork::from_code(self.network.clone(), self.dmq_network_magic).with_context(|| {
222            format!(
223                "Could not read DMQ Network '{}' from configuration.",
224                &self.network
225            )
226        })
227    }
228
229    /// Create the SQL store directory if not exist and return the path of the
230    /// SQLite3 file.
231    pub fn get_sqlite_file(&self, sqlite_file_name: &str) -> StdResult<PathBuf> {
232        let store_dir = &self.data_stores_directory;
233
234        if !store_dir.exists() {
235            std::fs::create_dir_all(store_dir).with_context(|| {
236                format!(
237                    "Could not create directory '{}' for Sqlite3 file.",
238                    store_dir.display()
239                )
240            })?;
241        }
242
243        Ok(self.data_stores_directory.join(sqlite_file_name))
244    }
245
246    /// Create era reader adapter from configuration settings.
247    pub fn build_era_reader_adapter(
248        &self,
249        chain_observer: Arc<dyn ChainObserver>,
250    ) -> StdResult<Arc<dyn EraReaderAdapter>> {
251        EraReaderAdapterBuilder::new(
252            &self.era_reader_adapter_type,
253            &self.era_reader_adapter_params,
254        )
255        .build(chain_observer)
256        .with_context(|| {
257            format!(
258                "Configuration: can not create era reader for adapter '{}'.",
259                &self.era_reader_adapter_type
260            )
261        })
262    }
263}
264
265/// Default configuration with all the default values for configurations.
266#[derive(Debug, Clone, DocumenterDefault)]
267pub struct DefaultConfiguration {
268    /// Era reader adapter type
269    pub era_reader_adapter_type: String,
270
271    /// Metrics HTTP server IP.
272    pub metrics_server_ip: String,
273
274    /// Metrics HTTP server listening port.
275    pub metrics_server_port: u16,
276
277    /// Network security parameter
278    pub network_security_parameter: u64,
279
280    /// Transaction pruning toggle
281    pub enable_transaction_pruning: bool,
282
283    /// Preload security parameter
284    pub preload_security_parameter: u64,
285
286    /// Chunk size for importing transactions
287    pub transactions_import_block_chunk_size: u64,
288
289    /// The maximum number of roll forwards during a poll of the block streamer when importing transactions.
290    pub cardano_transactions_block_streamer_max_roll_forwards_per_poll: u32,
291
292    /// Minimum duration between two consecutive block streamer polls in milliseconds.
293    pub cardano_transactions_block_streamer_throttling_interval: u64,
294}
295
296impl DefaultConfiguration {
297    fn namespace() -> String {
298        "default configuration".to_string()
299    }
300}
301
302impl Default for DefaultConfiguration {
303    fn default() -> Self {
304        Self {
305            era_reader_adapter_type: "bootstrap".to_string(),
306            metrics_server_ip: "0.0.0.0".to_string(),
307            metrics_server_port: 9090,
308            network_security_parameter: 2160, // 2160 is the mainnet value
309            preload_security_parameter: 2160,
310            enable_transaction_pruning: true,
311            transactions_import_block_chunk_size: 1500,
312            cardano_transactions_block_streamer_max_roll_forwards_per_poll: 10000,
313            cardano_transactions_block_streamer_throttling_interval: 400,
314        }
315    }
316}
317
318impl Source for DefaultConfiguration {
319    fn clone_into_box(&self) -> Box<dyn Source + Send + Sync> {
320        Box::new(self.clone())
321    }
322
323    fn collect(&self) -> Result<Map<String, Value>, ConfigError> {
324        let mut result = Map::new();
325        let namespace = DefaultConfiguration::namespace();
326        let myself = self.clone();
327
328        register_config_value!(result, &namespace, myself.era_reader_adapter_type);
329        register_config_value!(result, &namespace, myself.metrics_server_ip);
330        register_config_value!(result, &namespace, myself.metrics_server_port);
331        register_config_value!(result, &namespace, myself.network_security_parameter);
332        register_config_value!(result, &namespace, myself.preload_security_parameter);
333        register_config_value!(result, &namespace, myself.enable_transaction_pruning);
334        register_config_value!(
335            result,
336            &namespace,
337            myself.transactions_import_block_chunk_size
338        );
339        register_config_value!(
340            result,
341            &namespace,
342            myself.cardano_transactions_block_streamer_max_roll_forwards_per_poll
343        );
344        register_config_value!(
345            result,
346            &namespace,
347            myself.cardano_transactions_block_streamer_throttling_interval
348        );
349
350        Ok(result)
351    }
352}