diff --git a/mithril-signer/src/dependency_injection/builder.rs b/mithril-signer/src/dependency_injection/builder.rs index ebc9080deda..fb9458fe61e 100644 --- a/mithril-signer/src/dependency_injection/builder.rs +++ b/mithril-signer/src/dependency_injection/builder.rs @@ -513,7 +513,6 @@ impl<'a> DependenciesBuilder<'a> { let services = SignerDependencyContainer { ticker_service, - certificate_handler: aggregator_client, chain_observer, digester, single_signer, @@ -529,6 +528,8 @@ impl<'a> DependenciesBuilder<'a> { upkeep_service, epoch_service, certifier, + signer_registration_publisher: aggregator_client.clone(), + signers_registration_retriever: aggregator_client, kes_signer, network_configuration_service, }; diff --git a/mithril-signer/src/dependency_injection/containers.rs b/mithril-signer/src/dependency_injection/containers.rs index ce74c456a38..7baba8cddaa 100644 --- a/mithril-signer/src/dependency_injection/containers.rs +++ b/mithril-signer/src/dependency_injection/containers.rs @@ -16,12 +16,12 @@ use mithril_ticker::TickerService; use crate::MetricsService; use crate::services::{ - AggregatorClient, CertifierService, EpochService, SingleSigner, UpkeepService, + CertifierService, EpochService, SignerRegistrationPublisher, SignersRegistrationRetriever, + SingleSigner, UpkeepService, }; use crate::store::ProtocolInitializerStorer; type StakeStoreService = Arc; -type CertificateHandlerService = Arc; type ChainObserverService = Arc; type DigesterService = Arc; type SingleSignerService = Arc; @@ -40,9 +40,6 @@ pub struct SignerDependencyContainer { /// Stake store service pub stake_store: StakeStoreService, - /// Certificate handler service - pub certificate_handler: CertificateHandlerService, - /// Chain Observer service pub chain_observer: ChainObserverService, @@ -85,6 +82,12 @@ pub struct SignerDependencyContainer { /// Certifier service pub certifier: Arc, + /// Signer registration publisher + pub signer_registration_publisher: Arc, + + /// Signers registration retriever + pub signers_registration_retriever: Arc, + /// Kes signer service pub kes_signer: Option>, diff --git a/mithril-signer/src/entities/mod.rs b/mithril-signer/src/entities/mod.rs index d873f48c1d8..75c86ce4807 100644 --- a/mithril-signer/src/entities/mod.rs +++ b/mithril-signer/src/entities/mod.rs @@ -3,7 +3,7 @@ //! This module provide domain entities for the services & state machine. mod beacon_to_sign; -mod signer_epoch_settings; +mod registered_signers; pub use beacon_to_sign::*; -pub use signer_epoch_settings::*; +pub use registered_signers::*; diff --git a/mithril-signer/src/entities/signer_epoch_settings.rs b/mithril-signer/src/entities/registered_signers.rs similarity index 68% rename from mithril-signer/src/entities/signer_epoch_settings.rs rename to mithril-signer/src/entities/registered_signers.rs index a193a8282b6..979114323a7 100644 --- a/mithril-signer/src/entities/signer_epoch_settings.rs +++ b/mithril-signer/src/entities/registered_signers.rs @@ -1,9 +1,9 @@ use mithril_common::entities::{Epoch, Signer}; -/// SignerEpochSettings represents the settings of an epoch +/// `RegisteredSigners` represents the registered signers of an epoch #[derive(Clone, Debug, PartialEq)] -pub struct SignerEpochSettings { - /// Current Epoch +pub struct RegisteredSigners { + /// Epoch for which those registrations are active. pub epoch: Epoch, /// Current Signers @@ -14,9 +14,9 @@ pub struct SignerEpochSettings { } #[cfg(test)] -impl mithril_common::test::double::Dummy for SignerEpochSettings { - /// Create a dummy `SignerEpochSettings` - fn dummy() -> SignerEpochSettings { +impl mithril_common::test::double::Dummy for RegisteredSigners { + /// Create a dummy `RegisteredSigners` + fn dummy() -> RegisteredSigners { use mithril_common::test::double::fake_data; // Beacon @@ -28,7 +28,7 @@ impl mithril_common::test::double::Dummy for SignerEpochSettings { let next_signers = signers[2..5].to_vec(); // Signer Epoch settings - SignerEpochSettings { + RegisteredSigners { epoch: beacon.epoch, current_signers, next_signers, diff --git a/mithril-signer/src/lib.rs b/mithril-signer/src/lib.rs index 3631aaf5e16..734ad170b92 100644 --- a/mithril-signer/src/lib.rs +++ b/mithril-signer/src/lib.rs @@ -19,7 +19,7 @@ pub mod store; pub use commands::*; pub use configuration::{Configuration, DefaultConfiguration}; -pub use entities::SignerEpochSettings; +pub use entities::RegisteredSigners; pub use message_adapters::{FromEpochSettingsAdapter, ToRegisterSignerMessageAdapter}; pub use metrics::*; pub use runtime::*; diff --git a/mithril-signer/src/message_adapters/from_epoch_settings.rs b/mithril-signer/src/message_adapters/from_epoch_settings.rs index 9e3b0b3567d..44798d7db7a 100644 --- a/mithril-signer/src/message_adapters/from_epoch_settings.rs +++ b/mithril-signer/src/message_adapters/from_epoch_settings.rs @@ -4,15 +4,15 @@ use mithril_common::{ messages::{EpochSettingsMessage, SignerMessagePart, TryFromMessageAdapter}, }; -use crate::entities::SignerEpochSettings; +use crate::entities::RegisteredSigners; -/// Adapter to convert [EpochSettingsMessage] to [SignerEpochSettings]. +/// Adapter to convert [EpochSettingsMessage] to [RegisteredSigners]. pub struct FromEpochSettingsAdapter; -impl TryFromMessageAdapter for FromEpochSettingsAdapter { +impl TryFromMessageAdapter for FromEpochSettingsAdapter { /// Method to convert. - fn try_adapt(message: EpochSettingsMessage) -> StdResult { - let epoch_settings = SignerEpochSettings { + fn try_adapt(message: EpochSettingsMessage) -> StdResult { + let epoch_settings = RegisteredSigners { epoch: message.epoch, current_signers: SignerMessagePart::try_into_signers(message.current_signers) .with_context(|| "'FromMessageAdapter' can not convert the current signers")?, diff --git a/mithril-signer/src/runtime/runner.rs b/mithril-signer/src/runtime/runner.rs index a3390e9332e..234b0d4fca9 100644 --- a/mithril-signer/src/runtime/runner.rs +++ b/mithril-signer/src/runtime/runner.rs @@ -14,7 +14,7 @@ use mithril_protocol_config::model::MithrilNetworkConfiguration; use crate::Configuration; use crate::dependency_injection::SignerDependencyContainer; -use crate::entities::{BeaconToSign, SignerEpochSettings}; +use crate::entities::{BeaconToSign, RegisteredSigners}; use crate::services::{EpochService, MithrilProtocolInitializerBuilder}; /// This trait is mainly intended for mocking. @@ -29,7 +29,7 @@ pub trait Runner: Send + Sync { /// Fetch the current epoch settings if any. async fn get_signer_registrations_from_aggregator( &self, - ) -> StdResult>; + ) -> StdResult>; /// Fetch the beacon to sign if any. async fn get_beacon_to_sign(&self, time_point: TimePoint) -> StdResult>; @@ -131,10 +131,13 @@ impl Runner for SignerRunner { async fn get_signer_registrations_from_aggregator( &self, - ) -> StdResult> { + ) -> StdResult> { debug!(self.logger, ">> get_epoch_settings"); - self.services.certificate_handler.retrieve_epoch_settings().await + self.services + .signers_registration_retriever + .retrieve_all_signer_registrations() + .await } async fn get_beacon_to_sign(&self, time_point: TimePoint) -> StdResult> { @@ -233,7 +236,7 @@ impl Runner for SignerRunner { kes_period, ); self.services - .certificate_handler + .signer_registration_publisher .register_signer(epoch_offset_to_recording_epoch, &signer) .await?; @@ -414,9 +417,10 @@ mod tests { use crate::database::test_helper::main_db_connection; use crate::metrics::MetricsService; use crate::services::{ - CardanoTransactionsImporter, DumbAggregatorClient, MithrilEpochService, - MithrilSingleSigner, MockTransactionStore, MockUpkeepService, SignerCertifierService, - SignerSignableSeedBuilder, SignerSignedEntityConfigProvider, + CardanoTransactionsImporter, DumbSignersRegistrationRetriever, MithrilEpochService, + MithrilSingleSigner, MockTransactionStore, MockUpkeepService, SignaturePublisherNoop, + SignerCertifierService, SignerSignableSeedBuilder, SignerSignedEntityConfigProvider, + SpySignerRegistrationPublisher, }; use crate::test_tools::TestLogger; @@ -546,13 +550,12 @@ mod tests { Arc::new(CardanoTransactionsPreloaderActivation::new(true)), )); let upkeep_service = Arc::new(MockUpkeepService::new()); - let aggregator_client = Arc::new(DumbAggregatorClient::default()); let certifier = Arc::new(SignerCertifierService::new( Arc::new(SignedBeaconRepository::new(sqlite_connection.clone(), None)), Arc::new(SignerSignedEntityConfigProvider::new(epoch_service.clone())), signed_entity_type_lock.clone(), single_signer.clone(), - aggregator_client.clone(), + Arc::new(SignaturePublisherNoop), logger.clone(), )); let kes_signer = None; @@ -569,7 +572,6 @@ mod tests { SignerDependencyContainer { stake_store, - certificate_handler: aggregator_client, chain_observer, digester, single_signer, @@ -585,6 +587,8 @@ mod tests { upkeep_service, epoch_service, certifier, + signer_registration_publisher: Arc::new(SpySignerRegistrationPublisher::default()), + signers_registration_retriever: Arc::new(DumbSignersRegistrationRetriever::default()), kes_signer, network_configuration_service, } @@ -659,8 +663,8 @@ mod tests { async fn test_register_signer_to_aggregator() { let mut services = init_services().await; let fixture = MithrilFixtureBuilder::default().with_signers(5).build(); - let certificate_handler = Arc::new(DumbAggregatorClient::default()); - services.certificate_handler = certificate_handler.clone(); + let registration_publisher_spy = Arc::new(SpySignerRegistrationPublisher::default()); + services.signer_registration_publisher = registration_publisher_spy.clone(); let protocol_initializer_store = services.protocol_initializer_store.clone(); let current_epoch = services.ticker_service.get_current_epoch().await.unwrap(); @@ -699,7 +703,7 @@ mod tests { .expect("registering a signer to the aggregator should not fail"); let last_registered_signer_first_registration = - certificate_handler.get_last_registered_signer().await.unwrap(); + registration_publisher_spy.get_last_registered_signer().await.unwrap(); let maybe_protocol_initializer_first_registration = protocol_initializer_store .get_protocol_initializer(current_epoch.offset_to_recording_epoch()) .await @@ -709,7 +713,8 @@ mod tests { "A protocol initializer should have been registered at the 'Recording' epoch" ); - let total_registered_signers = certificate_handler.get_total_registered_signers().await; + let total_registered_signers = + registration_publisher_spy.get_total_registered_signers().await; assert_eq!(1, total_registered_signers); runner @@ -718,7 +723,7 @@ mod tests { .expect("registering a signer to the aggregator should not fail"); let last_registered_signer_second_registration = - certificate_handler.get_last_registered_signer().await.unwrap(); + registration_publisher_spy.get_last_registered_signer().await.unwrap(); let maybe_protocol_initializer_second_registration = protocol_initializer_store .get_protocol_initializer(current_epoch.offset_to_recording_epoch()) .await @@ -733,7 +738,8 @@ mod tests { "The signer registration should be the same and should have been registered twice" ); - let total_registered_signers = certificate_handler.get_total_registered_signers().await; + let total_registered_signers = + registration_publisher_spy.get_total_registered_signers().await; assert_eq!(1, total_registered_signers); } @@ -769,10 +775,7 @@ mod tests { #[tokio::test] async fn test_inform_epoch_setting_pass_available_signed_entity_types_to_epoch_service() { - let mut services = init_services().await; - let certificate_handler = Arc::new(DumbAggregatorClient::default()); - - services.certificate_handler = certificate_handler; + let services = init_services().await; let runner = init_runner(Some(services), None).await; let epoch = Epoch(1); diff --git a/mithril-signer/src/runtime/state_machine.rs b/mithril-signer/src/runtime/state_machine.rs index a800f298523..9109eeb90b6 100644 --- a/mithril-signer/src/runtime/state_machine.rs +++ b/mithril-signer/src/runtime/state_machine.rs @@ -496,7 +496,7 @@ mod tests { use mithril_common::entities::{ChainPoint, Epoch, ProtocolMessage, SignedEntityType}; use mithril_common::test::double::Dummy; - use crate::SignerEpochSettings; + use crate::RegisteredSigners; use crate::runtime::runner::MockSignerRunner; use crate::test_tools::TestLogger; @@ -547,7 +547,7 @@ mod tests { #[tokio::test] async fn unregistered_epoch_settings_behind_known_epoch() { let mut runner = MockSignerRunner::new(); - let epoch_settings = SignerEpochSettings { + let epoch_settings = RegisteredSigners { epoch: Epoch(3), current_signers: vec![], next_signers: vec![], @@ -594,7 +594,7 @@ mod tests { runner .expect_get_signer_registrations_from_aggregator() .once() - .returning(|| Ok(Some(SignerEpochSettings::dummy()))); + .returning(|| Ok(Some(RegisteredSigners::dummy()))); runner .expect_get_mithril_network_configuration() @@ -646,7 +646,7 @@ mod tests { runner .expect_get_signer_registrations_from_aggregator() .once() - .returning(|| Ok(Some(SignerEpochSettings::dummy()))); + .returning(|| Ok(Some(RegisteredSigners::dummy()))); runner .expect_get_mithril_network_configuration() @@ -702,7 +702,7 @@ mod tests { runner .expect_get_signer_registrations_from_aggregator() .once() - .returning(|| Ok(Some(SignerEpochSettings::dummy()))); + .returning(|| Ok(Some(RegisteredSigners::dummy()))); runner .expect_get_mithril_network_configuration() diff --git a/mithril-signer/src/services/aggregator_client.rs b/mithril-signer/src/services/aggregator_client.rs deleted file mode 100644 index 01578642511..00000000000 --- a/mithril-signer/src/services/aggregator_client.rs +++ /dev/null @@ -1,163 +0,0 @@ -use anyhow::anyhow; -use async_trait::async_trait; - -use mithril_aggregator_client::query::{ - GetAggregatorFeaturesQuery, GetEpochSettingsQuery, PostRegisterSignatureQuery, - PostRegisterSignerQuery, -}; -use mithril_aggregator_client::{AggregatorHttpClient, AggregatorHttpClientError}; -use mithril_common::{ - StdResult, - entities::{Epoch, ProtocolMessage, SignedEntityType, Signer, SingleSignature}, - messages::{AggregatorFeaturesMessage, TryFromMessageAdapter, TryToMessageAdapter}, -}; - -use crate::entities::SignerEpochSettings; -use crate::message_adapters::{ - FromEpochSettingsAdapter, ToRegisterSignatureMessageAdapter, ToRegisterSignerMessageAdapter, -}; - -/// Trait for mocking and testing a `AggregatorClient` -#[cfg_attr(test, mockall::automock)] -#[async_trait] -pub trait AggregatorClient: Sync + Send { - /// Retrieves epoch settings from the aggregator - async fn retrieve_epoch_settings(&self) -> StdResult>; - - /// Registers signer with the aggregator. - async fn register_signer(&self, epoch: Epoch, signer: &Signer) -> StdResult<()>; - - /// Registers single signature with the aggregator. - async fn register_signature( - &self, - signed_entity_type: &SignedEntityType, - signature: &SingleSignature, - protocol_message: &ProtocolMessage, - ) -> StdResult<()>; - - /// Retrieves aggregator features message from the aggregator - async fn retrieve_aggregator_features(&self) -> StdResult; -} - -#[async_trait] -impl AggregatorClient for AggregatorHttpClient { - async fn retrieve_epoch_settings(&self) -> StdResult> { - let message = self.send(GetEpochSettingsQuery::current()).await?; - let epoch_settings = FromEpochSettingsAdapter::try_adapt(message)?; - - Ok(Some(epoch_settings)) - } - - async fn register_signer(&self, epoch: Epoch, signer: &Signer) -> StdResult<()> { - let register_signer_message = - ToRegisterSignerMessageAdapter::try_adapt((epoch, signer.to_owned()))?; - - self.send(PostRegisterSignerQuery::new(register_signer_message)) - .await?; - - Ok(()) - } - - async fn register_signature( - &self, - signed_entity_type: &SignedEntityType, - signature: &SingleSignature, - protocol_message: &ProtocolMessage, - ) -> StdResult<()> { - let register_single_signature_message = ToRegisterSignatureMessageAdapter::try_adapt(( - signed_entity_type.to_owned(), - signature.to_owned(), - protocol_message, - )) - .map_err(|e| AggregatorHttpClientError::JsonParseFailed(anyhow!(e)))?; - - self.send(PostRegisterSignatureQuery::new( - register_single_signature_message, - )) - .await?; - - Ok(()) - } - - async fn retrieve_aggregator_features(&self) -> StdResult { - let aggregator_features = self.send(GetAggregatorFeaturesQuery::current()).await?; - Ok(aggregator_features) - } -} - -#[cfg(test)] -pub(crate) mod dumb { - use mithril_common::test::double::Dummy; - use tokio::sync::RwLock; - - use super::*; - - /// This aggregator client is intended to be used by test services. - /// It actually does not communicate with an aggregator host but mimics this behavior. - /// It is driven by a Tester that controls the data it can return, and it can return its internal state for testing. - pub struct DumbAggregatorClient { - epoch_settings: RwLock>, - last_registered_signer: RwLock>, - aggregator_features: RwLock, - total_registered_signers: RwLock, - } - - impl DumbAggregatorClient { - /// Return the last signer that called with the `register` method. - pub async fn get_last_registered_signer(&self) -> Option { - self.last_registered_signer.read().await.clone() - } - - /// Return the total number of signers that called with the `register` method. - pub async fn get_total_registered_signers(&self) -> u32 { - *self.total_registered_signers.read().await - } - } - - impl Default for DumbAggregatorClient { - fn default() -> Self { - Self { - epoch_settings: RwLock::new(Some(SignerEpochSettings::dummy())), - last_registered_signer: RwLock::new(None), - aggregator_features: RwLock::new(AggregatorFeaturesMessage::dummy()), - total_registered_signers: RwLock::new(0), - } - } - } - - #[async_trait] - impl AggregatorClient for DumbAggregatorClient { - async fn retrieve_epoch_settings(&self) -> StdResult> { - let epoch_settings = self.epoch_settings.read().await.clone(); - - Ok(epoch_settings) - } - - /// Registers signer with the aggregator - async fn register_signer(&self, _epoch: Epoch, signer: &Signer) -> StdResult<()> { - let mut last_registered_signer = self.last_registered_signer.write().await; - let signer = signer.clone(); - *last_registered_signer = Some(signer); - - let mut total_registered_signers = self.total_registered_signers.write().await; - *total_registered_signers += 1; - - Ok(()) - } - - /// Registers single signature with the aggregator - async fn register_signature( - &self, - _signed_entity_type: &SignedEntityType, - _signature: &SingleSignature, - _protocol_message: &ProtocolMessage, - ) -> StdResult<()> { - Ok(()) - } - - async fn retrieve_aggregator_features(&self) -> StdResult { - let aggregator_features = self.aggregator_features.read().await; - Ok(aggregator_features.clone()) - } - } -} diff --git a/mithril-signer/src/services/mod.rs b/mithril-signer/src/services/mod.rs index 823f1054b0c..1e49466d2e2 100644 --- a/mithril-signer/src/services/mod.rs +++ b/mithril-signer/src/services/mod.rs @@ -9,22 +9,20 @@ //! //! Each service is defined by a public API (a trait) that is used in the controllers (runtimes). -mod aggregator_client; mod cardano_transactions; mod certifier; mod epoch_service; mod signable_builder; mod signature_publisher; +mod signer_registration; mod single_signer; mod upkeep_service; -#[cfg(test)] -pub(crate) use aggregator_client::dumb::DumbAggregatorClient; -pub use aggregator_client::*; pub use cardano_transactions::*; pub use certifier::*; pub use epoch_service::*; pub use signable_builder::*; pub use signature_publisher::*; +pub use signer_registration::*; pub use single_signer::*; pub use upkeep_service::*; diff --git a/mithril-signer/src/services/signature_publisher/http.rs b/mithril-signer/src/services/signature_publisher/http.rs index f9ef912efe3..e66766bc734 100644 --- a/mithril-signer/src/services/signature_publisher/http.rs +++ b/mithril-signer/src/services/signature_publisher/http.rs @@ -1,21 +1,37 @@ +use anyhow::Context; use async_trait::async_trait; -use mithril_common::StdResult; -use mithril_common::entities::{ProtocolMessage, SignedEntityType, SingleSignature}; -use crate::services::AggregatorClient; +use mithril_aggregator_client::{AggregatorHttpClient, query::PostRegisterSignatureQuery}; +use mithril_common::{ + StdResult, + entities::{ProtocolMessage, SignedEntityType, SingleSignature}, + messages::TryToMessageAdapter, +}; + +use crate::message_adapters::ToRegisterSignatureMessageAdapter; use super::SignaturePublisher; #[async_trait] -impl SignaturePublisher for T { +impl SignaturePublisher for AggregatorHttpClient { async fn publish( &self, signed_entity_type: &SignedEntityType, signature: &SingleSignature, protocol_message: &ProtocolMessage, ) -> StdResult<()> { - self.register_signature(signed_entity_type, signature, protocol_message) - .await?; + let register_single_signature_message = ToRegisterSignatureMessageAdapter::try_adapt(( + signed_entity_type.to_owned(), + signature.to_owned(), + protocol_message, + )) + .with_context(|| "Failed to adapt message to register single signature message")?; + + self.send(PostRegisterSignatureQuery::new( + register_single_signature_message, + )) + .await?; + Ok(()) } } diff --git a/mithril-signer/src/services/signer_registration/mod.rs b/mithril-signer/src/services/signer_registration/mod.rs new file mode 100644 index 00000000000..49302ca86cc --- /dev/null +++ b/mithril-signer/src/services/signer_registration/mod.rs @@ -0,0 +1,5 @@ +mod publisher; +mod retriever; + +pub use publisher::*; +pub use retriever::*; diff --git a/mithril-signer/src/services/signer_registration/publisher/http.rs b/mithril-signer/src/services/signer_registration/publisher/http.rs new file mode 100644 index 00000000000..1d3d4f093c2 --- /dev/null +++ b/mithril-signer/src/services/signer_registration/publisher/http.rs @@ -0,0 +1,25 @@ +use anyhow::Context; + +use mithril_aggregator_client::{AggregatorHttpClient, query::PostRegisterSignerQuery}; +use mithril_common::{ + StdResult, + entities::{Epoch, Signer}, + messages::TryToMessageAdapter, +}; + +use crate::ToRegisterSignerMessageAdapter; +use crate::services::SignerRegistrationPublisher; + +#[async_trait::async_trait] +impl SignerRegistrationPublisher for AggregatorHttpClient { + async fn register_signer(&self, epoch: Epoch, signer: &Signer) -> StdResult<()> { + let register_signer_message = + ToRegisterSignerMessageAdapter::try_adapt((epoch, signer.to_owned())) + .with_context(|| "Failed to adapt message to register signer message")?; + + self.send(PostRegisterSignerQuery::new(register_signer_message)) + .await?; + + Ok(()) + } +} diff --git a/mithril-signer/src/services/signer_registration/publisher/interface.rs b/mithril-signer/src/services/signer_registration/publisher/interface.rs new file mode 100644 index 00000000000..86471ea596e --- /dev/null +++ b/mithril-signer/src/services/signer_registration/publisher/interface.rs @@ -0,0 +1,10 @@ +use mithril_common::StdResult; +use mithril_common::entities::{Epoch, Signer}; + +/// Publishes a signer registration to a third party. +#[cfg_attr(test, mockall::automock)] +#[async_trait::async_trait] +pub trait SignerRegistrationPublisher: Send + Sync { + /// Registers signer with the aggregator. + async fn register_signer(&self, epoch: Epoch, signer: &Signer) -> StdResult<()>; +} diff --git a/mithril-signer/src/services/signer_registration/publisher/mod.rs b/mithril-signer/src/services/signer_registration/publisher/mod.rs new file mode 100644 index 00000000000..de9d4b8e73d --- /dev/null +++ b/mithril-signer/src/services/signer_registration/publisher/mod.rs @@ -0,0 +1,8 @@ +mod http; +mod interface; +#[cfg(test)] +mod spy; + +pub use interface::*; +#[cfg(test)] +pub use spy::*; diff --git a/mithril-signer/src/services/signer_registration/publisher/spy.rs b/mithril-signer/src/services/signer_registration/publisher/spy.rs new file mode 100644 index 00000000000..f2b77292e9a --- /dev/null +++ b/mithril-signer/src/services/signer_registration/publisher/spy.rs @@ -0,0 +1,47 @@ +use tokio::sync::RwLock; + +use mithril_common::StdResult; +use mithril_common::entities::{Epoch, Signer}; + +use crate::services::SignerRegistrationPublisher; + +/// A spy implementation of the `SignerRegistrationPublisher` trait for testing +pub struct SpySignerRegistrationPublisher { + last_registered_signer: RwLock>, + total_registered_signers: RwLock, +} + +impl SpySignerRegistrationPublisher { + /// Return the last signer that called with the `register` method. + pub async fn get_last_registered_signer(&self) -> Option { + self.last_registered_signer.read().await.clone() + } + + /// Return the total number of signers that called with the `register` method. + pub async fn get_total_registered_signers(&self) -> u32 { + *self.total_registered_signers.read().await + } +} + +impl Default for SpySignerRegistrationPublisher { + fn default() -> Self { + Self { + last_registered_signer: RwLock::new(None), + total_registered_signers: RwLock::new(0), + } + } +} + +#[async_trait::async_trait] +impl SignerRegistrationPublisher for SpySignerRegistrationPublisher { + async fn register_signer(&self, _epoch: Epoch, signer: &Signer) -> StdResult<()> { + let mut last_registered_signer = self.last_registered_signer.write().await; + let signer = signer.clone(); + *last_registered_signer = Some(signer); + + let mut total_registered_signers = self.total_registered_signers.write().await; + *total_registered_signers += 1; + + Ok(()) + } +} diff --git a/mithril-signer/src/services/signer_registration/retriever/dumb.rs b/mithril-signer/src/services/signer_registration/retriever/dumb.rs new file mode 100644 index 00000000000..8fc5bea0d5c --- /dev/null +++ b/mithril-signer/src/services/signer_registration/retriever/dumb.rs @@ -0,0 +1,29 @@ +use tokio::sync::RwLock; + +use mithril_common::StdResult; +use mithril_common::test::double::Dummy; + +use crate::RegisteredSigners; +use crate::services::signer_registration::retriever::interface::SignersRegistrationRetriever; + +/// Dumb `SignersRegistrationRetriever` implementation for testing +pub struct DumbSignersRegistrationRetriever { + epoch_settings: RwLock>, +} + +impl Default for DumbSignersRegistrationRetriever { + fn default() -> Self { + Self { + epoch_settings: RwLock::new(Some(RegisteredSigners::dummy())), + } + } +} + +#[async_trait::async_trait] +impl SignersRegistrationRetriever for DumbSignersRegistrationRetriever { + async fn retrieve_all_signer_registrations(&self) -> StdResult> { + let epoch_settings = self.epoch_settings.read().await.clone(); + + Ok(epoch_settings) + } +} diff --git a/mithril-signer/src/services/signer_registration/retriever/http.rs b/mithril-signer/src/services/signer_registration/retriever/http.rs new file mode 100644 index 00000000000..8c3d4150ed8 --- /dev/null +++ b/mithril-signer/src/services/signer_registration/retriever/http.rs @@ -0,0 +1,15 @@ +use mithril_aggregator_client::{AggregatorHttpClient, query::GetEpochSettingsQuery}; +use mithril_common::{StdResult, messages::TryFromMessageAdapter}; + +use crate::services::SignersRegistrationRetriever; +use crate::{FromEpochSettingsAdapter, RegisteredSigners}; + +#[async_trait::async_trait] +impl SignersRegistrationRetriever for AggregatorHttpClient { + async fn retrieve_all_signer_registrations(&self) -> StdResult> { + let message = self.send(GetEpochSettingsQuery::current()).await?; + let epoch_settings = FromEpochSettingsAdapter::try_adapt(message)?; + + Ok(Some(epoch_settings)) + } +} diff --git a/mithril-signer/src/services/signer_registration/retriever/interface.rs b/mithril-signer/src/services/signer_registration/retriever/interface.rs new file mode 100644 index 00000000000..bcd26140156 --- /dev/null +++ b/mithril-signer/src/services/signer_registration/retriever/interface.rs @@ -0,0 +1,11 @@ +use mithril_common::StdResult; + +use crate::RegisteredSigners; + +/// Service responsible for retrieving the signer's registration from the mithril network +#[cfg_attr(test, mockall::automock)] +#[async_trait::async_trait] +pub trait SignersRegistrationRetriever: Sync + Send { + /// Retrieves signer's registration from the mithril network + async fn retrieve_all_signer_registrations(&self) -> StdResult>; +} diff --git a/mithril-signer/src/services/signer_registration/retriever/mod.rs b/mithril-signer/src/services/signer_registration/retriever/mod.rs new file mode 100644 index 00000000000..195d1398ff8 --- /dev/null +++ b/mithril-signer/src/services/signer_registration/retriever/mod.rs @@ -0,0 +1,8 @@ +#[cfg(test)] +mod dumb; +mod http; +mod interface; + +#[cfg(test)] +pub use dumb::*; +pub use interface::*; diff --git a/mithril-signer/tests/test_extensions/certificate_handler.rs b/mithril-signer/tests/test_extensions/fake_aggregator.rs similarity index 69% rename from mithril-signer/tests/test_extensions/certificate_handler.rs rename to mithril-signer/tests/test_extensions/fake_aggregator.rs index 394346231fb..9d4d3b21870 100644 --- a/mithril-signer/tests/test_extensions/certificate_handler.rs +++ b/mithril-signer/tests/test_extensions/fake_aggregator.rs @@ -1,35 +1,26 @@ use async_trait::async_trait; -use std::collections::BTreeSet; use std::{collections::HashMap, sync::Arc}; use tokio::sync::RwLock; use mithril_common::{ StdResult, - entities::{ - CardanoTransactionsSigningConfig, Epoch, ProtocolMessage, SignedEntityConfig, - SignedEntityType, SignedEntityTypeDiscriminants, Signer, SingleSignature, TimePoint, - }, - messages::AggregatorFeaturesMessage, + entities::{Epoch, ProtocolMessage, SignedEntityType, Signer, SingleSignature, TimePoint}, test::double::Dummy, }; use mithril_ticker::{MithrilTickerService, TickerService}; -use mithril_signer::{entities::SignerEpochSettings, services::AggregatorClient}; +use mithril_signer::services::{SignaturePublisher, SignerRegistrationPublisher}; +use mithril_signer::{entities::RegisteredSigners, services::SignersRegistrationRetriever}; pub struct FakeAggregator { - signed_entity_config: RwLock, registered_signers: RwLock>>, ticker_service: Arc, withhold_epoch_settings: RwLock, } impl FakeAggregator { - pub fn new( - signed_entity_config: SignedEntityConfig, - ticker_service: Arc, - ) -> Self { + pub fn new(ticker_service: Arc) -> Self { Self { - signed_entity_config: RwLock::new(signed_entity_config), registered_signers: RwLock::new(HashMap::new()), ticker_service, withhold_epoch_settings: RwLock::new(true), @@ -46,14 +37,6 @@ impl FakeAggregator { *settings = false; } - pub async fn change_allowed_discriminants( - &self, - discriminants: &BTreeSet, - ) { - let mut signed_entity_config = self.signed_entity_config.write().await; - signed_entity_config.allowed_discriminants = discriminants.clone(); - } - async fn get_time_point(&self) -> StdResult { let time_point = self.ticker_service.get_current_time_point().await?; Ok(time_point) @@ -81,8 +64,32 @@ impl FakeAggregator { } #[async_trait] -impl AggregatorClient for FakeAggregator { - async fn retrieve_epoch_settings(&self) -> StdResult> { +impl SignaturePublisher for FakeAggregator { + async fn publish( + &self, + _signed_entity_type: &SignedEntityType, + _signature: &SingleSignature, + _protocol_message: &ProtocolMessage, + ) -> StdResult<()> { + Ok(()) + } +} + +#[async_trait] +impl SignerRegistrationPublisher for FakeAggregator { + async fn register_signer(&self, epoch: Epoch, signer: &Signer) -> StdResult<()> { + let mut store = self.registered_signers.write().await; + let mut signers = store.get(&epoch).cloned().unwrap_or_default(); + signers.push(signer.clone()); + let _ = store.insert(epoch, signers); + + Ok(()) + } +} + +#[async_trait] +impl SignersRegistrationRetriever for FakeAggregator { + async fn retrieve_all_signer_registrations(&self) -> StdResult> { if *self.withhold_epoch_settings.read().await { Ok(None) } else { @@ -91,43 +98,13 @@ impl AggregatorClient for FakeAggregator { let current_signers = self.get_current_signers(&store).await?; let next_signers = self.get_next_signers(&store).await?; - Ok(Some(SignerEpochSettings { + Ok(Some(RegisteredSigners { epoch: time_point.epoch, current_signers, next_signers, })) } } - - /// Registers signer with the aggregator - async fn register_signer(&self, epoch: Epoch, signer: &Signer) -> StdResult<()> { - let mut store = self.registered_signers.write().await; - let mut signers = store.get(&epoch).cloned().unwrap_or_default(); - signers.push(signer.clone()); - let _ = store.insert(epoch, signers); - - Ok(()) - } - - /// Registers single signatures with the aggregator - async fn register_signature( - &self, - _signed_entity_type: &SignedEntityType, - _signature: &SingleSignature, - _protocol_message: &ProtocolMessage, - ) -> StdResult<()> { - Ok(()) - } - - async fn retrieve_aggregator_features(&self) -> StdResult { - let signed_entity_config = self.signed_entity_config.read().await; - - let mut message = AggregatorFeaturesMessage::dummy(); - message.capabilities.signed_entity_types = - signed_entity_config.allowed_discriminants.clone(); - - Ok(message) - } } #[cfg(test)] @@ -153,10 +130,7 @@ mod tests { immutable_observer.clone(), )); - ( - chain_observer, - FakeAggregator::new(SignedEntityConfig::dummy(), ticker_service), - ) + (chain_observer, FakeAggregator::new(ticker_service)) } #[tokio::test] @@ -209,7 +183,7 @@ mod tests { .await .expect("aggregator client should not fail while registering a user"); let epoch_settings = fake_aggregator - .retrieve_epoch_settings() + .retrieve_all_signer_registrations() .await .expect("we should have a result, None found!") .expect("we should have an EpochSettings, None found!"); @@ -222,7 +196,7 @@ mod tests { .await .expect("aggregator client should not fail while registering a user"); let epoch_settings = fake_aggregator - .retrieve_epoch_settings() + .retrieve_all_signer_registrations() .await .expect("we should have a result, None found!") .expect("we should have an EpochSettings, None found!"); @@ -236,7 +210,7 @@ mod tests { .await .expect("aggregator client should not fail while registering a user"); let epoch_settings = fake_aggregator - .retrieve_epoch_settings() + .retrieve_all_signer_registrations() .await .expect("we should have a result, None found!") .expect("we should have an EpochSettings, None found!"); @@ -244,35 +218,4 @@ mod tests { assert_eq!(2, epoch_settings.current_signers.len()); assert_eq!(1, epoch_settings.next_signers.len()); } - - #[tokio::test] - async fn retrieve_aggregator_features() { - let (_chain_observer, fake_aggregator) = init().await; - - { - let mut signing_config = fake_aggregator.signed_entity_config.write().await; - signing_config.allowed_discriminants = SignedEntityTypeDiscriminants::all(); - signing_config.cardano_transactions_signing_config = - CardanoTransactionsSigningConfig::dummy(); - } - - let features = fake_aggregator.retrieve_aggregator_features().await.unwrap(); - assert_eq!( - &SignedEntityTypeDiscriminants::all(), - &features.capabilities.signed_entity_types, - ); - - let new_discriminants = BTreeSet::from([ - SignedEntityTypeDiscriminants::CardanoTransactions, - SignedEntityTypeDiscriminants::CardanoImmutableFilesFull, - ]); - - fake_aggregator.change_allowed_discriminants(&new_discriminants).await; - - let updated_features = fake_aggregator.retrieve_aggregator_features().await.unwrap(); - assert_eq!( - &new_discriminants, - &updated_features.capabilities.signed_entity_types, - ); - } } diff --git a/mithril-signer/tests/test_extensions/mod.rs b/mithril-signer/tests/test_extensions/mod.rs index 9c6187923f7..edb4124b5fd 100644 --- a/mithril-signer/tests/test_extensions/mod.rs +++ b/mithril-signer/tests/test_extensions/mod.rs @@ -1,5 +1,5 @@ -mod certificate_handler; +mod fake_aggregator; mod state_machine_tester; -pub use certificate_handler::FakeAggregator; +pub use fake_aggregator::FakeAggregator; pub use state_machine_tester::StateMachineTester; diff --git a/mithril-signer/tests/test_extensions/state_machine_tester.rs b/mithril-signer/tests/test_extensions/state_machine_tester.rs index bcaa1220f71..14822173cdd 100644 --- a/mithril-signer/tests/test_extensions/state_machine_tester.rs +++ b/mithril-signer/tests/test_extensions/state_machine_tester.rs @@ -34,9 +34,8 @@ use mithril_common::{ api_version::APIVersionProvider, crypto_helper::{KesSigner, KesSignerStandard}, entities::{ - BlockNumber, CardanoTransactionsSigningConfig, ChainPoint, Epoch, SignedEntityConfig, - SignedEntityType, SignedEntityTypeDiscriminants, SignerWithStake, SlotNumber, SupportedEra, - TimePoint, + BlockNumber, CardanoTransactionsSigningConfig, ChainPoint, Epoch, SignedEntityType, + SignedEntityTypeDiscriminants, SignerWithStake, SlotNumber, SupportedEra, TimePoint, }, signable_builder::{ CardanoStakeDistributionSignableBuilder, CardanoTransactionsSignableBuilder, @@ -61,9 +60,9 @@ use mithril_signer::{ database::repository::{ProtocolInitializerRepository, SignedBeaconRepository, StakePoolStore}, dependency_injection::{DependenciesBuilder, SignerDependencyContainer}, services::{ - AggregatorClient, CardanoTransactionsImporter, MithrilEpochService, MithrilSingleSigner, - SignerCertifierService, SignerSignableSeedBuilder, SignerSignedEntityConfigProvider, - SignerUpkeepService, + CardanoTransactionsImporter, MithrilEpochService, MithrilSingleSigner, + SignerCertifierService, SignerRegistrationPublisher, SignerSignableSeedBuilder, + SignerSignedEntityConfigProvider, SignerUpkeepService, }, store::{MKTreeStoreSqlite, ProtocolInitializerStorer}, }; @@ -92,7 +91,7 @@ pub struct StateMachineTester { state_machine: StateMachine, immutable_observer: Arc, chain_observer: Arc, - certificate_handler: Arc, + fake_aggregator: Arc, network_configuration_service: Arc, protocol_initializer_store: Arc, stake_store: Arc, @@ -167,13 +166,7 @@ impl StateMachineTester { security_parameter: BlockNumber(0), step: BlockNumber(30), }; - let certificate_handler = Arc::new(FakeAggregator::new( - SignedEntityConfig { - allowed_discriminants: SignedEntityTypeDiscriminants::all(), - cardano_transactions_signing_config: cardano_transactions_signing_config.clone(), - }, - ticker_service.clone(), - )); + let fake_aggregator = Arc::new(FakeAggregator::new(ticker_service.clone())); let configuration_for_aggregation = MithrilNetworkConfigurationForEpoch { signed_entity_types_config: SignedEntityTypeConfiguration { @@ -313,7 +306,7 @@ impl StateMachineTester { Arc::new(SignerSignedEntityConfigProvider::new(epoch_service.clone())), signed_entity_type_lock.clone(), single_signer.clone(), - certificate_handler.clone(), + fake_aggregator.clone(), logger.clone(), )); let kes_signer = Some(Arc::new(KesSignerStandard::new( @@ -322,7 +315,7 @@ impl StateMachineTester { )) as Arc); let services = SignerDependencyContainer { - certificate_handler: certificate_handler.clone(), + signers_registration_retriever: fake_aggregator.clone(), ticker_service: ticker_service.clone(), chain_observer: chain_observer.clone(), digester: digester.clone(), @@ -339,6 +332,7 @@ impl StateMachineTester { upkeep_service, epoch_service, certifier, + signer_registration_publisher: fake_aggregator.clone(), kes_signer, network_configuration_service: network_configuration_service.clone(), }; @@ -359,7 +353,7 @@ impl StateMachineTester { state_machine, immutable_observer, chain_observer, - certificate_handler, + fake_aggregator, network_configuration_service, protocol_initializer_store, stake_store, @@ -477,7 +471,7 @@ impl StateMachineTester { /// make the aggregator send the epoch settings from now on pub async fn aggregator_send_epoch_settings(&mut self) -> &mut Self { - self.certificate_handler.release_epoch_settings().await; + self.fake_aggregator.release_epoch_settings().await; self } @@ -693,7 +687,7 @@ impl StateMachineTester { .unwrap() .epoch; for signer_with_stake in signers_with_stake { - self.certificate_handler + self.fake_aggregator .register_signer(epoch, &signer_with_stake.to_owned().into()) .await .map_err(TestError::SubsystemError)?;