mithril_aggregator/dependency_injection/containers/
serve.rs

1use slog::Logger;
2use std::sync::Arc;
3use tokio::sync::RwLock;
4
5use mithril_cardano_node_chain::chain_observer::ChainObserver;
6use mithril_common::{
7    api_version::APIVersionProvider,
8    entities::{
9        CardanoTransactionsSigningConfig, Epoch, ProtocolParameters, SignerWithStake,
10        StakeDistribution,
11    },
12    signable_builder::SignableBuilderService,
13    test::builder::MithrilFixture,
14};
15
16use mithril_era::{EraChecker, EraReader};
17use mithril_persistence::store::StakeStorer;
18use mithril_signed_entity_lock::SignedEntityTypeLock;
19use mithril_ticker::TickerService;
20
21use crate::{
22    EpochSettingsStorer, MetricsService, SignerRegisterer, SignerRegistrationRoundOpener,
23    SingleSignatureAuthenticator, VerificationKeyStorer,
24    database::repository::{
25        CertificateRepository, SignedEntityStorer, SignerGetter, StakePoolStore,
26    },
27    entities::AggregatorEpochSettings,
28    event_store::{EventMessage, TransmitterService},
29    services::{
30        CertificateChainSynchronizer, CertifierService, EpochService, MessageService,
31        ProverService, SignedEntityService, SignerRecorder, SignerSynchronizer,
32        StakeDistributionService, UpkeepService,
33    },
34};
35
36/// EpochServiceWrapper wraps
37pub type EpochServiceWrapper = Arc<RwLock<dyn EpochService>>;
38
39/// Dependencies container for the serve command
40pub struct ServeCommandDependenciesContainer {
41    /// Application root logger
42    pub(crate) root_logger: Logger,
43
44    /// Stake Store used by the StakeDistributionService
45    /// It shall be a private dependency.
46    pub(crate) stake_store: Arc<StakePoolStore>,
47
48    /// It shall be a private dependency.
49    /// Certificate store.
50    pub certificate_repository: Arc<CertificateRepository>,
51
52    /// Verification key store.
53    pub verification_key_store: Arc<dyn VerificationKeyStorer>,
54
55    /// Epoch settings storer.
56    pub epoch_settings_storer: Arc<dyn EpochSettingsStorer>,
57
58    /// Chain observer service.
59    pub(crate) chain_observer: Arc<dyn ChainObserver>,
60
61    /// Certificate chain synchronizer service
62    pub(crate) certificate_chain_synchronizer: Arc<dyn CertificateChainSynchronizer>,
63
64    /// Signer registerer service
65    pub signer_registerer: Arc<dyn SignerRegisterer>,
66
67    /// Signer synchronizer service
68    pub(crate) signer_synchronizer: Arc<dyn SignerSynchronizer>,
69
70    /// Signer registration round opener service
71    pub(crate) signer_registration_round_opener: Arc<dyn SignerRegistrationRoundOpener>,
72
73    /// Era checker service
74    pub(crate) era_checker: Arc<EraChecker>,
75
76    /// Era reader service
77    pub(crate) era_reader: Arc<EraReader>,
78
79    /// Event Transmitter Service
80    pub(crate) event_transmitter: Arc<TransmitterService<EventMessage>>,
81
82    /// API Version provider
83    pub(crate) api_version_provider: Arc<APIVersionProvider>,
84
85    /// Stake Distribution Service
86    pub(crate) stake_distribution_service: Arc<dyn StakeDistributionService>,
87
88    /// Signer Recorder
89    pub(crate) signer_recorder: Arc<dyn SignerRecorder>,
90
91    /// Signable Builder Service
92    pub signable_builder_service: Arc<dyn SignableBuilderService>,
93
94    /// Signed Entity Service
95    pub(crate) signed_entity_service: Arc<dyn SignedEntityService>,
96
97    /// Certifier Service
98    pub certifier_service: Arc<dyn CertifierService>,
99
100    /// Epoch service
101    pub(crate) epoch_service: EpochServiceWrapper,
102
103    /// Ticker Service
104    pub(crate) ticker_service: Arc<dyn TickerService>,
105
106    /// Signed Entity storer
107    pub signed_entity_storer: Arc<dyn SignedEntityStorer>,
108
109    /// Signer getter service
110    pub(crate) signer_getter: Arc<dyn SignerGetter>,
111
112    /// HTTP message service
113    pub message_service: Arc<dyn MessageService>,
114
115    /// Prover service
116    pub prover_service: Arc<dyn ProverService>,
117
118    /// Signed Entity Type Lock
119    pub signed_entity_type_lock: Arc<SignedEntityTypeLock>,
120
121    /// Upkeep service
122    pub(crate) upkeep_service: Arc<dyn UpkeepService>,
123
124    /// Single signer authenticator
125    pub(crate) single_signer_authenticator: Arc<SingleSignatureAuthenticator>,
126
127    /// Metrics service
128    pub(crate) metrics_service: Arc<MetricsService>,
129}
130
131#[doc(hidden)]
132impl ServeCommandDependenciesContainer {
133    /// `TEST METHOD ONLY`
134    ///
135    /// Get the first two epochs that will be used by a newly started aggregator
136    pub async fn get_genesis_epochs(&self) -> (Epoch, Epoch) {
137        let current_epoch = self
138            .chain_observer
139            .get_current_epoch()
140            .await
141            .expect("get_current_epoch should not fail")
142            .expect("an epoch should've been set to the chain observer");
143        let work_epoch = current_epoch
144            .offset_to_signer_retrieval_epoch()
145            .expect("epoch.offset_by SIGNER_EPOCH_RETRIEVAL_OFFSET should not fail");
146        let epoch_to_sign = current_epoch.offset_to_next_signer_retrieval_epoch();
147
148        (work_epoch, epoch_to_sign)
149    }
150
151    /// `TEST METHOD ONLY`
152    ///
153    /// Fill the stores of a [DependencyManager] in a way to simulate an aggregator state
154    /// using the data from a precomputed fixture.
155    pub async fn init_state_from_fixture(
156        &self,
157        fixture: &MithrilFixture,
158        cardano_transactions_signing_config: &CardanoTransactionsSigningConfig,
159        target_epochs: &[Epoch],
160    ) {
161        for epoch in target_epochs {
162            self.epoch_settings_storer
163                .save_epoch_settings(
164                    *epoch,
165                    AggregatorEpochSettings {
166                        protocol_parameters: fixture.protocol_parameters(),
167                        cardano_transactions_signing_config: cardano_transactions_signing_config
168                            .clone(),
169                    },
170                )
171                .await
172                .expect("save_epoch_settings should not fail");
173            self.fill_verification_key_store(*epoch, &fixture.signers_with_stake())
174                .await;
175            self.fill_stakes_store(*epoch, fixture.signers_with_stake()).await;
176        }
177    }
178
179    /// `TEST METHOD ONLY`
180    ///
181    /// Fill the stores of a [DependencyManager] in a way to simulate an aggregator genesis state.
182    ///
183    /// For the current and the next epoch:
184    /// * Fill the [VerificationKeyStorer] with the given signers keys.
185    /// * Fill the [StakeStore] with the given signers stakes.
186    /// * Fill the [ProtocolParametersStore] with the given parameters.
187    pub async fn prepare_for_genesis(
188        &self,
189        genesis_signers: Vec<SignerWithStake>,
190        second_epoch_signers: Vec<SignerWithStake>,
191        genesis_protocol_parameters: &ProtocolParameters,
192        cardano_transactions_signing_config: &CardanoTransactionsSigningConfig,
193    ) {
194        self.init_epoch_settings_storer(&AggregatorEpochSettings {
195            protocol_parameters: genesis_protocol_parameters.clone(),
196            cardano_transactions_signing_config: cardano_transactions_signing_config.clone(),
197        })
198        .await;
199
200        let (work_epoch, epoch_to_sign) = self.get_genesis_epochs().await;
201        for (epoch, signers) in
202            [(work_epoch, genesis_signers), (epoch_to_sign, second_epoch_signers)]
203        {
204            self.fill_verification_key_store(epoch, &signers).await;
205            self.fill_stakes_store(epoch, signers).await;
206        }
207    }
208
209    /// `TEST METHOD ONLY`
210    ///
211    /// Fill up to the first three epochs of the [EpochSettingsStorer] with the given value.
212    pub async fn init_epoch_settings_storer(&self, epoch_settings: &AggregatorEpochSettings) {
213        let (work_epoch, epoch_to_sign) = self.get_genesis_epochs().await;
214        let mut epochs_to_save = Vec::new();
215        epochs_to_save.push(work_epoch);
216        epochs_to_save.push(epoch_to_sign);
217        epochs_to_save.push(epoch_to_sign.next());
218        for epoch in epochs_to_save {
219            self.epoch_settings_storer
220                .save_epoch_settings(epoch, epoch_settings.clone())
221                .await
222                .expect("save_epoch_settings should not fail");
223        }
224    }
225
226    async fn fill_verification_key_store(&self, target_epoch: Epoch, signers: &[SignerWithStake]) {
227        for signer in signers {
228            self.signer_recorder
229                .record_signer_registration(signer.party_id.clone())
230                .await
231                .expect("record_signer_registration should not fail");
232            self.verification_key_store
233                .save_verification_key(target_epoch, signer.clone())
234                .await
235                .expect("save_verification_key should not fail");
236        }
237    }
238
239    async fn fill_stakes_store(&self, target_epoch: Epoch, signers: Vec<SignerWithStake>) {
240        let _ = self
241            .stake_store
242            .save_stakes(
243                target_epoch,
244                signers.iter().map(|s| s.into()).collect::<StakeDistribution>(),
245            )
246            .await
247            .expect("save_stakes should not fail");
248    }
249}
250
251#[cfg(test)]
252pub(crate) mod tests {
253
254    use std::{path::PathBuf, sync::Arc};
255
256    use crate::{
257        ServeCommandConfiguration, ServeCommandDependenciesContainer,
258        dependency_injection::DependenciesBuilder,
259    };
260
261    /// Initialize dependency container with a unique temporary snapshot directory build from test path.
262    /// This macro should used directly in a function test to be able to retrieve the function name.
263    #[macro_export]
264    macro_rules! initialize_dependencies {
265        () => {{ initialize_dependencies(mithril_common::temp_dir!()) }};
266    }
267
268    pub async fn initialize_dependencies(tmp_path: PathBuf) -> ServeCommandDependenciesContainer {
269        let config = ServeCommandConfiguration::new_sample(tmp_path);
270
271        let mut builder = DependenciesBuilder::new_with_stdout_logger(Arc::new(config));
272
273        builder.build_serve_dependencies_container().await.unwrap()
274    }
275}