mithril_aggregator/http_server/routes/
root_routes.rs1use super::middlewares;
2use crate::http_server::routes::router::RouterState;
3use warp::Filter;
4
5pub fn routes(
6 router_state: &RouterState,
7) -> impl Filter<Extract = (impl warp::Reply + use<>,), Error = warp::Rejection> + Clone + use<> {
8 root(router_state)
9}
10
11fn root(
13 router_state: &RouterState,
14) -> impl Filter<Extract = (impl warp::Reply + use<>,), Error = warp::Rejection> + Clone + use<> {
15 warp::path::end()
16 .and(middlewares::with_logger(router_state))
17 .and(middlewares::with_api_version_provider(router_state))
18 .and(middlewares::extract_config(router_state, |config| {
19 config.allowed_discriminants.clone()
20 }))
21 .and(middlewares::extract_config(router_state, |config| {
22 config.aggregate_signature_type
23 }))
24 .and(middlewares::extract_config(router_state, |config| {
25 config.cardano_transactions_prover_max_hashes_allowed_by_request
26 }))
27 .and_then(handlers::root)
28}
29
30mod handlers {
31 use std::collections::BTreeSet;
32 use std::{convert::Infallible, sync::Arc};
33
34 use mithril_common::AggregateSignatureType;
35 use slog::Logger;
36 use warp::http::StatusCode;
37
38 use mithril_common::api_version::APIVersionProvider;
39 use mithril_common::entities::SignedEntityTypeDiscriminants;
40 use mithril_common::messages::{
41 AggregatorCapabilities, AggregatorFeaturesMessage, CardanoTransactionsProverCapabilities,
42 };
43
44 use crate::http_server::routes::reply::json;
45 use crate::unwrap_to_internal_server_error;
46
47 pub async fn root(
49 logger: Logger,
50 api_version_provider: Arc<APIVersionProvider>,
51 allowed_signed_entity_type_discriminants: BTreeSet<SignedEntityTypeDiscriminants>,
52 aggregate_signature_type: AggregateSignatureType,
53 max_hashes_allowed_by_request: usize,
54 ) -> Result<impl warp::Reply, Infallible> {
55 let open_api_version = unwrap_to_internal_server_error!(
56 api_version_provider.compute_current_version(),
57 logger => "root::error"
58 );
59
60 let mut capabilities = AggregatorCapabilities {
61 signed_entity_types: allowed_signed_entity_type_discriminants,
62 aggregate_signature_type,
63 cardano_transactions_prover: None,
64 };
65
66 if capabilities
67 .signed_entity_types
68 .contains(&SignedEntityTypeDiscriminants::CardanoTransactions)
69 {
70 capabilities.cardano_transactions_prover =
71 Some(CardanoTransactionsProverCapabilities {
72 max_hashes_allowed_by_request,
73 });
74 }
75
76 Ok(json(
77 &AggregatorFeaturesMessage {
78 open_api_version: open_api_version.to_string(),
79 documentation_url: env!("CARGO_PKG_HOMEPAGE").to_string(),
80 capabilities,
81 },
82 StatusCode::OK,
83 ))
84 }
85}
86
87#[cfg(test)]
88mod tests {
89 use serde_json::Value::Null;
90 use std::collections::BTreeSet;
91 use std::sync::Arc;
92 use warp::http::{Method, StatusCode};
93 use warp::test::request;
94
95 use mithril_api_spec::APISpec;
96 use mithril_common::AggregateSignatureType;
97 use mithril_common::entities::SignedEntityTypeDiscriminants;
98 use mithril_common::messages::{
99 AggregatorCapabilities, AggregatorFeaturesMessage, CardanoTransactionsProverCapabilities,
100 };
101 use mithril_common::test::double::Dummy;
102
103 use crate::http_server::routes::router::RouterConfig;
104 use crate::initialize_dependencies;
105
106 use super::*;
107
108 fn setup_router(
109 state: RouterState,
110 ) -> impl Filter<Extract = (impl warp::Reply,), Error = warp::Rejection> + Clone {
111 let cors = warp::cors()
112 .allow_any_origin()
113 .allow_headers(vec!["content-type"])
114 .allow_methods(vec![Method::GET, Method::POST, Method::OPTIONS]);
115
116 warp::any().and(routes(&state).with(cors))
117 }
118
119 #[tokio::test]
120 async fn test_root_route_ok() {
121 let method = Method::GET.as_str();
122 let path = "/";
123 let config = RouterConfig {
124 allowed_discriminants: BTreeSet::from([
125 SignedEntityTypeDiscriminants::CardanoStakeDistribution,
126 SignedEntityTypeDiscriminants::CardanoImmutableFilesFull,
127 SignedEntityTypeDiscriminants::MithrilStakeDistribution,
128 SignedEntityTypeDiscriminants::CardanoTransactions,
129 SignedEntityTypeDiscriminants::CardanoDatabase,
130 ]),
131 cardano_transactions_prover_max_hashes_allowed_by_request: 500,
132 ..RouterConfig::dummy()
133 };
134 let dependency_manager = initialize_dependencies!().await;
135
136 let expected_open_api_version = dependency_manager
137 .api_version_provider
138 .clone()
139 .compute_current_version()
140 .unwrap()
141 .to_string();
142
143 let response = request()
144 .method(method)
145 .path(path)
146 .reply(&setup_router(RouterState::new(
147 Arc::new(dependency_manager),
148 config,
149 )))
150 .await;
151
152 let response_body: AggregatorFeaturesMessage =
153 serde_json::from_slice(response.body()).unwrap();
154
155 assert_eq!(response.status(), StatusCode::OK);
156
157 assert_eq!(
158 response_body,
159 AggregatorFeaturesMessage {
160 open_api_version: expected_open_api_version,
161 documentation_url: env!("CARGO_PKG_HOMEPAGE").to_string(),
162 capabilities: AggregatorCapabilities {
163 signed_entity_types: BTreeSet::from_iter([
164 SignedEntityTypeDiscriminants::CardanoStakeDistribution,
165 SignedEntityTypeDiscriminants::CardanoImmutableFilesFull,
166 SignedEntityTypeDiscriminants::MithrilStakeDistribution,
167 SignedEntityTypeDiscriminants::CardanoTransactions,
168 SignedEntityTypeDiscriminants::CardanoDatabase,
169 ]),
170 aggregate_signature_type: AggregateSignatureType::Concatenation,
171 cardano_transactions_prover: Some(CardanoTransactionsProverCapabilities {
172 max_hashes_allowed_by_request: 500
173 }),
174 },
175 }
176 );
177
178 APISpec::verify_conformity(
179 APISpec::get_default_spec_file_from(crate::http_server::API_SPEC_LOCATION),
180 method,
181 path,
182 "application/json",
183 &Null,
184 &response,
185 &StatusCode::OK,
186 )
187 .unwrap();
188 }
189
190 #[tokio::test]
191 async fn test_root_route_ok_with_cardano_transactions_enabled() {
192 let method = Method::GET.as_str();
193 let path = "/";
194 let config = RouterConfig {
195 allowed_discriminants: BTreeSet::from([
196 SignedEntityTypeDiscriminants::CardanoTransactions,
197 ]),
198 cardano_transactions_prover_max_hashes_allowed_by_request: 99,
199 ..RouterConfig::dummy()
200 };
201 let dependency_manager = initialize_dependencies!().await;
202
203 let response = request()
204 .method(method)
205 .path(path)
206 .reply(&setup_router(RouterState::new(
207 Arc::new(dependency_manager),
208 config,
209 )))
210 .await;
211
212 let response_body: AggregatorFeaturesMessage =
213 serde_json::from_slice(response.body()).unwrap();
214
215 assert_eq!(response.status(), StatusCode::OK);
216
217 assert_eq!(
218 response_body.capabilities.cardano_transactions_prover,
219 Some(CardanoTransactionsProverCapabilities {
220 max_hashes_allowed_by_request: 99
221 })
222 );
223
224 APISpec::verify_conformity(
225 APISpec::get_default_spec_file_from(crate::http_server::API_SPEC_LOCATION),
226 method,
227 path,
228 "application/json",
229 &Null,
230 &response,
231 &StatusCode::OK,
232 )
233 .unwrap();
234 }
235}