diff --git a/internal/mithril-aggregator-discovery/src/capabilities_discoverer.rs b/internal/mithril-aggregator-discovery/src/capabilities_discoverer.rs index cb76b253e36..13e5a17058d 100644 --- a/internal/mithril-aggregator-discovery/src/capabilities_discoverer.rs +++ b/internal/mithril-aggregator-discovery/src/capabilities_discoverer.rs @@ -6,7 +6,7 @@ use mithril_common::{ messages::AggregatorCapabilities, }; -use crate::{AggregatorDiscoverer, AggregatorEndpoint}; +use crate::{AggregatorDiscoverer, AggregatorEndpoint, model::AggregatorEndpointWithCapabilities}; /// Required capabilities for an aggregator. #[derive(Clone, PartialEq, Eq, Debug)] @@ -50,14 +50,14 @@ impl RequiredAggregatorCapabilities { /// An aggregator discoverer for specific capabilities. pub struct CapableAggregatorDiscoverer { required_capabilities: RequiredAggregatorCapabilities, - inner_discoverer: Arc, + inner_discoverer: Arc>, } impl CapableAggregatorDiscoverer { /// Creates a new `CapableAggregatorDiscoverer` instance with the provided capabilities. pub fn new( capabilities: RequiredAggregatorCapabilities, - inner_discoverer: Arc, + inner_discoverer: Arc>, ) -> Self { Self { required_capabilities: capabilities, @@ -67,11 +67,11 @@ impl CapableAggregatorDiscoverer { } #[async_trait::async_trait] -impl AggregatorDiscoverer for CapableAggregatorDiscoverer { +impl AggregatorDiscoverer for CapableAggregatorDiscoverer { async fn get_available_aggregators( &self, network: MithrilNetwork, - ) -> StdResult>> { + ) -> StdResult>> { let aggregator_endpoints = self.inner_discoverer.get_available_aggregators(network).await?; Ok(Box::new(CapableAggregatorDiscovererIterator { @@ -88,20 +88,19 @@ struct CapableAggregatorDiscovererIterator { } impl Iterator for CapableAggregatorDiscovererIterator { - type Item = AggregatorEndpoint; + type Item = AggregatorEndpointWithCapabilities; fn next(&mut self) -> Option { for aggregator_endpoint in self.inner_iterator.by_ref() { - let aggregator_endpoint_clone = aggregator_endpoint.clone(); - let aggregator_capabilities = tokio::task::block_in_place(move || { - tokio::runtime::Handle::current().block_on(async move { - aggregator_endpoint_clone.retrieve_capabilities().await - }) - }); - if let Ok(aggregator_capabilities) = aggregator_capabilities - && self.required_capabilities.matches(&aggregator_capabilities) + if let Ok(aggregator_with_capabilities) = + AggregatorEndpointWithCapabilities::try_from(aggregator_endpoint) { - return Some(aggregator_endpoint); + if self + .required_capabilities + .matches(&aggregator_with_capabilities.capabilities()) + { + return Some(aggregator_with_capabilities); + } } } @@ -292,7 +291,7 @@ mod tests { .await .unwrap(); - let next_aggregator = aggregators.next(); + let next_aggregator = aggregators.next().map(|endpoint| endpoint.into()); aggregator_server_mock.assert(); assert_eq!( Some(AggregatorEndpoint::new(aggregator_server.url("/"))), @@ -369,7 +368,7 @@ mod tests { .await .unwrap(); - let next_aggregator = aggregators.next(); + let next_aggregator = aggregators.next().map(|endpoint| endpoint.into()); aggregator_server_mock_1.assert(); aggregator_server_mock_2.assert(); assert_eq!( @@ -438,7 +437,7 @@ mod tests { .await .unwrap(); - let next_aggregator = aggregators.next(); + let next_aggregator = aggregators.next().map(|endpoint| endpoint.into()); aggregator_server_mock_1.assert(); aggregator_server_mock_2.assert(); aggregator_server_mock_3.assert(); diff --git a/internal/mithril-aggregator-discovery/src/http_config_discoverer.rs b/internal/mithril-aggregator-discovery/src/http_config_discoverer.rs index 62e966cf4ee..31d08ad5bef 100644 --- a/internal/mithril-aggregator-discovery/src/http_config_discoverer.rs +++ b/internal/mithril-aggregator-discovery/src/http_config_discoverer.rs @@ -67,7 +67,7 @@ impl Default for HttpConfigAggregatorDiscoverer { } #[async_trait::async_trait] -impl AggregatorDiscoverer for HttpConfigAggregatorDiscoverer { +impl AggregatorDiscoverer for HttpConfigAggregatorDiscoverer { async fn get_available_aggregators( &self, network: MithrilNetwork, diff --git a/internal/mithril-aggregator-discovery/src/interface.rs b/internal/mithril-aggregator-discovery/src/interface.rs index ebe55bc52a8..215dca9cc96 100644 --- a/internal/mithril-aggregator-discovery/src/interface.rs +++ b/internal/mithril-aggregator-discovery/src/interface.rs @@ -2,17 +2,15 @@ use mithril_common::{StdResult, entities::MithrilNetwork}; -use crate::model::AggregatorEndpoint; - /// An aggregator discoverer. #[cfg_attr(test, mockall::automock)] #[async_trait::async_trait] -pub trait AggregatorDiscoverer: Sync + Send { +pub trait AggregatorDiscoverer: Sync + Send { /// Get an iterator over a list of available aggregators in a Mithril network. /// /// Note: there is no guarantee that the returned aggregators are sorted, complete or up-to-date. async fn get_available_aggregators( &self, network: MithrilNetwork, - ) -> StdResult>>; + ) -> StdResult>>; } diff --git a/internal/mithril-aggregator-discovery/src/lib.rs b/internal/mithril-aggregator-discovery/src/lib.rs index 19657ff9b5e..05bcb4f605a 100644 --- a/internal/mithril-aggregator-discovery/src/lib.rs +++ b/internal/mithril-aggregator-discovery/src/lib.rs @@ -11,5 +11,5 @@ pub mod test; pub use capabilities_discoverer::{CapableAggregatorDiscoverer, RequiredAggregatorCapabilities}; pub use http_config_discoverer::HttpConfigAggregatorDiscoverer; pub use interface::AggregatorDiscoverer; -pub use model::AggregatorEndpoint; +pub use model::{AggregatorEndpoint, AggregatorEndpointWithCapabilities}; pub use rand_discoverer::ShuffleAggregatorDiscoverer; diff --git a/internal/mithril-aggregator-discovery/src/model.rs b/internal/mithril-aggregator-discovery/src/model.rs index f2754571492..828935a6171 100644 --- a/internal/mithril-aggregator-discovery/src/model.rs +++ b/internal/mithril-aggregator-discovery/src/model.rs @@ -3,7 +3,7 @@ use std::time::Duration; use serde::Serialize; use mithril_aggregator_client::{AggregatorHttpClient, query::GetAggregatorFeaturesQuery}; -use mithril_common::{StdResult, messages::AggregatorCapabilities}; +use mithril_common::{StdError, StdResult, messages::AggregatorCapabilities}; /// Representation of an aggregator endpoint #[derive(Debug, Clone, PartialEq, Eq, Serialize)] @@ -32,6 +32,12 @@ impl AggregatorEndpoint { } } +impl From for AggregatorEndpoint { + fn from(endpoint: AggregatorEndpointWithCapabilities) -> Self { + Self::new(endpoint.url) + } +} + impl From for String { fn from(endpoint: AggregatorEndpoint) -> Self { endpoint.url @@ -43,3 +49,47 @@ impl std::fmt::Display for AggregatorEndpoint { write!(f, "{}", self.url) } } + +/// Representation of an aggregator endpoint with capabilities +#[derive(Debug, Clone, PartialEq, Serialize)] +pub struct AggregatorEndpointWithCapabilities { + url: String, + capabilities: AggregatorCapabilities, +} +impl AggregatorEndpointWithCapabilities { + /// Create a new AggregatorEndpointWithCapabilities instance + pub fn new(url: String, capabilities: AggregatorCapabilities) -> Self { + Self { url, capabilities } + } + + /// Get the capabilities of the aggregator + pub fn capabilities(&self) -> &AggregatorCapabilities { + &self.capabilities + } +} + +impl TryFrom for AggregatorEndpointWithCapabilities { + type Error = StdError; + + fn try_from(endpoint: AggregatorEndpoint) -> Result { + let endpoint_clone = endpoint.clone(); + let aggregator_capabilities = tokio::task::block_in_place(move || { + tokio::runtime::Handle::current() + .block_on(async move { endpoint_clone.retrieve_capabilities().await }) + }); + + Ok(Self::new(endpoint.url, aggregator_capabilities?)) + } +} + +impl From for String { + fn from(endpoint: AggregatorEndpointWithCapabilities) -> Self { + endpoint.url + } +} + +impl std::fmt::Display for AggregatorEndpointWithCapabilities { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.url) + } +} diff --git a/internal/mithril-aggregator-discovery/src/rand_discoverer.rs b/internal/mithril-aggregator-discovery/src/rand_discoverer.rs index a616d15dcff..8154bf9e3cf 100644 --- a/internal/mithril-aggregator-discovery/src/rand_discoverer.rs +++ b/internal/mithril-aggregator-discovery/src/rand_discoverer.rs @@ -10,12 +10,15 @@ use crate::{AggregatorDiscoverer, AggregatorEndpoint}; /// A discoverer that returns a random set of aggregators pub struct ShuffleAggregatorDiscoverer { random_generator: Arc>>, - inner_discoverer: Arc, + inner_discoverer: Arc>, } impl ShuffleAggregatorDiscoverer { /// Creates a new `ShuffleAggregatorDiscoverer` instance with the provided inner discoverer. - pub fn new(inner_discoverer: Arc, random_generator: R) -> Self { + pub fn new( + inner_discoverer: Arc>, + random_generator: R, + ) -> Self { Self { inner_discoverer, random_generator: Arc::new(Mutex::new(Box::new(random_generator))), @@ -24,7 +27,9 @@ impl ShuffleAggregatorDiscoverer { } #[async_trait::async_trait] -impl AggregatorDiscoverer for ShuffleAggregatorDiscoverer { +impl AggregatorDiscoverer + for ShuffleAggregatorDiscoverer +{ async fn get_available_aggregators( &self, network: MithrilNetwork, diff --git a/internal/mithril-aggregator-discovery/src/test/double/discoverer.rs b/internal/mithril-aggregator-discovery/src/test/double/discoverer.rs index e4807d5d999..c8a39779153 100644 --- a/internal/mithril-aggregator-discovery/src/test/double/discoverer.rs +++ b/internal/mithril-aggregator-discovery/src/test/double/discoverer.rs @@ -23,7 +23,7 @@ impl AggregatorDiscovererFake { } #[async_trait::async_trait] -impl AggregatorDiscoverer for AggregatorDiscovererFake { +impl AggregatorDiscoverer for AggregatorDiscovererFake { async fn get_available_aggregators( &self, _network: MithrilNetwork, diff --git a/mithril-client-cli/src/commands/tools/aggregator_discovery.rs b/mithril-client-cli/src/commands/tools/aggregator_discovery.rs index c95810c4068..728a438534d 100644 --- a/mithril-client-cli/src/commands/tools/aggregator_discovery.rs +++ b/mithril-client-cli/src/commands/tools/aggregator_discovery.rs @@ -48,10 +48,28 @@ impl AggregatorDiscoveryCommand { } else { let lines = lines .into_iter() - .map(|endpoint| vec![endpoint.cell()]) + .map(|endpoint| { + let endpoint_clone = endpoint.clone(); + let capabilities = endpoint_clone.capabilities(); + vec![ + endpoint.cell(), + capabilities.aggregate_signature_type.cell(), + capabilities + .signed_entity_types + .iter() + .map(|signed_entity_type| signed_entity_type.to_string()) + .collect::>() + .join(",") + .cell(), + ] + }) .collect::>() .table() - .title(vec!["Aggregator Endpoint".cell()]); + .title(vec![ + "Aggregator Endpoint".cell(), + "Aggregate Signature Type".cell(), + "Signed Entity Types".cell(), + ]); print_stdout(lines)?; } diff --git a/mithril-client/src/client.rs b/mithril-client/src/client.rs index 2775632dc54..07709bd8ccd 100644 --- a/mithril-client/src/client.rs +++ b/mithril-client/src/client.rs @@ -16,8 +16,9 @@ use slog::{Logger, o}; #[cfg(not(target_family = "wasm"))] use mithril_aggregator_discovery::{ - AggregatorDiscoverer, AggregatorEndpoint, CapableAggregatorDiscoverer, - HttpConfigAggregatorDiscoverer, RequiredAggregatorCapabilities, ShuffleAggregatorDiscoverer, + AggregatorDiscoverer, AggregatorEndpoint, AggregatorEndpointWithCapabilities, + CapableAggregatorDiscoverer, HttpConfigAggregatorDiscoverer, RequiredAggregatorCapabilities, + ShuffleAggregatorDiscoverer, }; use mithril_common::api_version::APIVersionProvider; use mithril_common::{MITHRIL_CLIENT_TYPE_HEADER, MITHRIL_ORIGIN_TAG_HEADER}; @@ -201,7 +202,7 @@ pub struct ClientBuilder { #[cfg(not(target_family = "wasm"))] aggregator_capabilities: Option, #[cfg(not(target_family = "wasm"))] - aggregator_discoverer: Option>, + aggregator_discoverer: Option>>, genesis_verification_key: Option, origin_tag: Option, client_type: Option, @@ -295,7 +296,7 @@ impl ClientBuilder { #[cfg(not(target_family = "wasm"))] pub fn with_aggregator_discoverer( mut self, - discoverer: Arc, + discoverer: Arc>, ) -> ClientBuilder { self.aggregator_discoverer = Some(discoverer); @@ -432,7 +433,7 @@ impl ClientBuilder { pub fn discover_aggregator( &self, network: &MithrilNetwork, - ) -> MithrilResult> { + ) -> MithrilResult> { let discoverer = self .aggregator_discoverer .clone() @@ -441,9 +442,12 @@ impl ClientBuilder { Arc::new(CapableAggregatorDiscoverer::new( capabilities.to_owned(), discoverer.clone(), - )) as Arc + )) as Arc> } else { - discoverer as Arc + Arc::new(CapableAggregatorDiscoverer::new( + RequiredAggregatorCapabilities::All, + discoverer.clone(), + )) as Arc> }; tokio::task::block_in_place(move || { @@ -458,7 +462,7 @@ impl ClientBuilder { /// Default aggregator discoverer to use to find the aggregator endpoint when in automatic discovery. #[cfg(not(target_family = "wasm"))] - fn default_aggregator_discoverer() -> Arc { + fn default_aggregator_discoverer() -> Arc> { Arc::new(ShuffleAggregatorDiscoverer::new( Arc::new(HttpConfigAggregatorDiscoverer::default()), {