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