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}