mithril_aggregator/services/
network_configuration_provider.rs

1use anyhow::Context;
2use async_trait::async_trait;
3use std::collections::BTreeSet;
4use std::sync::Arc;
5
6use mithril_common::StdResult;
7use mithril_common::entities::{Epoch, SignedEntityTypeDiscriminants};
8use mithril_protocol_config::interface::MithrilNetworkConfigurationProvider;
9use mithril_protocol_config::model::{
10    MithrilNetworkConfiguration, MithrilNetworkConfigurationForEpoch, SignedEntityTypeConfiguration,
11};
12
13use crate::EpochSettingsStorer;
14use crate::entities::AggregatorEpochSettings;
15
16/// Read network configuration from the database epoch_settings or, if no records is available for
17/// an epoch, fallback to the provided configuration value
18pub struct LocalMithrilNetworkConfigurationProvider {
19    local_configuration_epoch_settings: AggregatorEpochSettings,
20    allowed_discriminants: BTreeSet<SignedEntityTypeDiscriminants>,
21    epoch_settings_store: Arc<dyn EpochSettingsStorer>,
22}
23
24impl LocalMithrilNetworkConfigurationProvider {
25    /// Instantiate a new `LocalMithrilNetworkConfigurationProvider`
26    pub fn new(
27        local_configuration_epoch_settings: AggregatorEpochSettings,
28        allowed_discriminants: BTreeSet<SignedEntityTypeDiscriminants>,
29        epoch_settings_store: Arc<dyn EpochSettingsStorer>,
30    ) -> Self {
31        Self {
32            local_configuration_epoch_settings,
33            allowed_discriminants,
34            epoch_settings_store,
35        }
36    }
37
38    /// Get epoch configuration from store or fallback to local configuration if it does not exists
39    async fn get_stored_configuration_or_fallback(
40        &self,
41        epoch: Epoch,
42    ) -> StdResult<MithrilNetworkConfigurationForEpoch> {
43        let epoch_settings = self.epoch_settings_store.get_epoch_settings(epoch).await?.unwrap_or(
44            AggregatorEpochSettings {
45                protocol_parameters: self
46                    .local_configuration_epoch_settings
47                    .protocol_parameters
48                    .clone(),
49                cardano_transactions_signing_config: self
50                    .local_configuration_epoch_settings
51                    .cardano_transactions_signing_config
52                    .clone(),
53                cardano_blocks_transactions_signing_config: self
54                    .local_configuration_epoch_settings
55                    .cardano_blocks_transactions_signing_config
56                    .clone(),
57            },
58        );
59
60        Ok(MithrilNetworkConfigurationForEpoch {
61            enabled_signed_entity_types: self.allowed_discriminants.clone(),
62            protocol_parameters: epoch_settings.protocol_parameters,
63            signed_entity_types_config: SignedEntityTypeConfiguration {
64                cardano_transactions: epoch_settings.cardano_transactions_signing_config,
65                cardano_blocks_transactions: epoch_settings
66                    .cardano_blocks_transactions_signing_config,
67            },
68        })
69    }
70}
71
72#[async_trait]
73impl MithrilNetworkConfigurationProvider for LocalMithrilNetworkConfigurationProvider {
74    async fn get_network_configuration(
75        &self,
76        epoch: Epoch,
77    ) -> StdResult<MithrilNetworkConfiguration> {
78        let aggregation_epoch =
79            epoch.offset_to_signer_retrieval_epoch().with_context(|| {
80                format!("MithrilNetworkConfigurationProvider could not compute aggregation epoch from epoch: {epoch}")
81            })?;
82        let next_aggregation_epoch = epoch.offset_to_next_signer_retrieval_epoch();
83        let registration_epoch = epoch.offset_to_next_signer_retrieval_epoch().next();
84
85        let configuration_for_aggregation =
86            self.get_stored_configuration_or_fallback(aggregation_epoch).await?;
87        let configuration_for_next_aggregation = self
88            .get_stored_configuration_or_fallback(next_aggregation_epoch)
89            .await?;
90        let configuration_for_registration =
91            self.get_stored_configuration_or_fallback(registration_epoch).await?;
92
93        let config = MithrilNetworkConfiguration {
94            epoch,
95            configuration_for_aggregation,
96            configuration_for_next_aggregation,
97            configuration_for_registration,
98        };
99        Ok(config)
100    }
101}
102
103#[cfg(test)]
104mod tests {
105    use mithril_common::{
106        entities::{
107            BlockNumber, CardanoBlocksTransactionsSigningConfig, CardanoTransactionsSigningConfig,
108            ProtocolParameters,
109        },
110        test::double::Dummy,
111    };
112
113    use crate::store::FakeEpochSettingsStorer;
114
115    use super::*;
116
117    #[tokio::test]
118    async fn get_stored_configuration_with_stored_value_returns_them() {
119        let local_configuration_epoch_settings = AggregatorEpochSettings {
120            protocol_parameters: ProtocolParameters::new(2000, 200, 0.2),
121            ..Dummy::dummy()
122        };
123        let stored_epoch_settings = AggregatorEpochSettings {
124            protocol_parameters: ProtocolParameters::new(1000, 100, 0.1),
125            ..Dummy::dummy()
126        };
127
128        let local_provider = LocalMithrilNetworkConfigurationProvider::new(
129            local_configuration_epoch_settings,
130            SignedEntityTypeDiscriminants::all(),
131            Arc::new(FakeEpochSettingsStorer::new(vec![(
132                Epoch(42),
133                stored_epoch_settings.clone(),
134            )])),
135        );
136
137        let network_configuration = local_provider
138            .get_stored_configuration_or_fallback(Epoch(42))
139            .await
140            .unwrap();
141
142        assert_eq!(
143            stored_epoch_settings.protocol_parameters,
144            network_configuration.protocol_parameters
145        )
146    }
147
148    #[tokio::test]
149    async fn get_stored_configuration_without_stored_value_fallback_to_configuration_value() {
150        let local_configuration_epoch_settings = AggregatorEpochSettings {
151            protocol_parameters: ProtocolParameters::new(2000, 200, 0.2),
152            ..Dummy::dummy()
153        };
154
155        let local_provider = LocalMithrilNetworkConfigurationProvider::new(
156            local_configuration_epoch_settings.clone(),
157            SignedEntityTypeDiscriminants::all(),
158            Arc::new(FakeEpochSettingsStorer::new(vec![])),
159        );
160
161        let network_configuration = local_provider
162            .get_stored_configuration_or_fallback(Epoch(42))
163            .await
164            .unwrap();
165
166        assert_eq!(
167            local_configuration_epoch_settings.protocol_parameters,
168            network_configuration.protocol_parameters
169        )
170    }
171
172    #[tokio::test]
173    async fn test_get_network_configuration_retrieve_configurations_for_aggregation_next_aggregation_and_registration()
174     {
175        let local_configuration_epoch_settings = AggregatorEpochSettings {
176            protocol_parameters: ProtocolParameters::new(3000, 300, 0.3),
177            cardano_transactions_signing_config: Some(CardanoTransactionsSigningConfig {
178                security_parameter: BlockNumber(3),
179                step: BlockNumber(30),
180            }),
181            cardano_blocks_transactions_signing_config: Some(
182                CardanoBlocksTransactionsSigningConfig {
183                    security_parameter: BlockNumber(33),
184                    step: BlockNumber(330),
185                },
186            ),
187        };
188
189        // Nothing stored at 44, should fallback to configuration
190        let local_provider = LocalMithrilNetworkConfigurationProvider::new(
191            local_configuration_epoch_settings,
192            SignedEntityTypeDiscriminants::all(),
193            Arc::new(FakeEpochSettingsStorer::new(vec![
194                (
195                    Epoch(42),
196                    AggregatorEpochSettings {
197                        protocol_parameters: ProtocolParameters::new(1000, 100, 0.1),
198                        cardano_transactions_signing_config: Some(
199                            CardanoTransactionsSigningConfig {
200                                security_parameter: BlockNumber(1),
201                                step: BlockNumber(10),
202                            },
203                        ),
204                        cardano_blocks_transactions_signing_config: Some(
205                            CardanoBlocksTransactionsSigningConfig {
206                                security_parameter: BlockNumber(11),
207                                step: BlockNumber(110),
208                            },
209                        ),
210                    },
211                ),
212                (
213                    Epoch(43),
214                    AggregatorEpochSettings {
215                        protocol_parameters: ProtocolParameters::new(2000, 200, 0.2),
216                        cardano_transactions_signing_config: Some(
217                            CardanoTransactionsSigningConfig {
218                                security_parameter: BlockNumber(2),
219                                step: BlockNumber(20),
220                            },
221                        ),
222                        cardano_blocks_transactions_signing_config: Some(
223                            CardanoBlocksTransactionsSigningConfig {
224                                security_parameter: BlockNumber(22),
225                                step: BlockNumber(220),
226                            },
227                        ),
228                    },
229                ),
230            ])),
231        );
232
233        let configuration = local_provider.get_network_configuration(Epoch(43)).await.unwrap();
234
235        assert_eq!(Epoch(43), configuration.epoch);
236
237        assert_eq!(
238            MithrilNetworkConfigurationForEpoch {
239                protocol_parameters: ProtocolParameters::new(1000, 100, 0.1),
240                enabled_signed_entity_types: SignedEntityTypeDiscriminants::all(),
241                signed_entity_types_config: SignedEntityTypeConfiguration {
242                    cardano_transactions: Some(CardanoTransactionsSigningConfig {
243                        security_parameter: BlockNumber(1),
244                        step: BlockNumber(10),
245                    }),
246                    cardano_blocks_transactions: Some(CardanoBlocksTransactionsSigningConfig {
247                        security_parameter: BlockNumber(11),
248                        step: BlockNumber(110),
249                    },),
250                },
251            },
252            configuration.configuration_for_aggregation
253        );
254
255        assert_eq!(
256            MithrilNetworkConfigurationForEpoch {
257                protocol_parameters: ProtocolParameters::new(2000, 200, 0.2),
258                enabled_signed_entity_types: SignedEntityTypeDiscriminants::all(),
259                signed_entity_types_config: SignedEntityTypeConfiguration {
260                    cardano_transactions: Some(CardanoTransactionsSigningConfig {
261                        security_parameter: BlockNumber(2),
262                        step: BlockNumber(20),
263                    }),
264                    cardano_blocks_transactions: Some(CardanoBlocksTransactionsSigningConfig {
265                        security_parameter: BlockNumber(22),
266                        step: BlockNumber(220),
267                    },),
268                },
269            },
270            configuration.configuration_for_next_aggregation
271        );
272
273        assert_eq!(
274            MithrilNetworkConfigurationForEpoch {
275                protocol_parameters: ProtocolParameters::new(3000, 300, 0.3),
276                enabled_signed_entity_types: SignedEntityTypeDiscriminants::all(),
277                signed_entity_types_config: SignedEntityTypeConfiguration {
278                    cardano_transactions: Some(CardanoTransactionsSigningConfig {
279                        security_parameter: BlockNumber(3),
280                        step: BlockNumber(30),
281                    }),
282                    cardano_blocks_transactions: Some(CardanoBlocksTransactionsSigningConfig {
283                        security_parameter: BlockNumber(33),
284                        step: BlockNumber(330),
285                    },),
286                },
287            },
288            configuration.configuration_for_registration
289        );
290    }
291}