use anyhow::Context;
use config::{ConfigError, Map, Source, Value, ValueKind};
use mithril_doc::{Documenter, DocumenterDefault, StructDoc};
use serde::{Deserialize, Serialize};
use std::{path::PathBuf, sync::Arc};
use mithril_common::{
chain_observer::ChainObserver,
crypto_helper::tests_setup,
entities::{BlockNumber, PartyId},
era::{
adapters::{EraReaderAdapterBuilder, EraReaderAdapterType},
EraReaderAdapter,
},
CardanoNetwork, StdResult,
};
#[derive(Debug, Clone, Serialize, Deserialize, Documenter)]
pub struct Configuration {
#[example = "`cardano-cli`"]
pub cardano_cli_path: PathBuf,
#[example = "`/tmp/cardano.sock`"]
pub cardano_node_socket_path: PathBuf,
#[example = "`testnet` or `mainnet` or `devnet`"]
pub network: String,
#[example = "`1097911063` or `42`"]
pub network_magic: Option<u64>,
pub network_security_parameter: BlockNumber,
pub preload_security_parameter: BlockNumber,
#[example = "`https://aggregator.pre-release-preview.api.mithril.network/aggregator`"]
pub aggregator_endpoint: String,
pub relay_endpoint: Option<String>,
#[example = "`pool1pxaqe80sqpde7902er5kf6v0c7y0sv6d5g676766v2h829fvs3x`"]
pub party_id: Option<PartyId>,
#[example = "`60000`"]
pub run_interval: u64,
pub db_directory: PathBuf,
#[example = "`./mithril-signer/stores`"]
pub data_stores_directory: PathBuf,
pub store_retention_limit: Option<usize>,
pub kes_secret_key_path: Option<PathBuf>,
pub operational_certificate_path: Option<PathBuf>,
pub disable_digests_cache: bool,
pub reset_digests_cache: bool,
pub era_reader_adapter_type: EraReaderAdapterType,
pub era_reader_adapter_params: Option<String>,
pub enable_metrics_server: bool,
pub metrics_server_ip: String,
pub metrics_server_port: u16,
pub allow_unparsable_block: bool,
pub enable_transaction_pruning: bool,
pub transactions_import_block_chunk_size: BlockNumber,
pub cardano_transactions_block_streamer_max_roll_forwards_per_poll: usize,
pub preloading_refresh_interval_in_seconds: u64,
}
impl Configuration {
#[doc(hidden)]
pub fn new_sample<P: Into<PartyId>>(party_id: P) -> Self {
let party_id: PartyId = party_id.into();
let signer_temp_dir = tests_setup::setup_temp_directory_for_signer(&party_id, false);
Self {
aggregator_endpoint: "http://0.0.0.0:8000".to_string(),
relay_endpoint: None,
cardano_cli_path: PathBuf::new(),
cardano_node_socket_path: PathBuf::new(),
db_directory: PathBuf::new(),
network: "devnet".to_string(),
network_magic: Some(42),
network_security_parameter: BlockNumber(2160),
preload_security_parameter: BlockNumber(30),
party_id: Some(party_id),
run_interval: 5000,
data_stores_directory: PathBuf::new(),
store_retention_limit: None,
kes_secret_key_path: signer_temp_dir.as_ref().map(|dir| dir.join("kes.sk")),
operational_certificate_path: signer_temp_dir
.as_ref()
.map(|dir| dir.join("opcert.cert")),
disable_digests_cache: false,
reset_digests_cache: false,
era_reader_adapter_type: EraReaderAdapterType::Bootstrap,
era_reader_adapter_params: None,
enable_metrics_server: true,
metrics_server_ip: "0.0.0.0".to_string(),
metrics_server_port: 9090,
allow_unparsable_block: false,
enable_transaction_pruning: false,
transactions_import_block_chunk_size: BlockNumber(1000),
cardano_transactions_block_streamer_max_roll_forwards_per_poll: 1000,
preloading_refresh_interval_in_seconds: 60,
}
}
pub fn get_network(&self) -> StdResult<CardanoNetwork> {
CardanoNetwork::from_code(self.network.clone(), self.network_magic).with_context(|| {
format!(
"Could not read Network '{}' from configuration.",
&self.network
)
})
}
pub fn get_sqlite_file(&self, sqlite_file_name: &str) -> StdResult<PathBuf> {
let store_dir = &self.data_stores_directory;
if !store_dir.exists() {
std::fs::create_dir_all(store_dir).with_context(|| {
format!(
"Could not create directory '{}' for Sqlite3 file.",
store_dir.display()
)
})?;
}
Ok(self.data_stores_directory.join(sqlite_file_name))
}
pub fn build_era_reader_adapter(
&self,
chain_observer: Arc<dyn ChainObserver>,
) -> StdResult<Arc<dyn EraReaderAdapter>> {
EraReaderAdapterBuilder::new(
&self.era_reader_adapter_type,
&self.era_reader_adapter_params,
)
.build(chain_observer)
.with_context(|| {
format!(
"Configuration: can not create era reader for adapter '{}'.",
&self.era_reader_adapter_type
)
})
}
}
#[derive(Debug, Clone, DocumenterDefault)]
pub struct DefaultConfiguration {
pub era_reader_adapter_type: String,
pub metrics_server_ip: String,
pub metrics_server_port: u16,
pub network_security_parameter: u64,
pub enable_transaction_pruning: bool,
pub preload_security_parameter: u64,
pub transactions_import_block_chunk_size: u64,
pub cardano_transactions_block_streamer_max_roll_forwards_per_poll: u32,
}
impl DefaultConfiguration {
fn namespace() -> String {
"default configuration".to_string()
}
}
impl Default for DefaultConfiguration {
fn default() -> Self {
Self {
era_reader_adapter_type: "bootstrap".to_string(),
metrics_server_ip: "0.0.0.0".to_string(),
metrics_server_port: 9090,
network_security_parameter: 2160, preload_security_parameter: 1000,
enable_transaction_pruning: true,
transactions_import_block_chunk_size: 1500,
cardano_transactions_block_streamer_max_roll_forwards_per_poll: 10000,
}
}
}
impl Source for DefaultConfiguration {
fn clone_into_box(&self) -> Box<dyn Source + Send + Sync> {
Box::new(self.clone())
}
fn collect(&self) -> Result<Map<String, Value>, ConfigError> {
macro_rules! insert_default_configuration {
( $map:ident, $config:ident.$parameter:ident ) => {{
$map.insert(
stringify!($parameter).to_string(),
into_value($config.$parameter),
);
}};
}
fn into_value<V: Into<ValueKind>>(value: V) -> Value {
Value::new(Some(&DefaultConfiguration::namespace()), value.into())
}
let mut result = Map::new();
let myself = self.clone();
insert_default_configuration!(result, myself.era_reader_adapter_type);
insert_default_configuration!(result, myself.metrics_server_ip);
insert_default_configuration!(result, myself.metrics_server_port);
insert_default_configuration!(result, myself.network_security_parameter);
insert_default_configuration!(result, myself.preload_security_parameter);
insert_default_configuration!(result, myself.enable_transaction_pruning);
insert_default_configuration!(result, myself.transactions_import_block_chunk_size);
insert_default_configuration!(
result,
myself.cardano_transactions_block_streamer_max_roll_forwards_per_poll
);
Ok(result)
}
}