use std::sync::Arc;
use tokio::sync::RwLock;
use mithril_common::{
api_version::APIVersionProvider,
cardano_block_scanner::BlockScanner,
certificate_chain::CertificateVerifier,
chain_observer::ChainObserver,
crypto_helper::ProtocolGenesisVerifier,
digesters::{ImmutableDigester, ImmutableFileObserver},
entities::{Epoch, ProtocolParameters, SignerWithStake, StakeDistribution},
era::{EraChecker, EraReader},
signable_builder::SignableBuilderService,
test_utils::MithrilFixture,
TimePointProvider,
};
use mithril_persistence::{sqlite::SqliteConnection, store::StakeStorer};
use crate::{
configuration::*,
database::repository::{
CertificateRepository, OpenMessageRepository, SignedEntityStorer, SignerGetter,
StakePoolStore,
},
event_store::{EventMessage, TransmitterService},
multi_signer::MultiSigner,
services::{
CertifierService, EpochService, MessageService, ProverService, SignedEntityService,
StakeDistributionService, TickerService, TransactionStore,
},
signer_registerer::SignerRecorder,
snapshot_uploaders::SnapshotUploader,
CertificatePendingStore, ProtocolParametersStorer, SignerRegisterer,
SignerRegistrationRoundOpener, Snapshotter, VerificationKeyStorer,
};
pub type MultiSignerWrapper = Arc<RwLock<dyn MultiSigner>>;
pub type EpochServiceWrapper = Arc<RwLock<dyn EpochService>>;
pub struct DependencyContainer {
pub config: Configuration,
pub sqlite_connection: Arc<SqliteConnection>,
pub sqlite_connection_transaction: Arc<SqliteConnection>,
pub stake_store: Arc<StakePoolStore>,
pub snapshot_uploader: Arc<dyn SnapshotUploader>,
pub multi_signer: MultiSignerWrapper,
pub certificate_pending_store: Arc<CertificatePendingStore>,
pub certificate_repository: Arc<CertificateRepository>,
pub open_message_repository: Arc<OpenMessageRepository>,
pub verification_key_store: Arc<dyn VerificationKeyStorer>,
pub protocol_parameters_store: Arc<dyn ProtocolParametersStorer>,
pub chain_observer: Arc<dyn ChainObserver>,
pub time_point_provider: Arc<dyn TimePointProvider>,
pub transaction_store: Arc<dyn TransactionStore>,
pub block_scanner: Arc<dyn BlockScanner>,
pub immutable_file_observer: Arc<dyn ImmutableFileObserver>,
pub digester: Arc<dyn ImmutableDigester>,
pub snapshotter: Arc<dyn Snapshotter>,
pub certificate_verifier: Arc<dyn CertificateVerifier>,
pub genesis_verifier: Arc<ProtocolGenesisVerifier>,
pub signer_registerer: Arc<dyn SignerRegisterer>,
pub signer_registration_round_opener: Arc<dyn SignerRegistrationRoundOpener>,
pub era_checker: Arc<EraChecker>,
pub era_reader: Arc<EraReader>,
pub event_transmitter: Arc<TransmitterService<EventMessage>>,
pub api_version_provider: Arc<APIVersionProvider>,
pub stake_distribution_service: Arc<dyn StakeDistributionService>,
pub signer_recorder: Arc<dyn SignerRecorder>,
pub signable_builder_service: Arc<dyn SignableBuilderService>,
pub signed_entity_service: Arc<dyn SignedEntityService>,
pub certifier_service: Arc<dyn CertifierService>,
pub epoch_service: EpochServiceWrapper,
pub ticker_service: Arc<dyn TickerService>,
pub signed_entity_storer: Arc<dyn SignedEntityStorer>,
pub signer_getter: Arc<dyn SignerGetter>,
pub message_service: Arc<dyn MessageService>,
pub prover_service: Arc<dyn ProverService>,
}
#[doc(hidden)]
impl DependencyContainer {
pub async fn get_genesis_epochs(&self) -> (Epoch, Epoch) {
let current_epoch = self
.chain_observer
.get_current_epoch()
.await
.expect("get_current_epoch should not fail")
.expect("an epoch should've been set to the chain observer");
let work_epoch = current_epoch
.offset_to_signer_retrieval_epoch()
.expect("epoch.offset_by SIGNER_EPOCH_RETRIEVAL_OFFSET should not fail");
let epoch_to_sign = current_epoch.offset_to_next_signer_retrieval_epoch();
(work_epoch, epoch_to_sign)
}
pub async fn init_state_from_fixture(&self, fixture: &MithrilFixture, target_epochs: &[Epoch]) {
for epoch in target_epochs {
self.protocol_parameters_store
.save_protocol_parameters(*epoch, fixture.protocol_parameters())
.await
.expect("save_protocol_parameters should not fail");
self.fill_verification_key_store(*epoch, &fixture.signers_with_stake())
.await;
self.fill_stakes_store(*epoch, fixture.signers_with_stake())
.await;
}
}
pub async fn prepare_for_genesis(
&self,
genesis_signers: Vec<SignerWithStake>,
second_epoch_signers: Vec<SignerWithStake>,
genesis_protocol_parameters: &ProtocolParameters,
) {
self.init_protocol_parameter_store(genesis_protocol_parameters)
.await;
let (work_epoch, epoch_to_sign) = self.get_genesis_epochs().await;
for (epoch, signers) in [
(work_epoch, genesis_signers),
(epoch_to_sign, second_epoch_signers),
] {
self.fill_verification_key_store(epoch, &signers).await;
self.fill_stakes_store(epoch, signers).await;
}
}
pub async fn init_protocol_parameter_store(&self, protocol_parameters: &ProtocolParameters) {
let (work_epoch, epoch_to_sign) = self.get_genesis_epochs().await;
let mut epochs_to_save = Vec::new();
epochs_to_save.push(work_epoch);
epochs_to_save.push(epoch_to_sign);
epochs_to_save.push(epoch_to_sign.next());
for epoch in epochs_to_save {
self.protocol_parameters_store
.save_protocol_parameters(epoch, protocol_parameters.clone())
.await
.expect("save_protocol_parameters should not fail");
}
}
async fn fill_verification_key_store(&self, target_epoch: Epoch, signers: &[SignerWithStake]) {
for signer in signers {
self.signer_recorder
.record_signer_registration(signer.party_id.clone())
.await
.expect("record_signer_registration should not fail");
self.verification_key_store
.save_verification_key(target_epoch, signer.clone())
.await
.expect("save_verification_key should not fail");
}
}
async fn fill_stakes_store(&self, target_epoch: Epoch, signers: Vec<SignerWithStake>) {
let _ = self
.stake_store
.save_stakes(
target_epoch,
signers
.iter()
.map(|s| s.into())
.collect::<StakeDistribution>(),
)
.await
.expect("save_stakes should not fail");
}
}
#[cfg(test)]
pub mod tests {
use crate::{dependency_injection::DependenciesBuilder, Configuration, DependencyContainer};
pub async fn initialize_dependencies() -> DependencyContainer {
let config = Configuration::new_sample();
let mut builder = DependenciesBuilder::new(config);
builder.build_dependency_container().await.unwrap()
}
}