Skip to content

Commit 99f52a4

Browse files
committed
test(common): allow to chain certificates to direct predecessor when using certificate chain builder
1 parent 5850048 commit 99f52a4

File tree

2 files changed

+114
-22
lines changed

2 files changed

+114
-22
lines changed

mithril-common/src/test_utils/certificate_chain_builder.rs

Lines changed: 111 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,20 @@ impl<'a> CertificateChainBuilderContext<'a> {
8282
}
8383
}
8484

85+
/// Chaining method to use when building a certificate chain with the [CertificateChainBuilder]. For tests only.
86+
#[derive(Debug, Clone, Copy, PartialEq, Default)]
87+
pub enum CertificateChainingMethod {
88+
/// `default` Chain certificates to the 'master' certificate of the epoch or if it's the 'master'
89+
/// certificate, chain it to the 'master' certificate of the previous epoch.
90+
///
91+
/// The 'master' certificate of an epoch is the first certificate of the epoch.
92+
#[default]
93+
ToMasterCertificate,
94+
95+
/// Chain certificates to their direct predecessor.
96+
ToDirectPredecessor,
97+
}
98+
8599
/// A builder for creating a certificate chain. For tests only.
86100
///
87101
/// # Simple example usage for building a fully valid certificate chain
@@ -149,6 +163,7 @@ pub struct CertificateChainBuilder<'a> {
149163
total_signers_per_epoch_processor: &'a TotalSignersPerEpochProcessorFunc,
150164
genesis_certificate_processor: &'a GenesisCertificateProcessorFunc,
151165
standard_certificate_processor: &'a StandardCertificateProcessorFunc,
166+
certificate_chaining_method: CertificateChainingMethod,
152167
}
153168

154169
impl<'a> CertificateChainBuilder<'a> {
@@ -166,6 +181,7 @@ impl<'a> CertificateChainBuilder<'a> {
166181
total_signers_per_epoch_processor: &|epoch| min(2 + *epoch as usize, 5),
167182
genesis_certificate_processor: &|certificate, _, _| certificate,
168183
standard_certificate_processor: &|certificate, _| certificate,
184+
certificate_chaining_method: Default::default(),
169185
}
170186
}
171187

@@ -220,6 +236,16 @@ impl<'a> CertificateChainBuilder<'a> {
220236
self
221237
}
222238

239+
/// Set the chaining method to use when building the certificate chain.
240+
pub fn with_certificate_chaining_method(
241+
mut self,
242+
certificate_chaining_method: CertificateChainingMethod,
243+
) -> Self {
244+
self.certificate_chaining_method = certificate_chaining_method;
245+
246+
self
247+
}
248+
223249
/// Build the certificate chain.
224250
pub fn build(self) -> (Vec<Certificate>, ProtocolGenesisVerifier) {
225251
let (genesis_signer, genesis_verifier) = CertificateChainBuilder::setup_genesis();
@@ -438,26 +464,31 @@ impl<'a> CertificateChainBuilder<'a> {
438464
certificate: &Certificate,
439465
certificates_chained: &'b [Certificate],
440466
) -> Option<&'b Certificate> {
441-
let is_certificate_first_of_epoch = certificates_chained
442-
.last()
443-
.map(|c| c.epoch != certificate.epoch)
444-
.unwrap_or(true);
445-
446-
certificates_chained
447-
.iter()
448-
.rev()
449-
.filter(|c| {
450-
if is_certificate_first_of_epoch {
451-
// The previous certificate of the first certificate of an epoch
452-
// is the first certificate of the previous epoch
453-
c.epoch == certificate.epoch.previous().unwrap()
454-
} else {
455-
// The previous certificate of not the first certificate of an epoch
456-
// is the first certificate of the epoch
457-
c.epoch == certificate.epoch
458-
}
459-
})
460-
.last()
467+
match self.certificate_chaining_method {
468+
CertificateChainingMethod::ToMasterCertificate => {
469+
let is_certificate_first_of_epoch = certificates_chained
470+
.last()
471+
.map(|c| c.epoch != certificate.epoch)
472+
.unwrap_or(true);
473+
474+
certificates_chained
475+
.iter()
476+
.rev()
477+
.filter(|c| {
478+
if is_certificate_first_of_epoch {
479+
// The previous certificate of the first certificate of an epoch
480+
// is the first certificate of the previous epoch
481+
c.epoch == certificate.epoch.previous().unwrap()
482+
} else {
483+
// The previous certificate of not the first certificate of an epoch
484+
// is the first certificate of the epoch
485+
c.epoch == certificate.epoch
486+
}
487+
})
488+
.last()
489+
}
490+
CertificateChainingMethod::ToDirectPredecessor => certificates_chained.last(),
491+
}
461492
}
462493

