mithril_client/certificate_client/mod.rs
1//! A client which retrieves and validates certificates from an aggregator.
2//!
3//! In order to do so it defines a [CertificateClient] exposes the following features:
4//! - [get][CertificateClient::get]: get a certificate data from its hash
5//! - [list][CertificateClient::list]: get the list of available certificates
6//! - [verify_chain][CertificateClient::verify_chain]: verify a certificate chain
7//!
8//! # Get a certificate
9//!
10//! To get a certificate using the [ClientBuilder][crate::client::ClientBuilder].
11//!
12//! ```no_run
13//! # async fn run() -> mithril_client::MithrilResult<()> {
14//! use mithril_client::ClientBuilder;
15//!
16//! let client = ClientBuilder::aggregator("YOUR_AGGREGATOR_ENDPOINT", "YOUR_GENESIS_VERIFICATION_KEY").build()?;
17//! let certificate = client.certificate().get("CERTIFICATE_HASH").await?.unwrap();
18//!
19//! println!("Certificate hash={}, signed_message={}", certificate.hash, certificate.signed_message);
20//! # Ok(())
21//! # }
22//! ```
23//!
24//! # List available certificates
25//!
26//! To list available certificates using the [ClientBuilder][crate::client::ClientBuilder].
27//!
28//! ```no_run
29//! # async fn run() -> mithril_client::MithrilResult<()> {
30//! use mithril_client::ClientBuilder;
31//!
32//! let client = mithril_client::ClientBuilder::aggregator("YOUR_AGGREGATOR_ENDPOINT", "YOUR_GENESIS_VERIFICATION_KEY").build()?;
33//! let certificates = client.certificate().list().await?;
34//!
35//! for certificate in certificates {
36//! println!("Certificate hash={}, signed_message={}", certificate.hash, certificate.signed_message);
37//! }
38//! # Ok(())
39//! # }
40//! ```
41//!
42//! # Validate a certificate chain
43//!
44//! To validate a certificate using the [ClientBuilder][crate::client::ClientBuilder].
45//!
46//! ```no_run
47//! # async fn run() -> mithril_client::MithrilResult<()> {
48//! use mithril_client::ClientBuilder;
49//!
50//! let client = ClientBuilder::aggregator("YOUR_AGGREGATOR_ENDPOINT", "YOUR_GENESIS_VERIFICATION_KEY").build()?;
51//! let certificate = client.certificate().verify_chain("CERTIFICATE_HASH").await?;
52//!
53//! println!("Chain of Certificate (hash: {}) is valid", certificate.hash);
54//! # Ok(())
55//! # }
56//! ```
57
58mod api;
59mod fetch;
60mod verify;
61#[cfg(feature = "unstable")]
62mod verify_cache;
63
64pub use api::*;
65pub use verify::MithrilCertificateVerifier;
66#[cfg(feature = "unstable")]
67pub use verify_cache::MemoryCertificateVerifierCache;
68
69#[cfg(test)]
70pub(crate) mod tests_utils {
71 use mithril_common::crypto_helper::ProtocolGenesisVerificationKey;
72 use mithril_common::entities::Certificate;
73 use mithril_common::messages::CertificateMessage;
74 use mockall::predicate::eq;
75 use std::sync::Arc;
76
77 use crate::feedback::{FeedbackReceiver, FeedbackSender};
78 use crate::test_utils::TestLogger;
79
80 use super::*;
81
82 #[derive(Default)]
83 pub(crate) struct CertificateClientTestBuilder {
84 aggregator_requester: MockCertificateAggregatorRequest,
85 genesis_verification_key: Option<String>,
86 feedback_receivers: Vec<Arc<dyn FeedbackReceiver>>,
87 #[cfg(feature = "unstable")]
88 verifier_cache: Option<Arc<dyn CertificateVerifierCache>>,
89 }
90
91 impl CertificateClientTestBuilder {
92 pub fn config_aggregator_requester_mock(
93 mut self,
94 config: impl FnOnce(&mut MockCertificateAggregatorRequest),
95 ) -> Self {
96 config(&mut self.aggregator_requester);
97 self
98 }
99
100 pub fn with_genesis_verification_key(
101 mut self,
102 genesis_verification_key: ProtocolGenesisVerificationKey,
103 ) -> Self {
104 self.genesis_verification_key = Some(genesis_verification_key.try_into().unwrap());
105 self
106 }
107
108 pub fn add_feedback_receiver(
109 mut self,
110 feedback_receiver: Arc<dyn FeedbackReceiver>,
111 ) -> Self {
112 self.feedback_receivers.push(feedback_receiver);
113 self
114 }
115
116 #[cfg(feature = "unstable")]
117 pub fn with_verifier_cache(
118 mut self,
119 verifier_cache: Arc<dyn CertificateVerifierCache>,
120 ) -> Self {
121 self.verifier_cache = Some(verifier_cache);
122 self
123 }
124
125 /// Builds a new [CertificateClient] with the given configuration.
126 ///
127 /// If no genesis verification key is provided, a [MockCertificateVerifier] will be used,
128 /// else a [MithrilCertificateVerifier] will be used.
129 pub fn build(self) -> CertificateClient {
130 let logger = TestLogger::stdout();
131 let aggregator_client = Arc::new(self.aggregator_requester);
132
133 let certificate_verifier: Arc<dyn CertificateVerifier> =
134 match self.genesis_verification_key {
135 None => Arc::new(MockCertificateVerifier::new()),
136 Some(genesis_verification_key) => Arc::new(
137 MithrilCertificateVerifier::new(
138 aggregator_client.clone(),
139 &genesis_verification_key,
140 FeedbackSender::new(&self.feedback_receivers),
141 #[cfg(feature = "unstable")]
142 self.verifier_cache,
143 logger.clone(),
144 )
145 .unwrap(),
146 ),
147 };
148
149 CertificateClient::new(aggregator_client.clone(), certificate_verifier, logger)
150 }
151 }
152
153 impl MockCertificateAggregatorRequest {
154 pub(crate) fn expect_certificate_chain(&mut self, certificate_chain: Vec<Certificate>) {
155 for certificate in certificate_chain {
156 let hash = certificate.hash.clone();
157 let message: CertificateMessage = certificate.try_into().unwrap();
158
159 self.expect_get_by_hash()
160 .with(eq(hash))
161 .once()
162 .returning(move |_| Ok(Some(message.to_owned())));
163 }
164 }
165 }
166}