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            },
54        );
55
56        Ok(MithrilNetworkConfigurationForEpoch {
57            enabled_signed_entity_types: self.allowed_discriminants.clone(),
58            protocol_parameters: epoch_settings.protocol_parameters,
59            signed_entity_types_config: SignedEntityTypeConfiguration {
60                cardano_transactions: epoch_settings.cardano_transactions_signing_config,
61            },
62        })
63    }
64}
65
66#[async_trait]
67impl MithrilNetworkConfigurationProvider for LocalMithrilNetworkConfigurationProvider {
68    async fn get_network_configuration(
69        &self,
70        epoch: Epoch,
71    ) -> StdResult<MithrilNetworkConfiguration> {
72        let aggregation_epoch =
73            epoch.offset_to_signer_retrieval_epoch().with_context(|| {
74                format!("MithrilNetworkConfigurationProvider could not compute aggregation epoch from epoch: {epoch}")
75            })?;
76        let next_aggregation_epoch = epoch.offset_to_next_signer_retrieval_epoch();
77        let registration_epoch = epoch.offset_to_next_signer_retrieval_epoch().next();
78
79        let configuration_for_aggregation =
80            self.get_stored_configuration_or_fallback(aggregation_epoch).await?;
81        let configuration_for_next_aggregation = self
82            .get_stored_configuration_or_fallback(next_aggregation_epoch)
83            .await?;
84        let configuration_for_registration =
85            self.get_stored_configuration_or_fallback(registration_epoch).await?;
86
87        let config = MithrilNetworkConfiguration {
88            epoch,
89            configuration_for_aggregation,
90            configuration_for_next_aggregation,
91            configuration_for_registration,
92        };
93        Ok(config)
94    }
95}
96
97#[cfg(test)]
98mod tests {
99    use mithril_common::{
100        entities::{BlockNumber, CardanoTransactionsSigningConfig, ProtocolParameters},
101        test::double::Dummy,
102    };
103
104    use crate::store::FakeEpochSettingsStorer;
105
106    use super::*;
107
108    #[tokio::test]
109    async fn get_stored_configuration_with_stored_value_returns_them() {
110        let local_configuration_epoch_settings = AggregatorEpochSettings {
111            protocol_parameters: ProtocolParameters::new(2000, 200, 0.2),
112            ..Dummy::dummy()
113        };
114        let stored_epoch_settings = AggregatorEpochSettings {
115            protocol_parameters: ProtocolParameters::new(1000, 100, 0.1),
116            ..Dummy::dummy()
117        };
118
119        let local_provider = LocalMithrilNetworkConfigurationProvider::new(
120            local_configuration_epoch_settings,
121            SignedEntityTypeDiscriminants::all(),
122            Arc::new(FakeEpochSettingsStorer::new(vec![(
123                Epoch(42),
124                stored_epoch_settings.clone(),
125            )])),
126        );
127
128        let network_configuration = local_provider
129            .get_stored_configuration_or_fallback(Epoch(42))
130            .await
131            .unwrap();
132
133        assert_eq!(
134            stored_epoch_settings.protocol_parameters,
135            network_configuration.protocol_parameters
136        )
137    }
138
139    #[tokio::test]
140    async fn get_stored_configuration_without_stored_value_fallback_to_configuration_value() {
141        let local_configuration_epoch_settings = AggregatorEpochSettings {
142            protocol_parameters: ProtocolParameters::new(2000, 200, 0.2),
143            ..Dummy::dummy()
144        };
145
146        let local_provider = LocalMithrilNetworkConfigurationProvider::new(
147            local_configuration_epoch_settings.clone(),
148            SignedEntityTypeDiscriminants::all(),
149            Arc::new(FakeEpochSettingsStorer::new(vec![])),
150        );
151
152        let network_configuration = local_provider
153            .get_stored_configuration_or_fallback(Epoch(42))
154            .await
155            .unwrap();
156
157        assert_eq!(
158            local_configuration_epoch_settings.protocol_parameters,
159            network_configuration.protocol_parameters
160        )
161    }
162
163    #[tokio::test]
164    async fn test_get_network_configuration_retrieve_configurations_for_aggregation_next_aggregation_and_registration()
165     {
166        let local_configuration_epoch_settings = AggregatorEpochSettings {
167            protocol_parameters: ProtocolParameters::new(3000, 300, 0.3),
168            cardano_transactions_signing_config: Some(CardanoTransactionsSigningConfig {
169                security_parameter: BlockNumber(3),
170                step: BlockNumber(30),
171            }),
172        };
173
174        // Nothing stored at 44, should fallback to configuration
175        let local_provider = LocalMithrilNetworkConfigurationProvider::new(
176            local_configuration_epoch_settings,
177            SignedEntityTypeDiscriminants::all(),
178            Arc::new(FakeEpochSettingsStorer::new(vec![
179                (
180                    Epoch(42),
181                    AggregatorEpochSettings {
182                        protocol_parameters: ProtocolParameters::new(1000, 100, 0.1),
183                        cardano_transactions_signing_config: Some(
184                            CardanoTransactionsSigningConfig {
185                                security_parameter: BlockNumber(1),
186                                step: BlockNumber(10),
187                            },
188                        ),
189                    },
190                ),
191                (
192                    Epoch(43),
193                    AggregatorEpochSettings {
194                        protocol_parameters: ProtocolParameters::new(2000, 200, 0.2),
195                        cardano_transactions_signing_config: Some(
196                            CardanoTransactionsSigningConfig {
197                                security_parameter: BlockNumber(2),
198                                step: BlockNumber(20),
199                            },
200                        ),
201                    },
202                ),
203            ])),
204        );
205
206        let configuration = local_provider.get_network_configuration(Epoch(43)).await.unwrap();
207
208        assert_eq!(Epoch(43), configuration.epoch);
209
210        assert_eq!(
211            MithrilNetworkConfigurationForEpoch {
212                protocol_parameters: ProtocolParameters::new(1000, 100, 0.1),
213                enabled_signed_entity_types: SignedEntityTypeDiscriminants::all(),
214                signed_entity_types_config: SignedEntityTypeConfiguration {
215                    cardano_transactions: Some(CardanoTransactionsSigningConfig {
216                        security_parameter: BlockNumber(1),
217                        step: BlockNumber(10),
218                    }),
219                },
220            },
221            configuration.configuration_for_aggregation
222        );
223
224        assert_eq!(
225            MithrilNetworkConfigurationForEpoch {
226                protocol_parameters: ProtocolParameters::new(2000, 200, 0.2),
227                enabled_signed_entity_types: SignedEntityTypeDiscriminants::all(),
228                signed_entity_types_config: SignedEntityTypeConfiguration {
229                    cardano_transactions: Some(CardanoTransactionsSigningConfig {
230                        security_parameter: BlockNumber(2),
231                        step: BlockNumber(20),
232                    }),
233                },
234            },
235            configuration.configuration_for_next_aggregation
236        );
237
238        assert_eq!(
239            MithrilNetworkConfigurationForEpoch {
240                protocol_parameters: ProtocolParameters::new(3000, 300, 0.3),
241                enabled_signed_entity_types: SignedEntityTypeDiscriminants::all(),
242                signed_entity_types_config: SignedEntityTypeConfiguration {
243                    cardano_transactions: Some(CardanoTransactionsSigningConfig {
244                        security_parameter: BlockNumber(3),
245                        step: BlockNumber(30),
246                    }),
247                },
248            },
249            configuration.configuration_for_registration
250        );
251    }
252}