Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
486f189
Implement test tools `equivalent_to` and `assert_equivalent`
dlachaume Jun 20, 2024
05c197b
Handle deduplicate list of transactions hashes in `compute_transactio…
dlachaume Jun 19, 2024
e618751
Handle empty cardano transactions hash in prover
dlachaume Jun 20, 2024
7cc4a95
Create a dedicated structure that filter a list of Cardano transactio…
dlachaume Jun 20, 2024
46dbc10
Add a limit for the number of transactions hashes to be certified by …
dlachaume Jun 21, 2024
d3ec53c
Add a validator for the transactions hash list that will be called on…
dlachaume Jun 21, 2024
48f4af1
Implement the validator in the proof route
dlachaume Jun 21, 2024
809d243
Handle deduplicate transactions hashes in the proof route
dlachaume Jun 24, 2024
9ec5039
Extend aggregator configuration by adding the maximum number of trans…
dlachaume Jun 24, 2024
1d107d4
Add aggregator parameter `cardano_transactions_prover_max_hashes_allo…
dlachaume Jun 24, 2024
fc107c9
Revert `prover` modifications after moving control and limit logic in…
dlachaume Jun 24, 2024
9a4fc2d
Handle Cardano transactions prover capability in explorer
dlachaume Jun 24, 2024
845a532
Fix wrong key for `cardano_transactions_database_connection_pool_size…
dlachaume Jun 25, 2024
8316a80
Refacto validator error messages and generic types in `ClientError` c…
dlachaume Jun 25, 2024
7a9e6ea
Move deduplicate responsability to `CardanoTransactionProofQueryParams`
dlachaume Jun 25, 2024
20c74ff
Bump `openapi.yml` and `mithril-explorer` versions
dlachaume Jun 25, 2024
9f63490
Bump crates versions
dlachaume Jun 25, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion mithril-aggregator/src/configuration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,9 @@ pub struct Configuration {
/// Cardano transactions signing configuration
#[example = "`{ security_parameter: 3000, step: 120 }`"]
pub cardano_transactions_signing_config: CardanoTransactionsSigningConfig,

/// Maximum number of transactions hashes allowed by request to the prover
pub cardano_transactions_prover_max_hashes_allowed_by_request: usize,
}

/// Uploader needed to copy the snapshot once computed.
Expand Down Expand Up @@ -245,6 +248,7 @@ impl Configuration {
security_parameter: 100,
step: 15,
},
cardano_transactions_prover_max_hashes_allowed_by_request: 100,
}
}

Expand Down Expand Up @@ -358,6 +362,9 @@ pub struct DefaultConfiguration {

/// Cardano transactions signing configuration
pub cardano_transactions_signing_config: CardanoTransactionsSigningConfig,

/// Maximum number of transactions hashes allowed by request to the prover
pub cardano_transactions_prover_max_hashes_allowed_by_request: u32,
}

impl Default for DefaultConfiguration {
Expand All @@ -384,6 +391,7 @@ impl Default for DefaultConfiguration {
security_parameter: 3000,
step: 120,
},
cardano_transactions_prover_max_hashes_allowed_by_request: 100,
}
}
}
Expand Down Expand Up @@ -463,7 +471,7 @@ impl Source for DefaultConfiguration {
into_value(myself.cardano_transactions_prover_cache_pool_size),
);
result.insert(
"cardano_transactions_prover_cache_pool_size".to_string(),
"cardano_transactions_database_connection_pool_size".to_string(),
into_value(myself.cardano_transactions_database_connection_pool_size),
);
result.insert(
Expand All @@ -483,6 +491,10 @@ impl Source for DefaultConfiguration {
),
])),
);
result.insert(
"cardano_transactions_prover_max_hashes_allowed_by_request".to_string(),
into_value(myself.cardano_transactions_prover_max_hashes_allowed_by_request),
);

Ok(result)
}
Expand Down
1 change: 1 addition & 0 deletions mithril-aggregator/src/http_server/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod routes;
pub mod validators;

pub const SERVER_BASE_PATH: &str = "aggregator";
17 changes: 17 additions & 0 deletions mithril-aggregator/src/http_server/routes/middlewares.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,20 @@ pub fn with_prover_service(
) -> impl Filter<Extract = (Arc<dyn ProverService>,), Error = Infallible> + Clone {
warp::any().map(move || dependency_manager.prover_service.clone())
}

pub mod validators {
use crate::http_server::validators::ProverTransactionsHashValidator;

use super::*;

/// With Prover Transactions Hash Validator
pub fn with_prover_transations_hash_validator(
dependency_manager: Arc<DependencyContainer>,
) -> impl Filter<Extract = (ProverTransactionsHashValidator,), Error = Infallible> + Clone {
let max_hashes = dependency_manager
.config
.cardano_transactions_prover_max_hashes_allowed_by_request;

warp::any().map(move || ProverTransactionsHashValidator::new(max_hashes))
}
}
112 changes: 106 additions & 6 deletions mithril-aggregator/src/http_server/routes/proof_routes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ fn proof_cardano_transaction(
.and(middlewares::with_signed_entity_service(
dependency_manager.clone(),
))
.and(
middlewares::validators::with_prover_transations_hash_validator(
dependency_manager.clone(),
),
)
.and(middlewares::with_prover_service(dependency_manager))
.and_then(handlers::proof_cardano_transaction)
}
Expand All @@ -47,7 +52,7 @@ mod handlers {
use warp::http::StatusCode;

use crate::{
http_server::routes::reply,
http_server::{routes::reply, validators::ProverTransactionsHashValidator},
message_adapters::ToCardanoTransactionsProofsMessageAdapter,
services::{ProverService, SignedEntityService},
unwrap_to_internal_server_error,
Expand All @@ -58,9 +63,10 @@ mod handlers {
pub async fn proof_cardano_transaction(
transaction_parameters: CardanoTransactionProofQueryParams,
signed_entity_service: Arc<dyn SignedEntityService>,
validator: ProverTransactionsHashValidator,
prover_service: Arc<dyn ProverService>,
) -> Result<impl warp::Reply, Infallible> {
let transaction_hashes = transaction_parameters
let mut transaction_hashes = transaction_parameters
.split_transactions_hashes()
.iter()
.map(|s| s.to_string())
Expand All @@ -70,6 +76,14 @@ mod handlers {
transaction_parameters.transaction_hashes
);

if let Err(error) = validator.validate(&transaction_hashes) {
warn!("proof_cardano_transaction::bad_request");
return Ok(reply::bad_request(error.label, error.message));
}

transaction_hashes.sort();
transaction_hashes.dedup();

match unwrap_to_internal_server_error!(
signed_entity_service
.get_last_cardano_transaction_snapshot()
Expand Down Expand Up @@ -123,7 +137,7 @@ mod tests {

use mithril_common::{
entities::{CardanoTransactionsSetProof, CardanoTransactionsSnapshot, SignedEntity},
test_utils::apispec::APISpec,
test_utils::{apispec::APISpec, fake_data},
};

use crate::services::MockSignedEntityService;
Expand Down Expand Up @@ -199,7 +213,9 @@ mod tests {
let response = request()
.method(method)
.path(&format!(
"/{SERVER_BASE_PATH}{path}?transaction_hashes=tx-123,tx-456"
"/{SERVER_BASE_PATH}{path}?transaction_hashes={},{}",
fake_data::transaction_hashes()[0],
fake_data::transaction_hashes()[1]
))
.reply(&setup_router(Arc::new(dependency_manager)))
.await;
Expand Down Expand Up @@ -228,7 +244,9 @@ mod tests {
let response = request()
.method(method)
.path(&format!(
"/{SERVER_BASE_PATH}{path}?transaction_hashes=tx-123,tx-456"
"/{SERVER_BASE_PATH}{path}?transaction_hashes={},{}",
fake_data::transaction_hashes()[0],
fake_data::transaction_hashes()[1]
))
.reply(&setup_router(Arc::new(dependency_manager)))
.await;
Expand Down Expand Up @@ -262,7 +280,9 @@ mod tests {
let response = request()
.method(method)
.path(&format!(
"/{SERVER_BASE_PATH}{path}?transaction_hashes=tx-123,tx-456"
"/{SERVER_BASE_PATH}{path}?transaction_hashes={},{}",
fake_data::transaction_hashes()[0],
fake_data::transaction_hashes()[1]
))
.reply(&setup_router(Arc::new(dependency_manager)))
.await;
Expand All @@ -278,4 +298,84 @@ mod tests {
)
.unwrap();
}

#[tokio::test]
async fn proof_cardano_transaction_return_bad_request_with_invalid_hashes() {
let config = Configuration::new_sample();
let mut builder = DependenciesBuilder::new(config);
let dependency_manager = builder.build_dependency_container().await.unwrap();

let method = Method::GET.as_str();
let path = "/proof/cardano-transaction";

let response = request()
.method(method)
.path(&format!(
"/{SERVER_BASE_PATH}{path}?transaction_hashes=invalid%3A%2F%2Fid,,tx-456"
))
.reply(&setup_router(Arc::new(dependency_manager)))
.await;

APISpec::verify_conformity(
APISpec::get_all_spec_files(),
method,
path,
"application/json",
&Null,
&response,
&StatusCode::BAD_REQUEST,
)
.unwrap();
}

#[tokio::test]
async fn proof_cardano_transaction_route_deduplicate_hashes() {
let config = Configuration::new_sample();
let mut builder = DependenciesBuilder::new(config);
let mut dependency_manager = builder.build_dependency_container().await.unwrap();
let mut mock_signed_entity_service = MockSignedEntityService::new();
mock_signed_entity_service
.expect_get_last_cardano_transaction_snapshot()
.returning(|| Ok(Some(SignedEntity::<CardanoTransactionsSnapshot>::dummy())));
dependency_manager.signed_entity_service = Arc::new(mock_signed_entity_service);

let mut mock_prover_service = MockProverService::new();
mock_prover_service
.expect_compute_transactions_proofs()
.withf(|_, transaction_hashes| {
transaction_hashes.len() == 2
&& transaction_hashes.contains(&fake_data::transaction_hashes()[0].to_string())
&& transaction_hashes.contains(&fake_data::transaction_hashes()[1].to_string())
})
.returning(|_, _| Ok(vec![CardanoTransactionsSetProof::dummy()]));
dependency_manager.prover_service = Arc::new(mock_prover_service);

let method = Method::GET.as_str();
let path = "/proof/cardano-transaction";

// We are testing on an unordered list of transaction hashes
let response = request()
.method(method)
.path(&format!(
"/{SERVER_BASE_PATH}{path}?transaction_hashes={},{},{},{},{}",
fake_data::transaction_hashes()[0],
fake_data::transaction_hashes()[1],
fake_data::transaction_hashes()[1],
fake_data::transaction_hashes()[0],
fake_data::transaction_hashes()[1]
))
.reply(&setup_router(Arc::new(dependency_manager)))
.await;

APISpec::verify_conformity(
APISpec::get_all_spec_files(),
method,
path,
"application/json",
&Null,
&response,
&StatusCode::OK,
)
.unwrap();
}
}
Loading