Skip to content

Commit c5fa040

Browse files
committed
test(aggregator): update tooling to check cert have associated signed entity only if not synchronized
Has synchronised certificate are created without a signed entity, previouysly it was only the case for genesis certificates.
1 parent 930ee6e commit c5fa040

File tree

2 files changed

+104
-70
lines changed

2 files changed

+104
-70
lines changed

mithril-aggregator/tests/test_extensions/runtime_tester.rs

Lines changed: 86 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ use mithril_common::{
3636
use mithril_era::{EraMarker, EraReader, adapters::EraReaderDummyAdapter};
3737

3838
use crate::test_extensions::leader_aggregator_http_server::LeaderAggregatorHttpServer;
39-
use crate::test_extensions::utilities::tx_hash;
39+
use crate::test_extensions::utilities::{async_wait, tx_hash};
4040
use crate::test_extensions::{AggregatorObserver, ExpectedCertificate, MetricsVerifier};
4141

4242
#[macro_export]
@@ -67,9 +67,10 @@ macro_rules! cycle_err {
6767
let (runtime_cycle_success, runtime_cycle_total) =
6868
$tester.get_runtime_cycle_success_and_total_since_startup_metrics();
6969

70-
RuntimeTester::cycle(&mut $tester)
70+
let err = RuntimeTester::cycle(&mut $tester)
7171
.await
7272
.expect_err("cycle tick should have returned an error");
73+
slog_scope::info!("cycle_err result: {err:?}");
7374
assert_eq!($expected_state, $tester.runtime.get_state());
7475

7576
assert_metrics_eq!(
@@ -85,12 +86,30 @@ macro_rules! cycle_err {
8586
macro_rules! assert_last_certificate_eq {
8687
( $tester:expr, $expected_certificate:expr ) => {{
8788
if let Some(signed_type) = $expected_certificate.get_signed_type() {
88-
$tester.wait_until_signed_entity(&signed_type).await.unwrap();
89+
RuntimeTester::wait_until_signed_entity(&$tester, &signed_type)
90+
.await
91+
.unwrap();
8992
}
9093

91-
let last_certificate = RuntimeTester::get_last_expected_certificate(&mut $tester)
92-
.await
93-
.unwrap();
94+
let is_synchronized_from_leader = false;
95+
let last_certificate =
96+
RuntimeTester::get_last_expected_certificate(&mut $tester, is_synchronized_from_leader)
97+
.await
98+
.unwrap();
99+
assert_eq!($expected_certificate, last_certificate);
100+
}};
101+
( $tester:expr, synchronised_from_leader => $expected_certificate:expr ) => {{
102+
if let Some(signed_type) = $expected_certificate.get_signed_type() {
103+
RuntimeTester::wait_until_certificate(&$tester, &signed_type)
104+
.await
105+
.unwrap();
106+
}
107+
108+
let is_synchronized_from_leader = true;
109+
let last_certificate =
110+
RuntimeTester::get_last_expected_certificate(&mut $tester, is_synchronized_from_leader)
111+
.await
112+
.unwrap();
94113
assert_eq!($expected_certificate, last_certificate);
95114
}};
96115
}
@@ -538,12 +557,11 @@ impl RuntimeTester {
538557
Ok(())
539558
}
540559

541-
/// Get the last produced certificate with its signed entity if it's not a genesis certificate
542-
pub async fn get_last_certificate_with_signed_entity(
560+
/// Get the last produced signed entity
561+
async fn get_last_signed_entity(
543562
&mut self,
544-
) -> StdResult<(Certificate, Option<SignedEntityRecord>)> {
545-
let certificate = self.observer.get_last_certificate().await?;
546-
563+
certificate: &Certificate,
564+
) -> StdResult<Option<SignedEntityRecord>> {
547565
let signed_entity = match &certificate.signature {
548566
CertificateSignature::GenesisSignature(..) => None,
549567
CertificateSignature::MultiSignature(..) => {
@@ -560,37 +578,40 @@ impl RuntimeTester {
560578
}
561579
};
562580

563-
Ok((certificate, signed_entity))
581+
Ok(signed_entity)
564582
}
565583

566584
/// Get the last produced certificate and transform it to a [ExpectedCertificate]
567-
pub async fn get_last_expected_certificate(&mut self) -> StdResult<ExpectedCertificate> {
568-
let (certificate, signed_entity_record) =
569-
self.get_last_certificate_with_signed_entity().await?;
585+
pub async fn get_last_expected_certificate(
586+
&mut self,
587+
is_synchronized_from_leader: bool,
588+
) -> StdResult<ExpectedCertificate> {
589+
let certificate = self.observer.get_last_certificate().await?;
570590

571-
let expected_certificate = match signed_entity_record {
572-
None if certificate.is_genesis() => ExpectedCertificate::new_genesis(
591+
let expected_certificate = if certificate.is_genesis() {
592+
ExpectedCertificate::new_genesis(
573593
certificate.epoch,
574594
certificate.aggregate_verification_key.try_into().unwrap(),
575-
),
576-
None => {
577-
panic!(
595+
)
596+
} else {
597+
let signed_entity_type = certificate.signed_entity_type();
598+
let previous_cert_identifier = self
599+
.get_expected_certificate_identifier(&certificate.previous_hash)
600+
.await?;
601+
602+
if !is_synchronized_from_leader && !certificate.is_genesis() {
603+
self.get_last_signed_entity(&certificate).await?.ok_or(anyhow!(
578604
"A certificate should always have a SignedEntity if it's not a genesis certificate"
579-
);
580-
}
581-
Some(record) => {
582-
let previous_cert_identifier = self
583-
.get_expected_certificate_identifier(&certificate.previous_hash)
584-
.await?;
585-
586-
ExpectedCertificate::new(
587-
certificate.epoch,
588-
certificate.metadata.signers.as_slice(),
589-
certificate.aggregate_verification_key.try_into().unwrap(),
590-
record.signed_entity_type,
591-
previous_cert_identifier,
592-
)
605+
))?;
593606
}
607+
608+
ExpectedCertificate::new(
609+
certificate.epoch,
610+
certificate.metadata.signers.as_slice(),
611+
certificate.aggregate_verification_key.try_into().unwrap(),
612+
signed_entity_type,
613+
previous_cert_identifier,
614+
)
594615
};
595616

596617
Ok(expected_certificate)
@@ -601,30 +622,22 @@ impl RuntimeTester {
601622
&mut self,
602623
certificate_hash: &str,
603624
) -> StdResult<String> {
604-
let cert_identifier = match self
625+
let certificate = self
605626
.dependencies
606-
.signed_entity_storer
607-
.get_signed_entity_by_certificate_id(certificate_hash)
627+
.certificate_repository
628+
.get_certificate::<Certificate>(certificate_hash)
608629
.await
609-
.with_context(|| "Querying signed entity should not fail")?
610-
{
611-
Some(record) => ExpectedCertificate::identifier(&record.signed_entity_type),
612-
None => {
613-
// Certificate is a genesis certificate
614-
let genesis_certificate = self
615-
.dependencies
616-
.certifier_service
617-
.get_certificate_by_hash(certificate_hash)
618-
.await
619-
.with_context(|| "Querying genesis certificate should not fail")?
620-
.ok_or(anyhow!(
621-
"A genesis certificate should exist with hash {}",
622-
certificate_hash
623-
))?;
624-
ExpectedCertificate::genesis_identifier(genesis_certificate.epoch)
625-
}
626-
};
630+
.with_context(|| format!("Failed to query certificate with hash {certificate_hash}"))?
631+
.ok_or(anyhow!(
632+
"A certificate should exist with hash {}",
633+
certificate_hash
634+
))?;
627635

636+
let cert_identifier = if certificate.is_genesis() {
637+
ExpectedCertificate::genesis_identifier(certificate.epoch)
638+
} else {
639+
ExpectedCertificate::identifier(&certificate.signed_entity_type())
640+
};
628641
Ok(cert_identifier)
629642
}
630643

@@ -634,22 +647,25 @@ impl RuntimeTester {
634647
&self,
635648
signed_entity_type_expected: &SignedEntityType,
636649
) -> StdResult<()> {
637-
let mut max_iteration = 100;
638-
while !self
639-
.observer
640-
.is_last_signed_entity(signed_entity_type_expected)
641-
.await?
642-
{
643-
max_iteration -= 1;
644-
if max_iteration <= 0 {
645-
return Err(anyhow!(
646-
"Signed entity not found: {signed_entity_type_expected}"
647-
));
648-
}
649-
tokio::time::sleep(Duration::from_millis(1)).await;
650-
}
650+
async_wait!(
651+
max_iter:100, sleep_ms:1,
652+
condition: !self.observer.is_last_signed_entity(signed_entity_type_expected).await?,
653+
error_msg: "Signed entity not found: {signed_entity_type_expected}"
654+
)
655+
}
651656

652-
Ok(())
657+
/// Wait until the last stored certificate of the given signed entity type
658+
/// corresponds to the expected signed entity type
659+
pub async fn wait_until_certificate(
660+
&self,
661+
certificate_signed_entity_type: &SignedEntityType,
662+
) -> StdResult<()> {
663+
async_wait!(
664+
max_iter:100, sleep_ms:1,
665+
condition: self.observer.get_last_certificate().await?.signed_entity_type()
666+
!= *certificate_signed_entity_type,
667+
error_msg: "Certificate not found for signed entity: {certificate_signed_entity_type}"
668+
)
653669
}
654670

655671
/// Returns the runtime cycle success and total metrics since startup

mithril-aggregator/tests/test_extensions/utilities.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,21 @@ macro_rules! comment {
2929
test_extensions::utilities::comment(format!($($comment)*));
3030
}};
3131
}
32+
33+
#[macro_export]
34+
macro_rules! async_wait {
35+
( max_iter:$max_iter:expr, sleep_ms:$sleep_ms:expr, condition:$condition:expr, error_msg:$($error_msg:tt)*
36+
) => {{
37+
let mut max_iteration: usize = $max_iter;
38+
while $condition {
39+
max_iteration -= 1;
40+
if max_iteration == 0 {
41+
return Err(anyhow::anyhow!($($error_msg)*));
42+
}
43+
tokio::time::sleep(Duration::from_millis($sleep_ms)).await;
44+
}
45+
46+
Ok(())
47+
}};
48+
}
49+
pub use async_wait;

0 commit comments

Comments
 (0)