Skip to content

Commit 1a973a2

Browse files
committed
wip(aggregator-discovery): add 'CapableAggregatorDiscoverer' decorator
1 parent a53082c commit 1a973a2

File tree

5 files changed

+168
-3
lines changed

5 files changed

+168
-3
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/mithril-aggregator-discovery/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ rand = ["dep:rand"]
2020
anyhow = { workspace = true }
2121
async-trait = { workspace = true }
2222
mithril-common = { path = "../../mithril-common" }
23+
mithril-aggregator-client = { path = "../mithril-aggregator-client" }
2324
rand = { version = "0.9.2", optional = true}
2425
reqwest = { workspace = true, features = [
2526
"default",
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
use std::sync::Arc;
2+
3+
use mithril_common::{StdResult, messages::AggregatorCapabilities};
4+
5+
use crate::{AggregatorDiscoverer, AggregatorEndpoint, MithrilNetwork};
6+
7+
/// An aggregator discoverer for specific capabilities.
8+
pub struct CapableAggregatorDiscoverer {
9+
capabilities: AggregatorCapabilities,
10+
inner_discoverer: Arc<dyn AggregatorDiscoverer>,
11+
}
12+
13+
impl CapableAggregatorDiscoverer {
14+
/// Creates a new `CapableAggregatorDiscoverer` instance with the provided capabilities.
15+
pub fn new(
16+
capabilities: AggregatorCapabilities,
17+
inner_discoverer: Arc<dyn AggregatorDiscoverer>,
18+
) -> Self {
19+
Self {
20+
capabilities,
21+
inner_discoverer,
22+
}
23+
}
24+
25+
/// Check if the available capabilities match the required capabilities.
26+
///
27+
/// Returns true if:
28+
/// - The aggregate signature types are the same.
29+
/// - All required signed entity types are included in the available signed entity types.
30+
fn capabilities_match(
31+
required: &AggregatorCapabilities,
32+
available: &AggregatorCapabilities,
33+
) -> bool {
34+
if available.aggregate_signature_type != required.aggregate_signature_type {
35+
return false;
36+
}
37+
38+
let available_signed_entity_types = &available.signed_entity_types;
39+
let required_signed_entity_types = &required.signed_entity_types;
40+
41+
required_signed_entity_types
42+
.iter()
43+
.all(|req| available_signed_entity_types.contains(req))
44+
}
45+
}
46+
47+
/// An iterator over aggregator endpoints filtered by capabilities.
48+
struct CapableAggregatorDiscovererIterator {
49+
capabilities: AggregatorCapabilities,
50+
inner_iterator: Box<dyn Iterator<Item = AggregatorEndpoint>>,
51+
}
52+
53+
impl Iterator for CapableAggregatorDiscovererIterator {
54+
type Item = AggregatorEndpoint;
55+
56+
fn next(&mut self) -> Option<Self::Item> {
57+
for aggregator_endpoint in &mut self.inner_iterator {
58+
let aggregator_capabilities = tokio::runtime::Handle::current()
59+
.block_on(async { aggregator_endpoint.retrieve_capabilities().await });
60+
if CapableAggregatorDiscoverer::capabilities_match(
61+
&self.capabilities,
62+
&aggregator_capabilities.ok()?,
63+
) {
64+
return Some(aggregator_endpoint);
65+
}
66+
}
67+
68+
None
69+
}
70+
}
71+
72+
#[async_trait::async_trait]
73+
impl AggregatorDiscoverer for CapableAggregatorDiscoverer {
74+
async fn get_available_aggregators(
75+
&self,
76+
network: MithrilNetwork,
77+
) -> StdResult<Box<dyn Iterator<Item = AggregatorEndpoint>>> {
78+
let aggregator_endpoints = self.inner_discoverer.get_available_aggregators(network).await?;
79+
80+
Ok(Box::new(CapableAggregatorDiscovererIterator {
81+
capabilities: self.capabilities.clone(),
82+
inner_iterator: aggregator_endpoints,
83+
}))
84+
}
85+
}
86+
87+
#[cfg(test)]
88+
mod tests {
89+
use std::collections::BTreeSet;
90+
91+
use mithril_common::{
92+
AggregateSignatureType,
93+
entities::SignedEntityTypeDiscriminants::{
94+
CardanoDatabase, CardanoStakeDistribution, CardanoTransactions,
95+
},
96+
};
97+
98+
use super::*;
99+
100+
#[test]
101+
fn capabilities_match_success() {
102+
let required = AggregatorCapabilities {
103+
aggregate_signature_type: AggregateSignatureType::Concatenation,
104+
signed_entity_types: BTreeSet::from([CardanoTransactions, CardanoStakeDistribution]),
105+
cardano_transactions_prover: None,
106+
};
107+
108+
let available = AggregatorCapabilities {
109+
aggregate_signature_type: AggregateSignatureType::Concatenation,
110+
signed_entity_types: BTreeSet::from([
111+
CardanoTransactions,
112+
CardanoStakeDistribution,
113+
CardanoDatabase,
114+
]),
115+
cardano_transactions_prover: None,
116+
};
117+
118+
assert!(CapableAggregatorDiscoverer::capabilities_match(
119+
&required, &available
120+
));
121+
}
122+
123+
#[test]
124+
fn capabilities_match_failure() {
125+
let required = AggregatorCapabilities {
126+
aggregate_signature_type: AggregateSignatureType::Concatenation,
127+
signed_entity_types: BTreeSet::from([CardanoTransactions, CardanoStakeDistribution]),
128+
cardano_transactions_prover: None,
129+
};
130+
131+
let available = AggregatorCapabilities {
132+
aggregate_signature_type: AggregateSignatureType::Concatenation,
133+
signed_entity_types: BTreeSet::from([CardanoTransactions]),
134+
cardano_transactions_prover: None,
135+
};
136+
137+
assert!(!CapableAggregatorDiscoverer::capabilities_match(
138+
&required, &available
139+
));
140+
}
141+
142+
#[tokio::test]
143+
async fn get_available_aggregators_success() {
144+
todo!()
145+
}
146+
147+
#[tokio::test]
148+
async fn get_available_aggregators_success_when_one_aggregator_capabilities_does_not_match() {
149+
todo!()
150+
}
151+
152+
#[tokio::test]
153+
async fn get_available_aggregators_success_when_one_aggregator_retruns_an_error() {
154+
todo!()
155+
}
156+
}

internal/mithril-aggregator-discovery/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#![warn(missing_docs)]
22
//! This crate provides mechanisms to discover aggregators in a Mithril network.
33
4+
mod capabilities_discoverer;
45
mod http_config_discoverer;
56
mod interface;
67
mod model;

internal/mithril-aggregator-discovery/src/model.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
use mithril_common::StdResult;
1+
use mithril_aggregator_client::{AggregatorHttpClient, query::GetAggregatorFeaturesQuery};
2+
use mithril_common::{StdResult, messages::AggregatorCapabilities};
23

34
/// Representation of a Mithril network
45
// TODO: to move to mithril common
@@ -35,8 +36,13 @@ impl AggregatorEndpoint {
3536
}
3637

3738
/// Retrieve the capabilities of the aggregator
38-
pub fn capabilities(&self) -> StdResult<()> {
39-
todo!("Implement capabilities retrieval")
39+
pub async fn retrieve_capabilities(&self) -> StdResult<AggregatorCapabilities> {
40+
let aggregator_client = AggregatorHttpClient::builder(self.url.clone()).build()?;
41+
42+
Ok(aggregator_client
43+
.send(GetAggregatorFeaturesQuery::current())
44+
.await?
45+
.capabilities)
4046
}
4147
}
4248

0 commit comments

Comments
 (0)