463494
// Returns the chained certificates in reverse order
@@ -788,7 +819,7 @@ mod test {
788819
}
789820

790821
#[test]
791-
fn builds_certificate_chain_correctly_chained() {
822+
fn builds_certificate_chain_chained_by_default_to_master_certificates() {
792823
fn create_fake_certificate(epoch: Epoch, index_in_epoch: u64) -> Certificate {
793824
Certificate {
794825
epoch,
@@ -845,6 +876,65 @@ mod test {
845876
);
846877
}
847878

879+
#[test]
880+
fn builds_certificate_chain_chained_to_direct_previous_if_option_set() {
881+
fn create_fake_certificate(epoch: Epoch, index_in_epoch: u64) -> Certificate {
882+
Certificate {
883+
epoch,
884+
signed_message: format!("certificate-{}-{index_in_epoch}", *epoch),
885+
..fake_data::certificate("cert-fake".to_string())
886+
}
887+
}
888+
889+
let certificates = vec![
890+
create_fake_certificate(Epoch(1), 1),
891+
create_fake_certificate(Epoch(2), 1),
892+
create_fake_certificate(Epoch(2), 2),
893+
create_fake_certificate(Epoch(3), 1),
894+
create_fake_certificate(Epoch(4), 1),
895+
create_fake_certificate(Epoch(4), 2),
896+
create_fake_certificate(Epoch(4), 3),
897+
];
898+
899+
let mut certificates_chained = CertificateChainBuilder::default()
900+
.with_certificate_chaining_method(CertificateChainingMethod::ToDirectPredecessor)
901+
.compute_chained_certificates(certificates);
902+
certificates_chained.reverse();
903+
904+
let certificate_chained_1_1 = &certificates_chained[0];
905+
let certificate_chained_2_1 = &certificates_chained[1];
906+
let certificate_chained_2_2 = &certificates_chained[2];
907+
let certificate_chained_3_1 = &certificates_chained[3];
908+
let certificate_chained_4_1 = &certificates_chained[4];
909+
let certificate_chained_4_2 = &certificates_chained[5];
910+
let certificate_chained_4_3 = &certificates_chained[6];
911+
assert_eq!("", certificate_chained_1_1.previous_hash);
912+
assert_eq!(
913+
certificate_chained_2_1.previous_hash,
914+
certificate_chained_1_1.hash
915+
);
916+
assert_eq!(
917+
certificate_chained_2_2.previous_hash,
918+
certificate_chained_2_1.hash
919+
);
920+
assert_eq!(
921+
certificate_chained_3_1.previous_hash,
922+
certificate_chained_2_2.hash
923+
);
924+
assert_eq!(
925+
certificate_chained_4_1.previous_hash,
926+
certificate_chained_3_1.hash
927+
);
928+
assert_eq!(
929+
certificate_chained_4_2.previous_hash,
930+
certificate_chained_4_1.hash
931+
);
932+
assert_eq!(
933+
certificate_chained_4_3.previous_hash,
934+
certificate_chained_4_2.hash
935+
);
936+
}
937+
848938
#[test]
849939
fn builds_certificate_chain_with_alteration_on_genesis_certificate() {
850940
let (certificates, _) = CertificateChainBuilder::new()

mithril-common/src/test_utils/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ mod temp_dir;
2525
pub mod test_http_server;
2626

2727
pub use cardano_transactions_builder::CardanoTransactionsBuilder;
28-
pub use certificate_chain_builder::{CertificateChainBuilder, CertificateChainBuilderContext};
28+
pub use certificate_chain_builder::{
29+
CertificateChainBuilder, CertificateChainBuilderContext, CertificateChainingMethod,
30+
};
2931
pub use fixture_builder::{MithrilFixtureBuilder, StakeDistributionGenerationMethod};
3032
pub use mithril_fixture::{MithrilFixture, SignerFixture};
3133
pub use temp_dir::*;

0 commit comments

Comments
 (0)