mithril_client/mithril_stake_distribution_client.rs
1//! A client to retrieve Mithril stake distributions data from an aggregator.
2//!
3//! In order to do so it defines a [MithrilStakeDistributionClient] which exposes the following features:
4//! - [get][MithrilStakeDistributionClient::get]: get a Mithril stake distribution data from its hash
5//! - [list][MithrilStakeDistributionClient::list]: get the list of available Mithril stake distribution
6//!
7//! # Get a Mithril stake distribution
8//!
9//! To get a Mithril stake distribution using the [ClientBuilder][crate::client::ClientBuilder].
10//!
11//! ```no_run
12//! # async fn run() -> mithril_client::MithrilResult<()> {
13//! use mithril_client::ClientBuilder;
14//!
15//! let client = ClientBuilder::aggregator("YOUR_AGGREGATOR_ENDPOINT", "YOUR_GENESIS_VERIFICATION_KEY").build()?;
16//! let mithril_stake_distribution = client.mithril_stake_distribution().get("MITHRIL_STAKE_DISTRIBUTION_HASH").await?.unwrap();
17//!
18//! println!("Mithril stake distribution hash={}, epoch={}", mithril_stake_distribution.hash, mithril_stake_distribution.epoch);
19//! # Ok(())
20//! # }
21//! ```
22//!
23//! # List available Mithril stake distributions
24//!
25//! To list available Mithril stake distributions using the [ClientBuilder][crate::client::ClientBuilder].
26//!
27//! ```no_run
28//! # async fn run() -> mithril_client::MithrilResult<()> {
29//! use mithril_client::ClientBuilder;
30//!
31//! let client = ClientBuilder::aggregator("YOUR_AGGREGATOR_ENDPOINT", "YOUR_GENESIS_VERIFICATION_KEY").build()?;
32//! let mithril_stake_distributions = client.mithril_stake_distribution().list().await?;
33//!
34//! for mithril_stake_distribution in mithril_stake_distributions {
35//! println!("Mithril stake distribution hash={}, epoch={}", mithril_stake_distribution.hash, mithril_stake_distribution.epoch);
36//! }
37//! # Ok(())
38//! # }
39//! ```
40
41use std::sync::Arc;
42
43use crate::{MithrilResult, MithrilStakeDistribution, MithrilStakeDistributionListItem};
44
45/// HTTP client for MithrilStakeDistribution API from the aggregator
46pub struct MithrilStakeDistributionClient {
47 aggregator_requester: Arc<dyn MithrilStakeDistributionAggregatorRequest>,
48}
49
50/// Define the requests against an aggregator related to Mithril stake distribution.
51#[cfg_attr(test, mockall::automock)]
52#[cfg_attr(target_family = "wasm", async_trait::async_trait(?Send))]
53#[cfg_attr(not(target_family = "wasm"), async_trait::async_trait)]
54pub trait MithrilStakeDistributionAggregatorRequest: Send + Sync {
55 /// Get the list of latest Mithril stake distributions from the aggregator.
56 async fn list_latest(&self) -> MithrilResult<Vec<MithrilStakeDistributionListItem>>;
57
58 /// Get a Mithril stake distribution for a given hash from the aggregator.
59 async fn get_by_hash(&self, hash: &str) -> MithrilResult<Option<MithrilStakeDistribution>>;
60}
61
62impl MithrilStakeDistributionClient {
63 /// Constructs a new `MithrilStakeDistributionClient`.
64 pub fn new(aggregator_requester: Arc<dyn MithrilStakeDistributionAggregatorRequest>) -> Self {
65 Self {
66 aggregator_requester,
67 }
68 }
69
70 /// Fetch a list of signed MithrilStakeDistribution
71 pub async fn list(&self) -> MithrilResult<Vec<MithrilStakeDistributionListItem>> {
72 self.aggregator_requester.list_latest().await
73 }
74
75 /// Get the given stake distribution data. If it cannot be found, None is returned.
76 pub async fn get(&self, hash: &str) -> MithrilResult<Option<MithrilStakeDistribution>> {
77 self.aggregator_requester.get_by_hash(hash).await
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use mockall::predicate::eq;
84
85 use mithril_common::test::double::fake_data;
86 use mithril_common::test::mock_extensions::MockBuilder;
87
88 use crate::MithrilSigner;
89 use crate::common::test::Dummy;
90
91 use super::*;
92
93 #[tokio::test]
94 async fn get_mithril_stake_distribution_list() {
95 let requester =
96 MockBuilder::<MockMithrilStakeDistributionAggregatorRequest>::configure(|mock| {
97 let messages = vec![
98 MithrilStakeDistributionListItem {
99 hash: "hash-123".to_string(),
100 ..Dummy::dummy()
101 },
102 MithrilStakeDistributionListItem {
103 hash: "hash-456".to_string(),
104 ..Dummy::dummy()
105 },
106 ];
107 mock.expect_list_latest().return_once(move || Ok(messages));
108 });
109 let client = MithrilStakeDistributionClient::new(requester);
110 let items = client.list().await.unwrap();
111
112 assert_eq!(2, items.len());
113 assert_eq!("hash-123".to_string(), items[0].hash);
114 assert_eq!("hash-456".to_string(), items[1].hash);
115 }
116
117 #[tokio::test]
118 async fn get_mithril_stake_distribution() {
119 let requester =
120 MockBuilder::<MockMithrilStakeDistributionAggregatorRequest>::configure(|mock| {
121 let message = MithrilStakeDistribution {
122 hash: "hash".to_string(),
123 signers_with_stake: MithrilSigner::from_signers(
124 fake_data::signers_with_stakes(2),
125 ),
126 ..Dummy::dummy()
127 };
128 mock.expect_get_by_hash()
129 .with(eq(message.hash.clone()))
130 .return_once(move |_| Ok(Some(message)));
131 });
132 let client = MithrilStakeDistributionClient::new(requester);
133
134 let stake_distribution_entity = client
135 .get("hash")
136 .await
137 .unwrap()
138 .expect("should return a mithril stake distribution");
139
140 assert_eq!("hash", &stake_distribution_entity.hash);
141 assert_eq!(2, stake_distribution_entity.signers_with_stake.len(),);
142 }
143}