Skip to content

Commit c9f8423

Browse files
committed
wip(client-cli): new aggregator discovery command
1 parent c55e43b commit c9f8423

File tree

4 files changed

+205
-8
lines changed

4 files changed

+205
-8
lines changed

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

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@ use mithril_common::{
88
use crate::{AggregatorDiscoverer, AggregatorEndpoint, MithrilNetwork};
99

1010
/// Required capabilities for an aggregator.
11-
#[derive(Clone)]
11+
#[derive(Clone, PartialEq, Eq, Debug)]
1212
pub enum RequiredAggregatorCapabilities {
13+
/// All
14+
All,
1315
/// Signed entity type.
1416
SignedEntityType(SignedEntityTypeDiscriminants),
1517
/// Aggregate signature type.
@@ -24,6 +26,7 @@ impl RequiredAggregatorCapabilities {
2426
/// Check if the available capabilities match the required capabilities.
2527
fn matches(&self, available: &AggregatorCapabilities) -> bool {
2628
match self {
29+
RequiredAggregatorCapabilities::All => true,
2730
RequiredAggregatorCapabilities::SignedEntityType(required_signed_entity_type) => {
2831
available
2932
.signed_entity_types
@@ -126,6 +129,18 @@ mod tests {
126129
mod required_capabilities {
127130
use super::*;
128131

132+
#[test]
133+
fn required_capabilities_match_all_success() {
134+
let required = RequiredAggregatorCapabilities::All;
135+
let available = AggregatorCapabilities {
136+
aggregate_signature_type: Concatenation,
137+
signed_entity_types: BTreeSet::from([]),
138+
cardano_transactions_prover: None,
139+
};
140+
141+
assert!(required.matches(&available));
142+
}
143+
129144
#[test]
130145
fn required_capabilities_match_signed_entity_types_success() {
131146
let required =

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,9 @@ impl From<AggregatorEndpoint> for String {
6363
endpoint.url
6464
}
6565
}
66+
67+
impl std::fmt::Display for AggregatorEndpoint {
68+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
69+
write!(f, "{}", self.url)
70+
}
71+
}
Lines changed: 172 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,192 @@
11
use clap::Parser;
22

3-
use mithril_client::{AggregatorDiscoveryType, ClientBuilder, MithrilNetwork, MithrilResult};
3+
use mithril_client::{
4+
AggregatorDiscoveryType, ClientBuilder, MithrilNetwork, MithrilResult,
5+
RequiredAggregatorCapabilities,
6+
common::{AggregateSignatureType, SignedEntityTypeDiscriminants},
7+
};
48

59
/// Clap command to select an aggregator from the available ones with automatic discovery.
610
#[derive(Parser, Debug, Clone)]
711
pub struct AggregatorSelectCommand {
812
/// Path to the Cardano node database directory.
913
#[clap(long)]
1014
network: MithrilNetwork,
15+
16+
/// Maximum number of entries to retrieve
17+
#[clap(long, default_value_t = 1)]
18+
max_entries: usize,
19+
20+
/// Signed entity types to consider for the discovery
21+
///
22+
/// If not provided, all signed entity types are considered.
23+
#[clap(long, default_value = "[]")]
24+
signed_entity_types: Vec<SignedEntityTypeDiscriminants>,
25+
26+
/// Aggregate signature types to consider for the discovery
27+
///
28+
/// If not provided, all aggregate signature types are considered.
29+
#[clap(long, default_value = "[]")]
30+
aggregate_signature_types: Vec<AggregateSignatureType>,
1131
}
1232

1333
impl AggregatorSelectCommand {
1434
/// Main command execution
1535
pub async fn execute(&self) -> MithrilResult<()> {
16-
let aggregator_endpoints =
17-
ClientBuilder::new(AggregatorDiscoveryType::Automatic(self.network.to_owned()))
18-
.with_default_aggregator_discoverer()
19-
.discover_aggregator(&self.network)?;
36+
let required_capabilities = self.build_required_capabilities();
37+
let client_builder =
38+
ClientBuilder::new(AggregatorDiscoveryType::Automatic(self.network.clone()))
39+
.with_capabilities(required_capabilities)
40+
.with_default_aggregator_discoverer();
41+
let aggregator_endpoints = client_builder
42+
.discover_aggregator(&self.network)?
43+
.take(self.max_entries);
2044

21-
for endpoint in aggregator_endpoints.iter() {
22-
println!("Discovered aggregator endpoint: {:?}", endpoint);
45+
println!(
46+
"Discovering at most {} aggregator endpoints:",
47+
self.max_entries,
48+
);
49+
for endpoint in aggregator_endpoints {
50+
println!("- Found: {endpoint}");
2351
}
2452

2553
Ok(())
2654
}
55+
56+
fn build_required_capabilities(&self) -> RequiredAggregatorCapabilities {
57+
if self.signed_entity_types.is_empty() && self.aggregate_signature_types.is_empty() {
58+
return RequiredAggregatorCapabilities::All;
59+
}
60+
61+
let mut required_capabilities = vec![];
62+
if !self.signed_entity_types.is_empty() {
63+
let mut required_capabilities_signed_entity_types = vec![];
64+
for signed_entity_type in &self.signed_entity_types {
65+
required_capabilities_signed_entity_types.push(
66+
RequiredAggregatorCapabilities::SignedEntityType(*signed_entity_type),
67+
);
68+
}
69+
required_capabilities.push(RequiredAggregatorCapabilities::Or(
70+
required_capabilities_signed_entity_types,
71+
));
72+
}
73+
74+
if !self.aggregate_signature_types.is_empty() {
75+
let mut required_capabilities_aggregate_signature_types = vec![];
76+
for aggregate_signature_type in &self.aggregate_signature_types {
77+
required_capabilities_aggregate_signature_types.push(
78+
RequiredAggregatorCapabilities::AggregateSignatureType(
79+
*aggregate_signature_type,
80+
),
81+
);
82+
}
83+
required_capabilities.push(RequiredAggregatorCapabilities::Or(
84+
required_capabilities_aggregate_signature_types,
85+
));
86+
}
87+
if required_capabilities.len() == 1 {
88+
return required_capabilities.into_iter().next().unwrap();
89+
} else {
90+
return RequiredAggregatorCapabilities::And(required_capabilities);
91+
}
92+
}
93+
}
94+
95+
#[cfg(test)]
96+
mod tests {
97+
use super::*;
98+
use mithril_client::common::SignedEntityTypeDiscriminants;
99+
100+
#[test]
101+
fn test_build_required_capabilities_all() {
102+
let command = AggregatorSelectCommand {
103+
network: MithrilNetwork::dummy(),
104+
max_entries: 1,
105+
signed_entity_types: vec![],
106+
aggregate_signature_types: vec![],
107+
};
108+
109+
let required_capabilities = command.build_required_capabilities();
110+
assert_eq!(required_capabilities, RequiredAggregatorCapabilities::All);
111+
}
112+
113+
#[test]
114+
fn test_build_required_capabilities_signed_entity_types() {
115+
let command = AggregatorSelectCommand {
116+
network: MithrilNetwork::dummy(),
117+
max_entries: 1,
118+
signed_entity_types: vec![
119+
SignedEntityTypeDiscriminants::CardanoTransactions,
120+
SignedEntityTypeDiscriminants::CardanoStakeDistribution,
121+
],
122+
aggregate_signature_types: vec![],
123+
};
124+
125+
let required_capabilities = command.build_required_capabilities();
126+
127+
assert_eq!(
128+
required_capabilities,
129+
RequiredAggregatorCapabilities::Or(vec![
130+
RequiredAggregatorCapabilities::SignedEntityType(
131+
SignedEntityTypeDiscriminants::CardanoTransactions
132+
),
133+
RequiredAggregatorCapabilities::SignedEntityType(
134+
SignedEntityTypeDiscriminants::CardanoStakeDistribution
135+
),
136+
])
137+
);
138+
}
139+
140+
#[test]
141+
fn test_build_required_capabilities_aggregate_signature_types() {
142+
let command = AggregatorSelectCommand {
143+
network: MithrilNetwork::dummy(),
144+
max_entries: 1,
145+
signed_entity_types: vec![],
146+
aggregate_signature_types: vec![AggregateSignatureType::Concatenation],
147+
};
148+
let required_capabilities = command.build_required_capabilities();
149+
150+
assert_eq!(
151+
required_capabilities,
152+
RequiredAggregatorCapabilities::Or(vec![
153+
RequiredAggregatorCapabilities::AggregateSignatureType(
154+
AggregateSignatureType::Concatenation
155+
),
156+
])
157+
);
158+
}
159+
160+
#[test]
161+
fn test_build_required_capabilities_both() {
162+
let command = AggregatorSelectCommand {
163+
network: MithrilNetwork::dummy(),
164+
max_entries: 1,
165+
signed_entity_types: vec![
166+
SignedEntityTypeDiscriminants::CardanoTransactions,
167+
SignedEntityTypeDiscriminants::CardanoStakeDistribution,
168+
],
169+
aggregate_signature_types: vec![AggregateSignatureType::Concatenation],
170+
};
171+
let required_capabilities = command.build_required_capabilities();
172+
173+
assert_eq!(
174+
required_capabilities,
175+
RequiredAggregatorCapabilities::And(vec![
176+
RequiredAggregatorCapabilities::Or(vec![
177+
RequiredAggregatorCapabilities::SignedEntityType(
178+
SignedEntityTypeDiscriminants::CardanoTransactions
179+
),
180+
RequiredAggregatorCapabilities::SignedEntityType(
181+
SignedEntityTypeDiscriminants::CardanoStakeDistribution
182+
),
183+
]),
184+
RequiredAggregatorCapabilities::Or(vec![
185+
RequiredAggregatorCapabilities::AggregateSignatureType(
186+
AggregateSignatureType::Concatenation
187+
),
188+
]),
189+
])
190+
);
191+
}
27192
}

mithril-stm/src/aggregate_signature/signature.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,17 @@ impl<D: Clone + Digest + FixedOutput + Send + Sync> From<&AggregateSignature<D>>
5959
}
6060
}
6161

62+
impl From<String> for AggregateSignatureType {
63+
fn from(s: String) -> Self {
64+
match s.as_str() {
65+
"Concatenation" => AggregateSignatureType::Concatenation,
66+
#[cfg(feature = "future_proof_system")]
67+
"Future" => AggregateSignatureType::Future,
68+
_ => panic!("Unknown aggregate signature type: {}", s),
69+
}
70+
}
71+
}
72+
6273
impl Display for AggregateSignatureType {
6374
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
6475
match self {

0 commit comments

Comments
 (0)