diff --git a/Cargo.lock b/Cargo.lock index ff60cb29480..09f2d150883 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3889,7 +3889,7 @@ dependencies = [ [[package]] name = "mithril-aggregator" -version = "0.7.68" +version = "0.7.69" dependencies = [ "anyhow", "async-trait", @@ -4048,7 +4048,7 @@ dependencies = [ [[package]] name = "mithril-client" -version = "0.12.17" +version = "0.12.18" dependencies = [ "anyhow", "async-recursion", @@ -4138,7 +4138,7 @@ dependencies = [ [[package]] name = "mithril-common" -version = "0.6.2" +version = "0.6.3" dependencies = [ "anyhow", "async-trait", diff --git a/mithril-aggregator/Cargo.toml b/mithril-aggregator/Cargo.toml index 7eff387b46b..ddf7d805559 100644 --- a/mithril-aggregator/Cargo.toml +++ b/mithril-aggregator/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mithril-aggregator" -version = "0.7.68" +version = "0.7.69" description = "A Mithril Aggregator server" authors = { workspace = true } edition = { workspace = true } diff --git a/mithril-aggregator/src/database/query/certificate/get_certificate.rs b/mithril-aggregator/src/database/query/certificate/get_certificate.rs index fba873aac06..ed613adeaec 100644 --- a/mithril-aggregator/src/database/query/certificate/get_certificate.rs +++ b/mithril-aggregator/src/database/query/certificate/get_certificate.rs @@ -71,18 +71,18 @@ mod tests { #[test] fn test_get_certificate_records_by_epoch() { - let (certificates, _) = setup_certificate_chain(20, 7); + let certificates = setup_certificate_chain(20, 7); let connection = main_db_connection().unwrap(); - insert_certificate_records(&connection, certificates.clone()); + insert_certificate_records(&connection, certificates.certificates_chained.clone()); let certificate_records: Vec = connection .fetch_collect(GetCertificateRecordQuery::by_epoch(Epoch(1)).unwrap()) .unwrap(); let expected_certificate_records: Vec = certificates - .iter() + .reversed_chain() + .into_iter() .filter_map(|c| (c.epoch == Epoch(1)).then_some(c.to_owned().into())) - .rev() .collect(); assert_eq!(expected_certificate_records, certificate_records); @@ -90,9 +90,9 @@ mod tests { .fetch_collect(GetCertificateRecordQuery::by_epoch(Epoch(3)).unwrap()) .unwrap(); let expected_certificate_records: Vec = certificates - .iter() + .reversed_chain() + .into_iter() .filter_map(|c| (c.epoch == Epoch(3)).then_some(c.to_owned().into())) - .rev() .collect(); assert_eq!(expected_certificate_records, certificate_records); @@ -104,15 +104,15 @@ mod tests { #[test] fn test_get_all_certificate_records() { - let (certificates, _) = setup_certificate_chain(5, 2); + let certificates = setup_certificate_chain(5, 2); let expected_certificate_records: Vec = certificates - .iter() - .map(|c| c.to_owned().into()) - .rev() + .reversed_chain() + .into_iter() + .map(Into::into) .collect(); let connection = main_db_connection().unwrap(); - insert_certificate_records(&connection, certificates.clone()); + insert_certificate_records(&connection, certificates.certificates_chained.clone()); let certificate_records: Vec = connection .fetch_collect(GetCertificateRecordQuery::all()) @@ -123,7 +123,7 @@ mod tests { #[test] fn test_get_all_genesis_certificate_records() { // Two chains with different protocol parameters so generated certificates are different. - let (first_certificates_chain, _) = CertificateChainBuilder::new() + let first_certificates_chain = CertificateChainBuilder::new() .with_total_certificates(2) .with_protocol_parameters(ProtocolParameters { m: 90, @@ -131,9 +131,11 @@ mod tests { phi_f: 0.65, }) .build(); - let first_chain_genesis: CertificateRecord = - first_certificates_chain.last().unwrap().clone().into(); - let (second_certificates_chain, _) = CertificateChainBuilder::new() + let first_chain_genesis: CertificateRecord = first_certificates_chain + .genesis_certificate() + .clone() + .into(); + let second_certificates_chain = CertificateChainBuilder::new() .with_total_certificates(2) .with_protocol_parameters(ProtocolParameters { m: 100, @@ -141,8 +143,10 @@ mod tests { phi_f: 0.65, }) .build(); - let second_chain_genesis: CertificateRecord = - second_certificates_chain.last().unwrap().clone().into(); + let second_chain_genesis: CertificateRecord = second_certificates_chain + .genesis_certificate() + .clone() + .into(); assert_ne!(first_chain_genesis, second_chain_genesis); let connection = main_db_connection().unwrap(); @@ -151,14 +155,14 @@ mod tests { .unwrap(); assert_eq!(Vec::::new(), certificate_records); - insert_certificate_records(&connection, first_certificates_chain); + insert_certificate_records(&connection, first_certificates_chain.certificates_chained); let certificate_records: Vec = connection .fetch_collect(GetCertificateRecordQuery::all_genesis()) .unwrap(); assert_eq!(vec![first_chain_genesis.to_owned()], certificate_records); - insert_certificate_records(&connection, second_certificates_chain); + insert_certificate_records(&connection, second_certificates_chain.certificates_chained); let certificate_records: Vec = connection .fetch_collect(GetCertificateRecordQuery::all_genesis()) diff --git a/mithril-aggregator/src/database/query/certificate/insert_certificate.rs b/mithril-aggregator/src/database/query/certificate/insert_certificate.rs index 64014580fb2..ea7494e02ed 100644 --- a/mithril-aggregator/src/database/query/certificate/insert_certificate.rs +++ b/mithril-aggregator/src/database/query/certificate/insert_certificate.rs @@ -111,11 +111,11 @@ mod tests { #[test] fn test_insert_certificate_record() { - let (certificates, _) = setup_certificate_chain(5, 2); + let certificates = setup_certificate_chain(5, 2); let connection = main_db_connection().unwrap(); - for certificate in certificates { + for certificate in certificates.certificates_chained { let certificate_record: CertificateRecord = certificate.into(); let certificate_record_saved = connection .fetch_first(InsertCertificateRecordQuery::one( @@ -128,9 +128,8 @@ mod tests { #[test] fn test_insert_many_certificates_records() { - let (certificates, _) = setup_certificate_chain(5, 2); - let certificates_records: Vec = - certificates.into_iter().map(|cert| cert.into()).collect(); + let certificates = setup_certificate_chain(5, 2); + let certificates_records: Vec = certificates.into(); let connection = main_db_connection().unwrap(); diff --git a/mithril-aggregator/src/database/record/certificate.rs b/mithril-aggregator/src/database/record/certificate.rs index 660a82b728e..493c91b747e 100644 --- a/mithril-aggregator/src/database/record/certificate.rs +++ b/mithril-aggregator/src/database/record/certificate.rs @@ -390,16 +390,16 @@ mod tests { #[test] fn test_convert_certificates() { - let (certificates, _) = setup_certificate_chain(20, 3); + let certificates = setup_certificate_chain(20, 3); let mut certificate_records: Vec = Vec::new(); - for certificate in certificates.clone() { + for certificate in certificates.certificates_chained.clone() { certificate_records.push(certificate.into()); } let mut certificates_new: Vec = Vec::new(); for certificate_record in certificate_records { certificates_new.push(certificate_record.into()); } - assert_eq!(certificates, certificates_new); + assert_eq!(certificates.certificates_chained, certificates_new); } #[test] diff --git a/mithril-aggregator/src/database/repository/certificate_repository.rs b/mithril-aggregator/src/database/repository/certificate_repository.rs index bd31fdb792a..e91945c3e18 100644 --- a/mithril-aggregator/src/database/repository/certificate_repository.rs +++ b/mithril-aggregator/src/database/repository/certificate_repository.rs @@ -245,10 +245,10 @@ mod tests { #[tokio::test] async fn repository_get_certificate() { - let (certificates, _) = setup_certificate_chain(5, 2); + let certificates = setup_certificate_chain(5, 2); let expected_hash = certificates[0].hash.clone(); let connection = Arc::new(main_db_connection().unwrap()); - insert_certificate_records(&connection, certificates.clone()); + insert_certificate_records(&connection, certificates.certificates_chained.clone()); let repository: CertificateRepository = CertificateRepository::new(connection); let certificate = repository @@ -268,29 +268,28 @@ mod tests { #[tokio::test] async fn repository_get_latest_certificates() { - let (certificates, _) = setup_certificate_chain(5, 2); + let certificates = setup_certificate_chain(5, 2); let connection = Arc::new(main_db_connection().unwrap()); - insert_certificate_records(&connection, certificates.clone()); + insert_certificate_records(&connection, certificates.certificates_chained.clone()); let repository = CertificateRepository::new(connection); let latest_certificates = repository .get_latest_certificates(certificates.len()) .await .unwrap(); - let expected: Vec = certificates.into_iter().rev().collect(); - assert_eq!(expected, latest_certificates); + assert_eq!(certificates.reversed_chain(), latest_certificates); } #[tokio::test] async fn repository_get_latest_genesis_certificate() { - let (certificates, _) = setup_certificate_chain(5, 2); + let certificates = setup_certificate_chain(5, 2); let connection = Arc::new(main_db_connection().unwrap()); - insert_certificate_records(&connection, certificates.clone()); + insert_certificate_records(&connection, certificates.certificates_chained.clone()); let repository = CertificateRepository::new(connection); let latest_certificates = repository.get_latest_genesis_certificate().await.unwrap(); - let expected = Some(certificates.last().unwrap().clone()); + let expected = Some(certificates.genesis_certificate().clone()); assert_eq!(expected, latest_certificates); } @@ -509,11 +508,11 @@ mod tests { #[tokio::test] async fn get_master_certificate_for_epoch() { - let (certificates, _) = setup_certificate_chain(3, 1); + let certificates = setup_certificate_chain(3, 1); let expected_certificate_id = &certificates[2].hash; let epoch = &certificates[2].epoch; let connection = Arc::new(main_db_connection().unwrap()); - insert_certificate_records(&connection, certificates.clone()); + insert_certificate_records(&connection, certificates.certificates_chained.clone()); let repository: CertificateRepository = CertificateRepository::new(connection); let certificate = repository @@ -527,7 +526,7 @@ mod tests { #[tokio::test] async fn save_certificate() { - let (certificates, _) = setup_certificate_chain(5, 3); + let certificates = setup_certificate_chain(5, 3); let connection = Arc::new(main_db_connection().unwrap()); let repository: CertificateRepository = CertificateRepository::new(connection.clone()); let certificate = repository diff --git a/mithril-client/Cargo.toml b/mithril-client/Cargo.toml index 7af459f8f1b..f0409c2e2c0 100644 --- a/mithril-client/Cargo.toml +++ b/mithril-client/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mithril-client" -version = "0.12.17" +version = "0.12.18" description = "Mithril client library" authors = { workspace = true } edition = { workspace = true } diff --git a/mithril-client/src/certificate_client/verify.rs b/mithril-client/src/certificate_client/verify.rs index 9255dba7676..6a022fbfb15 100644 --- a/mithril-client/src/certificate_client/verify.rs +++ b/mithril-client/src/certificate_client/verify.rs @@ -262,7 +262,7 @@ mod tests { #[tokio::test] async fn validating_chain_send_feedbacks() { - let (chain, verifier) = CertificateChainBuilder::new() + let chain = CertificateChainBuilder::new() .with_total_certificates(3) .with_certificates_per_epoch(1) .build(); @@ -270,8 +270,10 @@ mod tests { let feedback_receiver = Arc::new(StackFeedbackReceiver::new()); let certificate_client = CertificateClientTestBuilder::default() - .config_aggregator_client_mock(|mock| mock.expect_certificate_chain(chain.clone())) - .with_genesis_verification_key(verifier.to_verification_key()) + .config_aggregator_client_mock(|mock| { + mock.expect_certificate_chain(chain.certificates_chained.clone()) + }) + .with_genesis_verification_key(chain.genesis_verifier.to_verification_key()) .add_feedback_receiver(feedback_receiver.clone()) .build(); @@ -287,14 +289,12 @@ mod tests { let mut vec = vec![MithrilEvent::CertificateChainValidationStarted { certificate_chain_validation_id: id.to_string(), }]; - vec.extend( - chain - .into_iter() - .map(|c| MithrilEvent::CertificateValidated { - certificate_chain_validation_id: id.to_string(), - certificate_hash: c.hash, - }), - ); + vec.extend(chain.certificates_chained.into_iter().map(|c| { + MithrilEvent::CertificateValidated { + certificate_chain_validation_id: id.to_string(), + certificate_hash: c.hash, + } + })); vec.push(MithrilEvent::CertificateChainValidated { certificate_chain_validation_id: id.to_string(), }); @@ -306,15 +306,17 @@ mod tests { #[tokio::test] async fn verify_chain_return_certificate_with_given_hash() { - let (chain, verifier) = CertificateChainBuilder::new() + let chain = CertificateChainBuilder::new() .with_total_certificates(3) .with_certificates_per_epoch(1) .build(); let last_certificate_hash = chain.first().unwrap().hash.clone(); let certificate_client = CertificateClientTestBuilder::default() - .config_aggregator_client_mock(|mock| mock.expect_certificate_chain(chain.clone())) - .with_genesis_verification_key(verifier.to_verification_key()) + .config_aggregator_client_mock(|mock| { + mock.expect_certificate_chain(chain.certificates_chained.clone()) + }) + .with_genesis_verification_key(chain.genesis_verifier.to_verification_key()) .build(); let certificate = certificate_client @@ -359,7 +361,7 @@ mod tests { #[tokio::test] async fn genesis_certificates_verification_result_is_not_cached() { - let (chain, verifier) = CertificateChainBuilder::new() + let chain = CertificateChainBuilder::new() .with_total_certificates(1) .with_certificates_per_epoch(1) .build(); @@ -369,7 +371,7 @@ mod tests { let cache = Arc::new(MemoryCertificateVerifierCache::new(TimeDelta::hours(1))); let verifier = build_verifier_with_cache( |_mock| {}, - verifier.to_verification_key(), + chain.genesis_verifier.to_verification_key(), cache.clone(), ); @@ -394,7 +396,7 @@ mod tests { #[tokio::test] async fn non_genesis_certificates_verification_result_is_cached() { - let (chain, verifier) = CertificateChainBuilder::new() + let chain = CertificateChainBuilder::new() .with_total_certificates(2) .with_certificates_per_epoch(1) .build(); @@ -405,7 +407,7 @@ mod tests { let cache = Arc::new(MemoryCertificateVerifierCache::new(TimeDelta::hours(1))); let verifier = build_verifier_with_cache( |mock| mock.expect_certificate_chain(vec![genesis_certificate.clone()]), - verifier.to_verification_key(), + chain.genesis_verifier.to_verification_key(), cache.clone(), ); @@ -428,7 +430,7 @@ mod tests { #[tokio::test] async fn verification_of_first_certificate_of_a_chain_should_always_fetch_it_from_network() { - let (chain, verifier) = CertificateChainBuilder::new() + let chain = CertificateChainBuilder::new() .with_total_certificates(2) .with_certificates_per_epoch(1) .build(); @@ -440,10 +442,10 @@ mod tests { ); let certificate_client = CertificateClientTestBuilder::default() .config_aggregator_client_mock(|mock| { - // Expect to first certificate to be fetched from the network - mock.expect_certificate_chain(chain.clone()); + // Expect to fetch the first certificate from the network + mock.expect_certificate_chain(chain.certificates_chained.clone()); }) - .with_genesis_verification_key(verifier.to_verification_key()) + .with_genesis_verification_key(chain.genesis_verifier.to_verification_key()) .with_verifier_cache(cache.clone()) .build(); @@ -466,7 +468,7 @@ mod tests { // | n°3 | 2 | n°2 | Yes | No | // | n°2 | 2 | n°1 | Yes | No | // | n°1 | 1 | None (genesis) | Yes | Yes | - let (chain, verifier) = CertificateChainBuilder::new() + let chain = CertificateChainBuilder::new() .with_total_certificates(6) .with_certificates_per_epoch(3) .with_certificate_chaining_method(CertificateChainingMethod::Sequential) @@ -503,7 +505,7 @@ mod tests { .config_aggregator_client_mock(|mock| { mock.expect_certificate_chain(certificates_that_must_be_fully_verified); }) - .with_genesis_verification_key(verifier.to_verification_key()) + .with_genesis_verification_key(chain.genesis_verifier.to_verification_key()) .with_verifier_cache(cache) .build(); @@ -515,7 +517,7 @@ mod tests { #[tokio::test] async fn verify_chain_return_certificate_with_cache() { - let (chain, verifier) = CertificateChainBuilder::new() + let chain = CertificateChainBuilder::new() .with_total_certificates(5) .with_certificates_per_epoch(1) .build(); @@ -531,7 +533,7 @@ mod tests { [chain[0..3].to_vec(), vec![chain.last().unwrap().clone()]].concat(), ) }) - .with_genesis_verification_key(verifier.to_verification_key()) + .with_genesis_verification_key(chain.genesis_verifier.to_verification_key()) .with_verifier_cache(Arc::new(cache)) .build(); diff --git a/mithril-common/Cargo.toml b/mithril-common/Cargo.toml index 84102d43c08..509dfeefaab 100644 --- a/mithril-common/Cargo.toml +++ b/mithril-common/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mithril-common" -version = "0.6.2" +version = "0.6.3" description = "Common types, interfaces, and utilities for Mithril nodes." authors = { workspace = true } edition = { workspace = true } diff --git a/mithril-common/src/certificate_chain/certificate_verifier.rs b/mithril-common/src/certificate_chain/certificate_verifier.rs index 584f44a3c6f..6042454b44b 100644 --- a/mithril-common/src/certificate_chain/certificate_verifier.rs +++ b/mithril-common/src/certificate_chain/certificate_verifier.rs @@ -531,15 +531,14 @@ mod tests { #[tokio::test] async fn verify_genesis_certificate_success() { let (total_certificates, certificates_per_epoch) = (5, 1); - let (fake_certificates, genesis_verifier) = - setup_certificate_chain(total_certificates, certificates_per_epoch); + let fake_certificates = setup_certificate_chain(total_certificates, certificates_per_epoch); let verifier = MockDependencyInjector::new().build_certificate_verifier(); - let genesis_certificate = fake_certificates.last().unwrap().clone(); + let genesis_certificate = fake_certificates.genesis_certificate(); let verify = verifier .verify_genesis_certificate( - &genesis_certificate, - &genesis_verifier.to_verification_key(), + genesis_certificate, + &fake_certificates.genesis_verifier.to_verification_key(), ) .await; @@ -549,18 +548,17 @@ mod tests { #[tokio::test] async fn verify_genesis_certificate_fails_if_is_not_genesis() { let (total_certificates, certificates_per_epoch) = (5, 1); - let (fake_certificates, genesis_verifier) = - setup_certificate_chain(total_certificates, certificates_per_epoch); + let fake_certificates = setup_certificate_chain(total_certificates, certificates_per_epoch); let verifier = MockDependencyInjector::new().build_certificate_verifier(); let standard_certificate = fake_certificates[0].clone(); - let mut genesis_certificate = fake_certificates.last().unwrap().clone(); + let mut genesis_certificate = fake_certificates.genesis_certificate().clone(); genesis_certificate.signature = standard_certificate.signature.clone(); genesis_certificate.hash = genesis_certificate.compute_hash(); let error = verifier .verify_genesis_certificate( &genesis_certificate, - &genesis_verifier.to_verification_key(), + &fake_certificates.genesis_verifier.to_verification_key(), ) .await .expect_err("verify_genesis_certificate should fail"); @@ -574,16 +572,15 @@ mod tests { #[tokio::test] async fn verify_genesis_certificate_fails_if_hash_unmatch() { let (total_certificates, certificates_per_epoch) = (5, 1); - let (fake_certificates, genesis_verifier) = - setup_certificate_chain(total_certificates, certificates_per_epoch); + let fake_certificates = setup_certificate_chain(total_certificates, certificates_per_epoch); let verifier = MockDependencyInjector::new().build_certificate_verifier(); - let mut genesis_certificate = fake_certificates.last().unwrap().clone(); + let mut genesis_certificate = fake_certificates.genesis_certificate().clone(); genesis_certificate.hash = "another-hash".to_string(); let error = verifier .verify_genesis_certificate( &genesis_certificate, - &genesis_verifier.to_verification_key(), + &fake_certificates.genesis_verifier.to_verification_key(), ) .await .expect_err("verify_genesis_certificate should fail"); @@ -594,10 +591,9 @@ mod tests { #[tokio::test] async fn verify_genesis_certificate_fails_if_protocol_message_unmatch() { let (total_certificates, certificates_per_epoch) = (5, 1); - let (fake_certificates, genesis_verifier) = - setup_certificate_chain(total_certificates, certificates_per_epoch); + let fake_certificates = setup_certificate_chain(total_certificates, certificates_per_epoch); let verifier = MockDependencyInjector::new().build_certificate_verifier(); - let mut genesis_certificate = fake_certificates.last().unwrap().clone(); + let mut genesis_certificate = fake_certificates.genesis_certificate().clone(); genesis_certificate.protocol_message.set_message_part( ProtocolMessagePartKey::CurrentEpoch, "another-value".to_string(), @@ -607,7 +603,7 @@ mod tests { let error = verifier .verify_genesis_certificate( &genesis_certificate, - &genesis_verifier.to_verification_key(), + &fake_certificates.genesis_verifier.to_verification_key(), ) .await .expect_err("verify_genesis_certificate should fail"); @@ -621,17 +617,16 @@ mod tests { #[tokio::test] async fn verify_genesis_certificate_fails_if_epoch_unmatch() { let (total_certificates, certificates_per_epoch) = (5, 1); - let (fake_certificates, genesis_verifier) = - setup_certificate_chain(total_certificates, certificates_per_epoch); + let fake_certificates = setup_certificate_chain(total_certificates, certificates_per_epoch); let verifier = MockDependencyInjector::new().build_certificate_verifier(); - let mut genesis_certificate = fake_certificates.last().unwrap().clone(); + let mut genesis_certificate = fake_certificates.genesis_certificate().clone(); genesis_certificate.epoch -= 1; genesis_certificate.hash = genesis_certificate.compute_hash(); let error = verifier .verify_genesis_certificate( &genesis_certificate, - &genesis_verifier.to_verification_key(), + &fake_certificates.genesis_verifier.to_verification_key(), ) .await .expect_err("verify_genesis_certificate should fail"); @@ -642,8 +637,7 @@ mod tests { #[tokio::test] async fn verify_standard_certificate_success_with_different_epochs_as_previous() { let (total_certificates, certificates_per_epoch) = (5, 1); - let (fake_certificates, _) = - setup_certificate_chain(total_certificates, certificates_per_epoch); + let fake_certificates = setup_certificate_chain(total_certificates, certificates_per_epoch); let verifier = MockDependencyInjector::new().build_certificate_verifier(); let certificate = fake_certificates[0].clone(); let previous_certificate = fake_certificates[1].clone(); @@ -658,8 +652,7 @@ mod tests { #[tokio::test] async fn verify_standard_certificate_success_with_same_epoch_as_previous() { let (total_certificates, certificates_per_epoch) = (5, 2); - let (fake_certificates, _) = - setup_certificate_chain(total_certificates, certificates_per_epoch); + let fake_certificates = setup_certificate_chain(total_certificates, certificates_per_epoch); let verifier = MockDependencyInjector::new().build_certificate_verifier(); let certificate = fake_certificates[0].clone(); let previous_certificate = fake_certificates[1].clone(); @@ -674,10 +667,9 @@ mod tests { #[tokio::test] async fn verify_standard_certificate_fails_if_is_not_genesis() { let (total_certificates, certificates_per_epoch) = (5, 1); - let (fake_certificates, _) = - setup_certificate_chain(total_certificates, certificates_per_epoch); + let fake_certificates = setup_certificate_chain(total_certificates, certificates_per_epoch); let verifier = MockDependencyInjector::new().build_certificate_verifier(); - let genesis_certificate = fake_certificates.last().unwrap().clone(); + let genesis_certificate = fake_certificates.genesis_certificate(); let mut standard_certificate = fake_certificates[0].clone(); standard_certificate.signature = genesis_certificate.signature.clone(); standard_certificate.hash = standard_certificate.compute_hash(); @@ -697,8 +689,7 @@ mod tests { #[tokio::test] async fn verify_standard_certificate_fails_if_infinite_loop() { let (total_certificates, certificates_per_epoch) = (5, 1); - let (fake_certificates, _) = - setup_certificate_chain(total_certificates, certificates_per_epoch); + let fake_certificates = setup_certificate_chain(total_certificates, certificates_per_epoch); let verifier = MockDependencyInjector::new().build_certificate_verifier(); let mut certificate = fake_certificates[0].clone(); certificate.previous_hash = certificate.hash.clone(); @@ -718,8 +709,7 @@ mod tests { #[tokio::test] async fn verify_standard_certificate_fails_if_hash_unmatch() { let (total_certificates, certificates_per_epoch) = (5, 1); - let (fake_certificates, _) = - setup_certificate_chain(total_certificates, certificates_per_epoch); + let fake_certificates = setup_certificate_chain(total_certificates, certificates_per_epoch); let verifier = MockDependencyInjector::new().build_certificate_verifier(); let mut certificate = fake_certificates[0].clone(); certificate.hash = "another-hash".to_string(); @@ -736,8 +726,7 @@ mod tests { #[tokio::test] async fn verify_standard_certificate_fails_if_protocol_message_unmatch() { let (total_certificates, certificates_per_epoch) = (5, 1); - let (fake_certificates, _) = - setup_certificate_chain(total_certificates, certificates_per_epoch); + let fake_certificates = setup_certificate_chain(total_certificates, certificates_per_epoch); let verifier = MockDependencyInjector::new().build_certificate_verifier(); let mut certificate = fake_certificates[0].clone(); certificate.protocol_message.set_message_part( @@ -761,8 +750,7 @@ mod tests { #[tokio::test] async fn verify_standard_certificate_fails_if_epoch_unmatch() { let (total_certificates, certificates_per_epoch) = (5, 1); - let (fake_certificates, _) = - setup_certificate_chain(total_certificates, certificates_per_epoch); + let fake_certificates = setup_certificate_chain(total_certificates, certificates_per_epoch); let verifier = MockDependencyInjector::new().build_certificate_verifier(); let mut certificate = fake_certificates[0].clone(); certificate.epoch -= 1; @@ -813,7 +801,7 @@ mod tests { } let (total_certificates, certificates_per_epoch) = (5, 1); - let (fake_certificates, _) = CertificateChainBuilder::new() + let fake_certificates = CertificateChainBuilder::new() .with_total_certificates(total_certificates) .with_certificates_per_epoch(certificates_per_epoch) .with_standard_certificate_processor(&|certificate, context| { @@ -842,8 +830,7 @@ mod tests { #[tokio::test] async fn verify_standard_certificate_fails_if_certificate_previous_hash_unmatch() { let (total_certificates, certificates_per_epoch) = (5, 1); - let (fake_certificates, _) = - setup_certificate_chain(total_certificates, certificates_per_epoch); + let fake_certificates = setup_certificate_chain(total_certificates, certificates_per_epoch); let verifier = MockDependencyInjector::new().build_certificate_verifier(); let certificate = fake_certificates[0].clone(); let mut previous_certificate = fake_certificates[1].clone(); @@ -864,8 +851,7 @@ mod tests { #[tokio::test] async fn verify_standard_certificate_fails_if_certificate_chain_avk_unmatch() { let (total_certificates, certificates_per_epoch) = (5, 1); - let (fake_certificates, _) = - setup_certificate_chain(total_certificates, certificates_per_epoch); + let fake_certificates = setup_certificate_chain(total_certificates, certificates_per_epoch); let verifier = MockDependencyInjector::new().build_certificate_verifier(); let mut certificate = fake_certificates[0].clone(); let mut previous_certificate = fake_certificates[1].clone(); @@ -890,8 +876,7 @@ mod tests { #[tokio::test] async fn verify_standard_certificate_fails_if_certificate_chain_protocol_parameters_unmatch() { let (total_certificates, certificates_per_epoch) = (5, 1); - let (fake_certificates, _) = - setup_certificate_chain(total_certificates, certificates_per_epoch); + let fake_certificates = setup_certificate_chain(total_certificates, certificates_per_epoch); let verifier = MockDependencyInjector::new().build_certificate_verifier(); let mut certificate = fake_certificates[0].clone(); let mut previous_certificate = fake_certificates[1].clone(); @@ -919,16 +904,15 @@ mod tests { #[tokio::test] async fn verify_certificate_success_when_certificate_is_genesis_and_valid() { let (total_certificates, certificates_per_epoch) = (5, 1); - let (fake_certificates, genesis_verifier) = - setup_certificate_chain(total_certificates, certificates_per_epoch); - let genesis_certificate = fake_certificates.last().unwrap().clone(); + let fake_certificates = setup_certificate_chain(total_certificates, certificates_per_epoch); + let genesis_certificate = fake_certificates.genesis_certificate(); let mock_container = MockDependencyInjector::new(); let verifier = mock_container.build_certificate_verifier(); let verify = verifier .verify_certificate( - &genesis_certificate, - &genesis_verifier.to_verification_key(), + genesis_certificate, + &fake_certificates.genesis_verifier.to_verification_key(), ) .await; @@ -938,8 +922,7 @@ mod tests { #[tokio::test] async fn verify_certificate_success_when_certificate_is_standard_and_valid() { let (total_certificates, certificates_per_epoch) = (5, 1); - let (fake_certificates, genesis_verifier) = - setup_certificate_chain(total_certificates, certificates_per_epoch); + let fake_certificates = setup_certificate_chain(total_certificates, certificates_per_epoch); let certificate = fake_certificates[0].clone(); let previous_certificate = fake_certificates[1].clone(); let mut mock_container = MockDependencyInjector::new(); @@ -951,7 +934,10 @@ mod tests { let verifier = mock_container.build_certificate_verifier(); let verify = verifier - .verify_certificate(&certificate, &genesis_verifier.to_verification_key()) + .verify_certificate( + &certificate, + &fake_certificates.genesis_verifier.to_verification_key(), + ) .await; verify.expect("verify_certificate should not fail"); @@ -1013,8 +999,7 @@ mod tests { } let (total_certificates, certificates_per_epoch) = (10, 1); - let (fake_certificates, genesis_verifier) = - setup_certificate_chain(total_certificates, certificates_per_epoch); + let fake_certificates = setup_certificate_chain(total_certificates, certificates_per_epoch); let fake_certificate_to_verify = fake_certificates[0].clone(); let verifier = CertificateVerifierTest::from_certificates(&fake_certificates); assert!(verifier.has_unverified_certificates().await); @@ -1022,7 +1007,7 @@ mod tests { let verify = verifier .verify_certificate_chain( fake_certificate_to_verify, - &genesis_verifier.to_verification_key(), + &fake_certificates.genesis_verifier.to_verification_key(), ) .await; @@ -1033,8 +1018,7 @@ mod tests { #[tokio::test] async fn verify_certificate_chain_success_when_chain_is_valid() { let (total_certificates, certificates_per_epoch) = (7, 2); - let (fake_certificates, genesis_verifier) = - setup_certificate_chain(total_certificates, certificates_per_epoch); + let fake_certificates = setup_certificate_chain(total_certificates, certificates_per_epoch); let certificate_retriever = FakeCertificaterRetriever::from_certificates(&fake_certificates); let verifier = @@ -1044,7 +1028,7 @@ mod tests { let verify = verifier .verify_certificate_chain( certificate_to_verify, - &genesis_verifier.to_verification_key(), + &fake_certificates.genesis_verifier.to_verification_key(), ) .await; verify.expect("verify_certificate_chain should not fail"); @@ -1053,7 +1037,7 @@ mod tests { #[tokio::test] async fn verify_certificate_chain_fails_when_chain_is_tampered() { let (total_certificates, certificates_per_epoch) = (7, 2); - let (mut fake_certificates, genesis_verifier) = + let mut fake_certificates = setup_certificate_chain(total_certificates, certificates_per_epoch); let index_certificate_fail = (total_certificates / 2) as usize; fake_certificates[index_certificate_fail].signed_message = "tampered-message".to_string(); @@ -1066,7 +1050,7 @@ mod tests { let error = verifier .verify_certificate_chain( certificate_to_verify, - &genesis_verifier.to_verification_key(), + &fake_certificates.genesis_verifier.to_verification_key(), ) .await .expect_err("verify_certificate_chain should fail"); @@ -1125,7 +1109,7 @@ mod tests { } let (total_certificates, certificates_per_epoch) = (7, 2); - let (fake_certificates, genesis_verifier) = CertificateChainBuilder::new() + let fake_certificates = CertificateChainBuilder::new() .with_total_certificates(total_certificates) .with_certificates_per_epoch(certificates_per_epoch) .with_standard_certificate_processor(&|certificate, context| { @@ -1146,7 +1130,7 @@ mod tests { let error = verifier .verify_certificate( &certificate_to_verify, - &genesis_verifier.to_verification_key(), + &fake_certificates.genesis_verifier.to_verification_key(), ) .await .expect_err("verify_certificate_chain should fail"); diff --git a/mithril-common/src/crypto_helper/tests_setup.rs b/mithril-common/src/crypto_helper/tests_setup.rs index 1dfef479521..1f8071dc740 100644 --- a/mithril-common/src/crypto_helper/tests_setup.rs +++ b/mithril-common/src/crypto_helper/tests_setup.rs @@ -6,11 +6,11 @@ use rand_core::SeedableRng; use crate::{ crypto_helper::{cardano::KesSignerStandard, KesSigner}, - entities::{Certificate, ProtocolMessage, ProtocolMessagePartKey, SignerWithStake, Stake}, - test_utils::{CertificateChainBuilder, SignerFixture, TempDir}, + entities::{ProtocolMessage, ProtocolMessagePartKey, SignerWithStake, Stake}, + test_utils::{CertificateChainBuilder, CertificateChainFixture, SignerFixture, TempDir}, }; -use super::{ed25519_alias::genesis::*, types::*, OpCert, SerDeShelleyFileFormat}; +use super::{types::*, OpCert, SerDeShelleyFileFormat}; /// Create or retrieve a temporary directory for storing cryptographic material for a signer, use this for tests only. pub fn setup_temp_directory_for_signer( @@ -195,11 +195,10 @@ pub fn setup_signers_from_stake_distribution( pub fn setup_certificate_chain( total_certificates: u64, certificates_per_epoch: u64, -) -> (Vec, ProtocolGenesisVerifier) { - let certificate_chain_builder = CertificateChainBuilder::new() +) -> CertificateChainFixture { + CertificateChainBuilder::new() .with_total_certificates(total_certificates) .with_certificates_per_epoch(certificates_per_epoch) - .with_protocol_parameters(setup_protocol_parameters()); - - certificate_chain_builder.build() + .with_protocol_parameters(setup_protocol_parameters()) + .build() } diff --git a/mithril-common/src/test_utils/certificate_chain_builder.rs b/mithril-common/src/test_utils/certificate_chain_builder.rs index 8f4a0ad4499..d72fc93bbe9 100644 --- a/mithril-common/src/test_utils/certificate_chain_builder.rs +++ b/mithril-common/src/test_utils/certificate_chain_builder.rs @@ -1,21 +1,22 @@ +use std::cmp::min; +use std::collections::{BTreeSet, HashMap}; +use std::iter::repeat_n; +use std::ops::{Deref, DerefMut}; +use std::sync::Arc; + use crate::{ certificate_chain::CertificateGenesisProducer, crypto_helper::{ ProtocolAggregateVerificationKey, ProtocolClerk, ProtocolGenesisSigner, ProtocolGenesisVerifier, ProtocolParameters, }, - entities::{Certificate, CertificateSignature, Epoch, ProtocolMessage, ProtocolMessagePartKey}, + entities::{ + CardanoDbBeacon, Certificate, CertificateMetadata, CertificateSignature, Epoch, + ProtocolMessage, ProtocolMessagePartKey, SignedEntityType, + }, test_utils::{fake_data, MithrilFixture, MithrilFixtureBuilder, SignerFixture}, }; -use crate::entities::CertificateMetadata; -use std::{ - cmp::min, - collections::{BTreeSet, HashMap}, - iter::repeat_n, - sync::Arc, -}; - /// Genesis certificate processor function type. For tests only. type GenesisCertificateProcessorFunc = dyn Fn(Certificate, &CertificateChainBuilderContext, &ProtocolGenesisSigner) -> Certificate; @@ -96,6 +97,71 @@ pub enum CertificateChainingMethod { Sequential, } +/// Fixture built from a [CertificateChainBuilder], certificates are ordered from latest to genesis +#[derive(Debug, Clone)] +pub struct CertificateChainFixture { + /// The full certificates list, ordered from latest to genesis + pub certificates_chained: Vec, + /// The genesis verifier associated with this chain genesis certificate + pub genesis_verifier: ProtocolGenesisVerifier, +} + +impl Deref for CertificateChainFixture { + type Target = [Certificate]; + + fn deref(&self) -> &Self::Target { + &self.certificates_chained + } +} + +impl DerefMut for CertificateChainFixture { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.certificates_chained + } +} + +impl> From for Vec { + fn from(fixture: CertificateChainFixture) -> Self { + fixture + .certificates_chained + .into_iter() + .map(C::from) + .collect() + } +} + +impl CertificateChainFixture { + /// Return the genesis certificate of this chain + pub fn genesis_certificate(&self) -> &Certificate { + &self.certificates_chained[self.certificates_chained.len() - 1] + } + + /// Return a copy of the chain but with reversed order (from genesis to last) + pub fn reversed_chain(&self) -> Vec { + self.certificates_chained.iter().rev().cloned().collect() + } + + /// Extract the chain starting from the certificate with the given hash and all its parents + /// until the genesis certificate. + pub fn certificate_path_to_genesis>( + &self, + certificate_hash: H, + ) -> Vec { + let mut subchain = Vec::new(); + let mut hash_to_search = certificate_hash.as_ref().to_string(); + + // takes advantage of the fact that chained certificates are ordered from last to genesis + for certificate in &self.certificates_chained { + if certificate.hash == hash_to_search { + subchain.push(certificate.clone()); + hash_to_search = certificate.previous_hash.clone(); + } + } + + subchain + } +} + /// A builder for creating a certificate chain. For tests only. /// /// # Simple example usage for building a fully valid certificate chain @@ -104,12 +170,12 @@ pub enum CertificateChainingMethod { /// use mithril_common::crypto_helper::ProtocolParameters; /// use mithril_common::test_utils::CertificateChainBuilder; /// -/// let (certificate_chain, _protocol_genesis_verifier) = CertificateChainBuilder::new() +/// let certificate_chain_fixture = CertificateChainBuilder::new() /// .with_total_certificates(5) /// .with_certificates_per_epoch(2) /// .build(); /// -/// assert_eq!(5, certificate_chain.len()); +/// assert_eq!(5, certificate_chain_fixture.len()); /// ``` /// /// # More complex example usage for building a fully valid certificate chain @@ -119,7 +185,7 @@ pub enum CertificateChainingMethod { /// use mithril_common::crypto_helper::ProtocolParameters; /// use mithril_common::test_utils::CertificateChainBuilder; /// -/// let (certificate_chain, _protocol_genesis_verifier) = CertificateChainBuilder::new() +/// let certificate_chain_fixture = CertificateChainBuilder::new() /// .with_total_certificates(5) /// .with_certificates_per_epoch(2) /// .with_protocol_parameters(ProtocolParameters { @@ -130,7 +196,7 @@ pub enum CertificateChainingMethod { /// .with_total_signers_per_epoch_processor(&|epoch| min(1 + *epoch as usize, 10)) /// .build(); /// -/// assert_eq!(5, certificate_chain.len()); +/// assert_eq!(5, certificate_chain_fixture.len()); /// ``` /// /// # Advanced example usage for building an adversarial certificate chain @@ -140,7 +206,7 @@ pub enum CertificateChainingMethod { /// use mithril_common::crypto_helper::ProtocolParameters; /// use mithril_common::test_utils::CertificateChainBuilder; /// -/// let (certificate_chain, _protocol_genesis_verifier) = CertificateChainBuilder::new() +/// let certificate_chain_fixture = CertificateChainBuilder::new() /// .with_total_certificates(5) /// .with_certificates_per_epoch(2) /// .with_standard_certificate_processor(&|certificate, context| { @@ -154,7 +220,7 @@ pub enum CertificateChainingMethod { /// }) /// .build(); /// -/// assert_eq!(5, certificate_chain.len()); +/// assert_eq!(5, certificate_chain_fixture.len()); /// ``` pub struct CertificateChainBuilder<'a> { total_certificates: u64, @@ -247,7 +313,7 @@ impl<'a> CertificateChainBuilder<'a> { } /// Build the certificate chain. - pub fn build(self) -> (Vec, ProtocolGenesisVerifier) { + pub fn build(self) -> CertificateChainFixture { let (genesis_signer, genesis_verifier) = CertificateChainBuilder::setup_genesis(); let genesis_certificate_processor = self.genesis_certificate_processor; let standard_certificate_processor = self.standard_certificate_processor; @@ -279,7 +345,10 @@ impl<'a> CertificateChainBuilder<'a> { .collect::>(); let certificates_chained = self.compute_chained_certificates(certificates); - (certificates_chained, genesis_verifier) + CertificateChainFixture { + certificates_chained, + genesis_verifier, + } } fn compute_clerk_for_signers(signers: &[SignerFixture]) -> ProtocolClerk { @@ -438,7 +507,10 @@ impl<'a> CertificateChainBuilder<'a> { .aggregate(&single_signatures, certificate.signed_message.as_bytes()) .unwrap(); certificate.signature = CertificateSignature::MultiSignature( - certificate.signed_entity_type(), + SignedEntityType::CardanoDatabase(CardanoDbBeacon::new( + *context.epoch, + context.index_certificate as u64, + )), multi_signature.into(), ); @@ -565,12 +637,12 @@ mod test { total_certificates: u64, certificates_per_epoch: u64, ) -> Vec { - let (certificate_chain, _) = CertificateChainBuilder::default() + let certificate_chain_fixture = CertificateChainBuilder::default() .with_total_certificates(total_certificates) .with_certificates_per_epoch(certificates_per_epoch) .build(); - certificate_chain + certificate_chain_fixture.certificates_chained } #[test] @@ -750,6 +822,10 @@ mod test { .build_genesis_certificate(&context, &protocol_genesis_signer); assert!(genesis_certificate.is_genesis()); + assert_eq!( + SignedEntityType::genesis(Epoch(1)), + genesis_certificate.signed_entity_type() + ); assert_eq!(Epoch(1), genesis_certificate.epoch); assert_eq!( expected_protocol_parameters, @@ -798,6 +874,10 @@ mod test { .build_standard_certificate(&context); assert!(!standard_certificate.is_genesis()); + assert_eq!( + SignedEntityType::CardanoDatabase(CardanoDbBeacon::new(1, 2)), + standard_certificate.signed_entity_type() + ); assert_eq!(Epoch(1), standard_certificate.epoch); assert_eq!( expected_protocol_parameters, @@ -937,7 +1017,7 @@ mod test { #[test] fn builds_certificate_chain_with_alteration_on_genesis_certificate() { - let (certificates, _) = CertificateChainBuilder::new() + let certificate_chain_fixture = CertificateChainBuilder::new() .with_total_certificates(5) .with_genesis_certificate_processor(&|certificate, _, _| { let mut certificate = certificate; @@ -949,7 +1029,7 @@ mod test { assert_eq!( "altered_msg".to_string(), - certificates.last().unwrap().signed_message + certificate_chain_fixture.last().unwrap().signed_message ); } @@ -961,7 +1041,7 @@ mod test { .map(|i| format!("altered-msg-{i}")) .collect::>(); - let (certificates, _) = CertificateChainBuilder::new() + let certificate_chain_fixture = CertificateChainBuilder::new() .with_total_certificates(total_certificates) .with_standard_certificate_processor(&|certificate, context| { let mut certificate = certificate; @@ -971,11 +1051,79 @@ mod test { }) .build(); - let signed_message = certificates + let signed_message = certificate_chain_fixture + .certificates_chained .into_iter() .take(total_certificates as usize - 1) .map(|certificate| certificate.signed_message) .collect::>(); assert_eq!(expected_signed_messages, signed_message); } + + mod certificate_chain_fixture { + use super::*; + + #[test] + fn get_genesis_certificate() { + let chain_with_only_a_genesis = CertificateChainBuilder::new() + .with_total_certificates(1) + .build(); + assert!(chain_with_only_a_genesis.genesis_certificate().is_genesis()); + + let chain_with_multiple_certificates = CertificateChainBuilder::new() + .with_total_certificates(10) + .build(); + assert!(chain_with_multiple_certificates + .genesis_certificate() + .is_genesis()); + } + + #[test] + fn path_to_genesis_from_a_chain_with_one_certificate_per_epoch() { + let chain = CertificateChainBuilder::new() + .with_total_certificates(5) + .with_certificates_per_epoch(1) + .build(); + + assert_eq!( + chain.certificate_path_to_genesis(&chain[0].hash), + chain.certificates_chained + ); + } + + #[test] + fn path_to_genesis_from_a_chain_with_multiple_certificates_per_epoch() { + let chain = CertificateChainBuilder::new() + .with_total_certificates(9) + .with_certificates_per_epoch(3) + .build(); + + let expected_subchain = vec![ + chain[1].clone(), + chain[4].clone(), + chain[7].clone(), + chain[8].clone(), + ]; + assert_eq!( + chain.certificate_path_to_genesis(&chain[1].hash), + expected_subchain + ); + } + + #[test] + fn reversed_chain() { + let chain = CertificateChainBuilder::new() + .with_total_certificates(5) + .with_certificates_per_epoch(2) + .build(); + + let expected: Vec = chain + .certificates_chained + .clone() + .into_iter() + .rev() + .collect(); + assert_eq!(chain.reversed_chain(), expected); + } + } } diff --git a/mithril-common/src/test_utils/mock_extensions.rs b/mithril-common/src/test_utils/mock_extensions.rs new file mode 100644 index 00000000000..d4644230ded --- /dev/null +++ b/mithril-common/src/test_utils/mock_extensions.rs @@ -0,0 +1,61 @@ +//! A set of tools for working with `automock` +//! +//! IMPORTANT: To avoid polluting production code, those tools do not expose or reexpose any +//! `automock`types, users need to add them themselves to their crates. +use std::sync::Arc; + +/// Helper to create configured Mockall mock. +/// +/// This allows creation of the mock in a dedicated block isolated from the remaining test method +/// code. +pub struct MockBuilder { + phantom: std::marker::PhantomData, +} + +impl MockBuilder { + /// Create a new instance of the mock with the given configuration + /// + /// The type must be specified either: + /// ``` + /// use mithril_common::test_utils::mock_extensions::MockBuilder; + /// # #[derive(Default)] struct MockType {}; + /// + /// // from the builder generic + /// let mock = MockBuilder::::configure(|mock| {}); + /// + /// // or from the closure parameter + /// let mock = MockBuilder::configure(|mock: &mut MockType| {}); + /// ``` + pub fn configure(mock_config: impl FnOnce(&mut M)) -> Arc { + let mut mock = M::default(); + mock_config(&mut mock); + Arc::new(mock) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[mockall::automock] + trait TestTrait { + fn test_method(&self) -> String; + } + + #[test] + fn using_mock_builder() { + // specify the type on the closure parameter + let mock = MockBuilder::configure(|mock: &mut MockTestTrait| { + mock.expect_test_method() + .returning(|| "test explicit type".to_string()); + }); + assert_eq!("test explicit type".to_string(), mock.test_method()); + + // specify the type on the builder generic + let mock = MockBuilder::::configure(|mock| { + mock.expect_test_method() + .returning(|| "test turbofish".to_string()); + }); + assert_eq!("test turbofish".to_string(), mock.test_method()); + } +} diff --git a/mithril-common/src/test_utils/mod.rs b/mithril-common/src/test_utils/mod.rs index 08d29a6182c..535e27de0f0 100644 --- a/mithril-common/src/test_utils/mod.rs +++ b/mithril-common/src/test_utils/mod.rs @@ -8,6 +8,7 @@ pub mod fake_data; pub mod fake_keys; +pub mod mock_extensions; mod cardano_transactions_builder; mod certificate_chain_builder; @@ -20,7 +21,8 @@ mod temp_dir; pub use cardano_transactions_builder::CardanoTransactionsBuilder; pub use certificate_chain_builder::{ - CertificateChainBuilder, CertificateChainBuilderContext, CertificateChainingMethod, + CertificateChainBuilder, CertificateChainBuilderContext, CertificateChainFixture, + CertificateChainingMethod, }; pub use dir_eq::*; pub use fixture_builder::{MithrilFixtureBuilder, StakeDistributionGenerationMethod};