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: Some(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: 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: CardanoTransactionsSigningConfig {
184                            security_parameter: BlockNumber(1),
185                            step: BlockNumber(10),
186                        },
187                    },
188                ),
189                (
190                    Epoch(43),
191                    AggregatorEpochSettings {
192                        protocol_parameters: ProtocolParameters::new(2000, 200, 0.2),
193                        cardano_transactions_signing_config: CardanoTransactionsSigningConfig {
194                            security_parameter: BlockNumber(2),
195                            step: BlockNumber(20),
196                        },
197                    },
198                ),
199            ])),
200        );
201
202        let configuration = local_provider.get_network_configuration(Epoch(43)).await.unwrap();
203
204        assert_eq!(Epoch(43), configuration.epoch);
205
206        assert_eq!(
207            MithrilNetworkConfigurationForEpoch {
208                protocol_parameters: ProtocolParameters::new(1000, 100, 0.1),
209                enabled_signed_entity_types: SignedEntityTypeDiscriminants::all(),
210                signed_entity_types_config: SignedEntityTypeConfiguration {
211                    cardano_transactions: Some(CardanoTransactionsSigningConfig {
212                        security_parameter: BlockNumber(1),
213                        step: BlockNumber(10),
214                    }),
215                },
216            },
217            configuration.configuration_for_aggregation
218        );
219
220        assert_eq!(
221            MithrilNetworkConfigurationForEpoch {
222                protocol_parameters: ProtocolParameters::new(2000, 200, 0.2),
223                enabled_signed_entity_types: SignedEntityTypeDiscriminants::all(),
224                signed_entity_types_config: SignedEntityTypeConfiguration {
225                    cardano_transactions: Some(CardanoTransactionsSigningConfig {
226                        security_parameter: BlockNumber(2),
227                        step: BlockNumber(20),
228                    }),
229                },
230            },
231            configuration.configuration_for_next_aggregation
232        );
233
234        assert_eq!(
235            MithrilNetworkConfigurationForEpoch {
236                protocol_parameters: ProtocolParameters::new(3000, 300, 0.3),
237                enabled_signed_entity_types: SignedEntityTypeDiscriminants::all(),
238                signed_entity_types_config: SignedEntityTypeConfiguration {
239                    cardano_transactions: Some(CardanoTransactionsSigningConfig {
240                        security_parameter: BlockNumber(3),
241                        step: BlockNumber(30),
242                    }),
243                },
244            },
245            configuration.configuration_for_registration
246        );
247    }
248}