diff --git a/Cargo.lock b/Cargo.lock
index 44ef9f6de80..b47c8220e45 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3621,6 +3621,7 @@ dependencies = [
"mithril-era",
"mithril-metric",
"mithril-persistence",
+ "mithril-protocol-config",
"mithril-resource-pool",
"mithril-signed-entity-lock",
"mithril-signed-entity-preloader",
diff --git a/docs/website/root/manual/develop/nodes/mithril-aggregator.md b/docs/website/root/manual/develop/nodes/mithril-aggregator.md
index 7ef2126b6ac..243fd1d7f22 100644
--- a/docs/website/root/manual/develop/nodes/mithril-aggregator.md
+++ b/docs/website/root/manual/develop/nodes/mithril-aggregator.md
@@ -537,6 +537,7 @@ Here is a list of the available parameters for the serve command:
| `cardano_transactions_prover_max_hashes_allowed_by_request` | `--cardano-transactions-prover-max-hashes-allowed-by-request` | - | `CARDANO_TRANSACTIONS_PROVER_MAX_HASHES_ALLOWED_BY_REQUEST` | Maximum number of transactions hashes allowed by request to the prover of the Cardano transactions | `100` | `100` | - |
| `cardano_transactions_block_streamer_max_roll_forwards_per_poll` | `--cardano-transactions-block-streamer-max-roll-forwards-per-poll` | - | `CARDANO_TRANSACTIONS_BLOCK_STREAMER_MAX_ROLL_FORWARDS_PER_POLL` | Maximum number of roll forwards during a poll of the block streamer when importing transactions | `1000` | `1000` | - |
| `cardano_transactions_signing_config` | `--cardano-transactions-signing-config` | - | `CARDANO_TRANSACTIONS_SIGNING_CONFIG` | Cardano transactions signing configuration | `{ "security_parameter": 3000, "step": 120 }` | `{ "security_parameter": 3000, "step": 120 }` | - |
+| `preload_security_parameter` | - | - | `PRELOAD_SECURITY_PARAMETER` | Blocks offset, from the tip of the chain, to exclude during the cardano transactions preload
`[default: 2160]`. | `2160` | - | :heavy_check_mark: |
| `enable_metrics_server` | `--enable-metrics-server` | - | `ENABLE_METRICS_SERVER` | Enable metrics HTTP server (Prometheus endpoint on /metrics) | `false` | - | - |
| `metrics_server_ip` | `--metrics-server-ip` | - | `METRICS_SERVER_IP` | Metrics HTTP server IP | `0.0.0.0` | - | - |
| `metrics_server_port` | `--metrics-server-port` | - | `METRICS_SERVER_PORT` | Metrics HTTP server listening port | `9090` | - | - |
diff --git a/mithril-aggregator/Cargo.toml b/mithril-aggregator/Cargo.toml
index 8390d0136fb..89a470ad16b 100644
--- a/mithril-aggregator/Cargo.toml
+++ b/mithril-aggregator/Cargo.toml
@@ -36,6 +36,7 @@ mithril-doc = { path = "../internal/mithril-doc" }
mithril-era = { path = "../internal/mithril-era" }
mithril-metric = { path = "../internal/mithril-metric" }
mithril-persistence = { path = "../internal/mithril-persistence" }
+mithril-protocol-config = { path = "../internal/mithril-protocol-config" }
mithril-resource-pool = { path = "../internal/mithril-resource-pool" }
mithril-signed-entity-lock = { path = "../internal/signed-entity/mithril-signed-entity-lock" }
mithril-signed-entity-preloader = { path = "../internal/signed-entity/mithril-signed-entity-preloader" }
diff --git a/mithril-aggregator/src/configuration.rs b/mithril-aggregator/src/configuration.rs
index fc3d2400899..ff72b93810b 100644
--- a/mithril-aggregator/src/configuration.rs
+++ b/mithril-aggregator/src/configuration.rs
@@ -109,7 +109,7 @@ pub trait ConfigurationSource {
}
/// Protocol parameters
- fn protocol_parameters(&self) -> ProtocolParameters {
+ fn protocol_parameters(&self) -> Option {
panic!("protocol_parameters is not implemented.");
}
@@ -251,10 +251,15 @@ pub trait ConfigurationSource {
}
/// Cardano transactions signing configuration
- fn cardano_transactions_signing_config(&self) -> CardanoTransactionsSigningConfig {
+ fn cardano_transactions_signing_config(&self) -> Option {
panic!("cardano_transactions_signing_config is not implemented.");
}
+ /// Blocks offset, from the tip of the chain, to exclude during the cardano transactions preload
+ fn preload_security_parameter(&self) -> BlockNumber {
+ panic!("preload_security_parameter is not implemented.");
+ }
+
/// Maximum number of transactions hashes allowed by request to the prover of the Cardano transactions
fn cardano_transactions_prover_max_hashes_allowed_by_request(&self) -> usize {
panic!("cardano_transactions_prover_max_hashes_allowed_by_request is not implemented.");
@@ -373,12 +378,20 @@ pub trait ConfigurationSource {
}
}
- /// Infer the [AggregatorEpochSettings] from the configuration.
- fn get_epoch_settings_configuration(&self) -> AggregatorEpochSettings {
- AggregatorEpochSettings {
- protocol_parameters: self.protocol_parameters(),
- cardano_transactions_signing_config: self.cardano_transactions_signing_config(),
- }
+ /// `leader aggregator only` Infer the [AggregatorEpochSettings] from the configuration.
+ fn get_leader_aggregator_epoch_settings_configuration(
+ &self,
+ ) -> StdResult {
+ Ok(AggregatorEpochSettings {
+ protocol_parameters: self.protocol_parameters().with_context(
+ || "Configuration `protocol_parameter` is mandatory for a Leader Aggregator",
+ )?,
+ cardano_transactions_signing_config: self
+ .cardano_transactions_signing_config()
+ .with_context(
+ || "Configuration `cardano_transactions_signing_config` is mandatory for a Leader Aggregator",
+ )?,
+ })
}
/// Check if the aggregator is running in follower mode.
@@ -453,7 +466,7 @@ pub struct ServeCommandConfiguration {
/// Protocol parameters
#[example = "`{ k: 5, m: 100, phi_f: 0.65 }`"]
- pub protocol_parameters: ProtocolParameters,
+ pub protocol_parameters: Option,
/// Type of snapshot uploader to use
#[example = "`gcp` or `local`"]
@@ -556,7 +569,11 @@ pub struct ServeCommandConfiguration {
/// Cardano transactions signing configuration
#[example = "`{ security_parameter: 3000, step: 120 }`"]
- pub cardano_transactions_signing_config: CardanoTransactionsSigningConfig,
+ pub cardano_transactions_signing_config: Option,
+
+ /// Blocks offset, from the tip of the chain, to exclude during the cardano transactions preload
+ /// `[default: 2160]`.
+ pub preload_security_parameter: BlockNumber,
/// Maximum number of transactions hashes allowed by request to the prover of the Cardano transactions
pub cardano_transactions_prover_max_hashes_allowed_by_request: usize,
@@ -672,11 +689,11 @@ impl ServeCommandConfiguration {
network_magic: Some(42),
dmq_network_magic: Some(3141592),
chain_observer_type: ChainObserverType::Fake,
- protocol_parameters: ProtocolParameters {
+ protocol_parameters: Some(ProtocolParameters {
k: 5,
m: 100,
phi_f: 0.95,
- },
+ }),
snapshot_uploader_type: SnapshotUploaderType::Local,
snapshot_bucket_name: None,
snapshot_use_cdn_domain: false,
@@ -710,10 +727,11 @@ impl ServeCommandConfiguration {
allow_unparsable_block: false,
cardano_transactions_prover_cache_pool_size: 3,
cardano_transactions_database_connection_pool_size: 5,
- cardano_transactions_signing_config: CardanoTransactionsSigningConfig {
+ cardano_transactions_signing_config: Some(CardanoTransactionsSigningConfig {
security_parameter: BlockNumber(120),
step: BlockNumber(15),
- },
+ }),
+ preload_security_parameter: BlockNumber(30),
cardano_transactions_prover_max_hashes_allowed_by_request: 100,
cardano_transactions_block_streamer_max_roll_forwards_per_poll: 1000,
enable_metrics_server: true,
@@ -773,7 +791,7 @@ impl ConfigurationSource for ServeCommandConfiguration {
self.chain_observer_type.clone()
}
- fn protocol_parameters(&self) -> ProtocolParameters {
+ fn protocol_parameters(&self) -> Option {
self.protocol_parameters.clone()
}
@@ -877,10 +895,14 @@ impl ConfigurationSource for ServeCommandConfiguration {
self.cardano_transactions_database_connection_pool_size
}
- fn cardano_transactions_signing_config(&self) -> CardanoTransactionsSigningConfig {
+ fn cardano_transactions_signing_config(&self) -> Option {
self.cardano_transactions_signing_config.clone()
}
+ fn preload_security_parameter(&self) -> BlockNumber {
+ self.preload_security_parameter
+ }
+
fn cardano_transactions_prover_max_hashes_allowed_by_request(&self) -> usize {
self.cardano_transactions_prover_max_hashes_allowed_by_request
}
@@ -981,6 +1003,9 @@ pub struct DefaultConfiguration {
/// Cardano transactions signing configuration
pub cardano_transactions_signing_config: CardanoTransactionsSigningConfig,
+ /// Blocks offset, from the tip of the chain, to exclude during the cardano transactions preload
+ pub preload_security_parameter: u64,
+
/// Maximum number of transactions hashes allowed by request to the prover of the Cardano transactions
pub cardano_transactions_prover_max_hashes_allowed_by_request: u32,
@@ -1026,6 +1051,7 @@ impl Default for DefaultConfiguration {
security_parameter: BlockNumber(3000),
step: BlockNumber(120),
},
+ preload_security_parameter: 2160,
cardano_transactions_prover_max_hashes_allowed_by_request: 100,
cardano_transactions_block_streamer_max_roll_forwards_per_poll: 10000,
enable_metrics_server: "false".to_string(),
@@ -1104,6 +1130,7 @@ impl Source for DefaultConfiguration {
&namespace,
myself.persist_usage_report_interval_in_seconds
);
+ register_config_value!(result, &namespace, myself.preload_security_parameter);
register_config_value!(
result,
&namespace,
@@ -1111,7 +1138,7 @@ impl Source for DefaultConfiguration {
|v: CardanoTransactionsSigningConfig| HashMap::from([
(
"security_parameter".to_string(),
- ValueKind::from(*v.security_parameter,),
+ ValueKind::from(*v.security_parameter),
),
("step".to_string(), ValueKind::from(*v.step),)
])
diff --git a/mithril-aggregator/src/database/query/epoch_settings/insert_or_ignore_epoch_settings.rs b/mithril-aggregator/src/database/query/epoch_settings/insert_or_ignore_epoch_settings.rs
new file mode 100644
index 00000000000..8bac1b12804
--- /dev/null
+++ b/mithril-aggregator/src/database/query/epoch_settings/insert_or_ignore_epoch_settings.rs
@@ -0,0 +1,116 @@
+use sqlite::Value;
+
+use mithril_persistence::sqlite::{Query, SourceAlias, SqLiteEntity, WhereCondition};
+
+use crate::database::record::EpochSettingsRecord;
+
+/// Query to update [EpochSettingsRecord] in the sqlite database
+pub struct InsertOrIgnoreEpochSettingsQuery {
+ condition: WhereCondition,
+}
+
+impl InsertOrIgnoreEpochSettingsQuery {
+ pub fn one(epoch_settings: EpochSettingsRecord) -> Self {
+ Self {
+ condition: WhereCondition::new(
+ "(epoch_setting_id, protocol_parameters, cardano_transactions_signing_config) values (?1, ?2, ?3)",
+ vec![
+ Value::Integer(*epoch_settings.epoch_settings_id as i64),
+ Value::String(
+ serde_json::to_string(&epoch_settings.protocol_parameters).unwrap(),
+ ),
+ Value::String(
+ serde_json::to_string(&epoch_settings.cardano_transactions_signing_config)
+ .unwrap(),
+ ),
+ ],
+ ),
+ }
+ }
+}
+
+impl Query for InsertOrIgnoreEpochSettingsQuery {
+ type Entity = EpochSettingsRecord;
+
+ fn filters(&self) -> WhereCondition {
+ self.condition.clone()
+ }
+
+ fn get_definition(&self, condition: &str) -> String {
+ // it is important to alias the fields with the same name as the table
+ // since the table cannot be aliased in a RETURNING statement in SQLite.
+ let projection = Self::Entity::get_projection()
+ .expand(SourceAlias::new(&[("{:epoch_setting:}", "epoch_setting")]));
+
+ format!("insert or ignore into epoch_setting {condition} returning {projection}")
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use mithril_common::entities::{BlockNumber, CardanoTransactionsSigningConfig, Epoch};
+ use mithril_common::test::double::fake_data;
+ use mithril_persistence::sqlite::ConnectionExtensions;
+
+ use crate::database::query::GetEpochSettingsQuery;
+ use crate::database::test_helper::main_db_connection;
+
+ use super::*;
+
+ #[test]
+ fn test_insert_epoch_setting_in_empty_db() {
+ let connection = main_db_connection().unwrap();
+
+ let expected_epoch_settings = EpochSettingsRecord {
+ epoch_settings_id: Epoch(3),
+ protocol_parameters: fake_data::protocol_parameters(),
+ cardano_transactions_signing_config: CardanoTransactionsSigningConfig {
+ security_parameter: BlockNumber(24),
+ step: BlockNumber(62),
+ },
+ };
+ let record = connection
+ .fetch_first(InsertOrIgnoreEpochSettingsQuery::one(
+ expected_epoch_settings.clone(),
+ ))
+ .unwrap();
+
+ assert_eq!(Some(expected_epoch_settings), record);
+ }
+
+ #[test]
+ fn test_cant_replace_existing_value() {
+ let connection = main_db_connection().unwrap();
+
+ let expected_epoch_settings = EpochSettingsRecord {
+ epoch_settings_id: Epoch(3),
+ protocol_parameters: fake_data::protocol_parameters(),
+ cardano_transactions_signing_config: CardanoTransactionsSigningConfig {
+ security_parameter: BlockNumber(24),
+ step: BlockNumber(62),
+ },
+ };
+ let record = connection
+ .fetch_first(InsertOrIgnoreEpochSettingsQuery::one(
+ expected_epoch_settings.clone(),
+ ))
+ .unwrap();
+ assert!(record.is_some());
+
+ let record = connection
+ .fetch_first(InsertOrIgnoreEpochSettingsQuery::one(EpochSettingsRecord {
+ cardano_transactions_signing_config: CardanoTransactionsSigningConfig {
+ security_parameter: BlockNumber(134),
+ step: BlockNumber(872),
+ },
+ ..expected_epoch_settings.clone()
+ }))
+ .unwrap();
+ assert!(record.is_none());
+
+ let record_in_db = connection
+ .fetch_first(GetEpochSettingsQuery::by_epoch(Epoch(3)).unwrap())
+ .unwrap();
+ assert_eq!(Some(expected_epoch_settings), record_in_db);
+ }
+}
diff --git a/mithril-aggregator/src/database/query/epoch_settings/mod.rs b/mithril-aggregator/src/database/query/epoch_settings/mod.rs
index 8ff7fb12e7d..e45403ee09d 100644
--- a/mithril-aggregator/src/database/query/epoch_settings/mod.rs
+++ b/mithril-aggregator/src/database/query/epoch_settings/mod.rs
@@ -1,7 +1,7 @@
mod delete_epoch_settings;
mod get_epoch_settings;
-mod update_epoch_settings;
+mod insert_or_ignore_epoch_settings;
pub use delete_epoch_settings::*;
pub use get_epoch_settings::*;
-pub use update_epoch_settings::*;
+pub use insert_or_ignore_epoch_settings::*;
diff --git a/mithril-aggregator/src/database/query/epoch_settings/update_epoch_settings.rs b/mithril-aggregator/src/database/query/epoch_settings/update_epoch_settings.rs
deleted file mode 100644
index d21c1312059..00000000000
--- a/mithril-aggregator/src/database/query/epoch_settings/update_epoch_settings.rs
+++ /dev/null
@@ -1,103 +0,0 @@
-use sqlite::Value;
-
-use mithril_common::entities::Epoch;
-use mithril_persistence::sqlite::{Query, SourceAlias, SqLiteEntity, WhereCondition};
-
-use crate::database::record::EpochSettingsRecord;
-use crate::entities::AggregatorEpochSettings;
-
-/// Query to update [EpochSettingsRecord] in the sqlite database
-pub struct UpdateEpochSettingsQuery {
- condition: WhereCondition,
-}
-
-impl UpdateEpochSettingsQuery {
- pub fn one(epoch: Epoch, epoch_settings: AggregatorEpochSettings) -> Self {
- let epoch_settings_id: i64 = epoch.try_into().unwrap();
-
- Self {
- condition: WhereCondition::new(
- "(epoch_setting_id, protocol_parameters, cardano_transactions_signing_config) values (?1, ?2, ?3)",
- vec![
- Value::Integer(epoch_settings_id),
- Value::String(
- serde_json::to_string(&epoch_settings.protocol_parameters).unwrap(),
- ),
- Value::String(
- serde_json::to_string(&epoch_settings.cardano_transactions_signing_config)
- .unwrap(),
- ),
- ],
- ),
- }
- }
-}
-
-impl Query for UpdateEpochSettingsQuery {
- type Entity = EpochSettingsRecord;
-
- fn filters(&self) -> WhereCondition {
- self.condition.clone()
- }
-
- fn get_definition(&self, condition: &str) -> String {
- // it is important to alias the fields with the same name as the table
- // since the table cannot be aliased in a RETURNING statement in SQLite.
- let projection = Self::Entity::get_projection()
- .expand(SourceAlias::new(&[("{:epoch_setting:}", "epoch_setting")]));
-
- format!("insert or replace into epoch_setting {condition} returning {projection}")
- }
-}
-
-#[cfg(test)]
-mod tests {
- use mithril_common::entities::{BlockNumber, CardanoTransactionsSigningConfig};
- use mithril_common::test::double::fake_data;
- use mithril_persistence::sqlite::ConnectionExtensions;
-
- use crate::database::query::GetEpochSettingsQuery;
- use crate::database::test_helper::{insert_epoch_settings, main_db_connection};
-
- use super::*;
-
- #[test]
- fn test_update_epoch_settings() {
- let connection = main_db_connection().unwrap();
- insert_epoch_settings(&connection, &[*Epoch(3)]).unwrap();
-
- let epoch_settings_send_to_update = AggregatorEpochSettings {
- protocol_parameters: fake_data::protocol_parameters(),
- cardano_transactions_signing_config: CardanoTransactionsSigningConfig {
- security_parameter: BlockNumber(24),
- step: BlockNumber(62),
- },
- };
- let record_returned_by_update_query = connection
- .fetch_first(UpdateEpochSettingsQuery::one(
- Epoch(3),
- epoch_settings_send_to_update.clone(),
- ))
- .unwrap()
- .unwrap();
-
- assert_eq!(Epoch(3), record_returned_by_update_query.epoch_settings_id);
- assert_eq!(
- epoch_settings_send_to_update.protocol_parameters,
- record_returned_by_update_query.protocol_parameters
- );
- assert_eq!(
- epoch_settings_send_to_update.cardano_transactions_signing_config,
- record_returned_by_update_query.cardano_transactions_signing_config
- );
-
- let mut cursor = connection
- .fetch(GetEpochSettingsQuery::by_epoch(Epoch(3)).unwrap())
- .unwrap();
- let epoch_settings_record =
- cursor.next().expect("Should have an epoch settings for epoch 3.");
-
- assert_eq!(record_returned_by_update_query, epoch_settings_record);
- assert_eq!(0, cursor.count());
- }
-}
diff --git a/mithril-aggregator/src/database/record/epoch_settings.rs b/mithril-aggregator/src/database/record/epoch_settings.rs
index 21cc605742a..bf9b271e2ea 100644
--- a/mithril-aggregator/src/database/record/epoch_settings.rs
+++ b/mithril-aggregator/src/database/record/epoch_settings.rs
@@ -4,7 +4,7 @@ use mithril_persistence::sqlite::{HydrationError, Projection, SqLiteEntity};
use crate::entities::AggregatorEpochSettings;
/// Settings for an epoch, including the protocol parameters.
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Clone)]
pub struct EpochSettingsRecord {
/// Epoch settings id, i.e. the epoch number.
pub epoch_settings_id: Epoch,
diff --git a/mithril-aggregator/src/database/repository/epoch_settings_store.rs b/mithril-aggregator/src/database/repository/epoch_settings_store.rs
index 8949657149a..28defe049e9 100644
--- a/mithril-aggregator/src/database/repository/epoch_settings_store.rs
+++ b/mithril-aggregator/src/database/repository/epoch_settings_store.rs
@@ -8,8 +8,9 @@ use mithril_common::entities::{Epoch, ProtocolParameters};
use mithril_persistence::sqlite::{ConnectionExtensions, SqliteConnection};
use crate::database::query::{
- DeleteEpochSettingsQuery, GetEpochSettingsQuery, UpdateEpochSettingsQuery,
+ DeleteEpochSettingsQuery, GetEpochSettingsQuery, InsertOrIgnoreEpochSettingsQuery,
};
+use crate::database::record::EpochSettingsRecord;
use crate::entities::AggregatorEpochSettings;
use crate::services::EpochPruningTask;
use crate::{EpochSettingsStorer, ProtocolParametersRetriever};
@@ -50,13 +51,17 @@ impl EpochSettingsStorer for EpochSettingsStore {
epoch: Epoch,
epoch_settings: AggregatorEpochSettings,
) -> StdResult