mithril_signer/
configuration.rs

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    /// Number of retry attempts when publishing the signature
21    pub retry_attempts: u8,
22
23    /// Delay (in milliseconds) between two retry attempts when publishing the signature
24    pub retry_delay_ms: u64,
25
26    /// Delay (in milliseconds) between two separate publications done by the delayer signature publisher
27    pub delayer_delay_ms: u64,
28
29    /// Whether to skip the delayer when publishing the signature
30    ///
31    /// If set to true, the signatures will be published only once:
32    /// - if the 'future_dmq` feature is used to compile, the signatures will be published only with the DMQ protocol
33    /// - if the `future_dmq` feature is not used, the signatures will be published with the regular HTTP protocol
34    pub skip_delayer: bool,
35}
36
37/// Client configuration
38#[derive(Debug, Clone, Serialize, Deserialize, Documenter)]
39pub struct Configuration {
40    /// Cardano CLI tool path
41    #[example = "`cardano-cli`"]
42    pub cardano_cli_path: PathBuf,
43
44    /// Path of the socket opened by the Cardano node
45    #[example = "`/ipc/node.socket`"]
46    pub cardano_node_socket_path: PathBuf,
47
48    /// Path of the socket opened by the DMQ node
49    #[example = "`/ipc/dmq.socket`"]
50    pub dmq_node_socket_path: Option<PathBuf>,
51
52    /// Cardano network
53    #[example = "`mainnet` or `preprod` or `devnet`"]
54    pub network: String,
55
56    /// Cardano Network Magic number
57    /// useful for TestNet & DevNet
58    #[example = "`1097911063` or `42`"]
59    pub network_magic: Option<u64>,
60
61    /// Also known as `k`, it defines the number of blocks that are required for the blockchain to
62    /// be considered final, preventing any further rollback `[default: 2160]`.
63    pub network_security_parameter: BlockNumber,
64
65    /// Blocks offset, from the tip of the chain, to exclude during the cardano transactions preload
66    /// `[default: 3000]`.
67    pub preload_security_parameter: BlockNumber,
68
69    /// Aggregator endpoint
70    #[example = "`https://aggregator.pre-release-preview.api.mithril.network/aggregator`"]
71    pub aggregator_endpoint: String,
72
73    /// Relay endpoint
74    pub relay_endpoint: Option<String>,
75
76    /// Party Id
77    ///
78    /// Used only for testing when SPO pool id is not certified
79    #[example = "`pool1pxaqe80sqpde7902er5kf6v0c7y0sv6d5g676766v2h829fvs3x`"]
80    pub party_id: Option<PartyId>,
81
82    /// Run Interval
83    #[example = "`60000`"]
84    pub run_interval: u64,
85
86    /// Directory to snapshot
87    pub db_directory: PathBuf,
88
89    /// Directory to store signer data (Stakes, Protocol initializers, ...)
90    #[example = "`./mithril-signer/stores`"]
91    pub data_stores_directory: PathBuf,
92
93    /// Store retention limit. If set to None, no limit will be set.
94    pub store_retention_limit: Option<usize>,
95
96    /// File path to the KES secret key of the pool
97    pub kes_secret_key_path: Option<PathBuf>,
98
99    /// File path to the operational certificate of the pool
100    pub operational_certificate_path: Option<PathBuf>,
101
102    /// Disable immutables digests cache.
103    pub disable_digests_cache: bool,
104
105    /// If set the existing immutables digests cache will be reset.
106    ///
107    /// Will be ignored if set in conjunction with `disable_digests_cache`.
108    pub reset_digests_cache: bool,
109
110    /// Era reader adapter type
111    pub era_reader_adapter_type: EraReaderAdapterType,
112
113    /// Era reader adapter parameters
114    pub era_reader_adapter_params: Option<String>,
115
116    /// Enable metrics server (Prometheus endpoint on /metrics).
117    pub enable_metrics_server: bool,
118
119    /// Metrics HTTP Server IP.
120    pub metrics_server_ip: String,
121
122    /// Metrics HTTP Server listening port.
123    pub metrics_server_port: u16,
124
125    /// If set no error is returned in case of unparsable block and an error log is written instead.
126    ///
127    /// Will be ignored on (pre)production networks.
128    pub allow_unparsable_block: bool,
129
130    /// If set, the signer will prune the cardano transactions in database older than the
131    /// [network_security_parameter][Self::network_security_parameter] blocks after each import
132    /// `[default: true]`.
133    pub enable_transaction_pruning: bool,
134
135    /// Chunk size for importing transactions, combined with transaction pruning it reduces the
136    /// storage footprint of the signer by reducing the number of transactions stored on disk
137    /// at any given time.
138    pub transactions_import_block_chunk_size: BlockNumber,
139
140    /// The maximum number of roll forwards during a poll of the block streamer when importing transactions.
141    pub cardano_transactions_block_streamer_max_roll_forwards_per_poll: usize,
142
143    /// Preloading refresh interval in seconds
144    pub preloading_refresh_interval_in_seconds: u64,
145
146    /// Signature publisher configuration
147    #[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    /// Create a sample configuration mainly for tests
153    #[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    /// Return the CardanoNetwork value from the configuration.
199    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    /// Create the SQL store directory if not exist and return the path of the
209    /// SQLite3 file.
210    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    /// Create era reader adapter from configuration settings.
226    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/// Default configuration with all the default values for configurations.
245#[derive(Debug, Clone, DocumenterDefault)]
246pub struct DefaultConfiguration {
247    /// Era reader adapter type
248    pub era_reader_adapter_type: String,
249
250    /// Metrics HTTP server IP.
251    pub metrics_server_ip: String,
252
253    /// Metrics HTTP server listening port.
254    pub metrics_server_port: u16,
255
256    /// Network security parameter
257    pub network_security_parameter: u64,
258
259    /// Transaction pruning toggle
260    pub enable_transaction_pruning: bool,
261
262    /// Preload security parameter
263    pub preload_security_parameter: u64,
264
265    /// Chunk size for importing transactions
266    pub transactions_import_block_chunk_size: u64,
267
268    /// The maximum number of roll forwards during a poll of the block streamer when importing transactions.
269    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, // 2160 is the mainnet value
285            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}