mithril_aggregator/services/certifier/
certifier_service.rs

1use anyhow::Context;
2use async_trait::async_trait;
3use chrono::Utc;
4use slog::{debug, info, trace, warn, Logger};
5use std::sync::Arc;
6
7use mithril_common::certificate_chain::CertificateVerifier;
8use mithril_common::crypto_helper::{ProtocolGenesisVerifier, PROTOCOL_VERSION};
9use mithril_common::entities::{
10    Certificate, CertificateMetadata, CertificateSignature, Epoch, ProtocolMessage,
11    SignedEntityType, SingleSignatures, StakeDistributionParty,
12};
13use mithril_common::logging::LoggerExtensions;
14use mithril_common::protocol::ToMessage;
15use mithril_common::{CardanoNetwork, StdResult};
16
17use crate::database::record::{OpenMessageRecord, OpenMessageWithSingleSignaturesRecord};
18use crate::database::repository::{
19    CertificateRepository, OpenMessageRepository, SingleSignatureRepository,
20};
21use crate::dependency_injection::EpochServiceWrapper;
22use crate::entities::OpenMessage;
23use crate::services::{CertifierService, CertifierServiceError, SignatureRegistrationStatus};
24use crate::MultiSigner;
25
26/// Mithril CertifierService implementation
27pub struct MithrilCertifierService {
28    network: CardanoNetwork,
29    open_message_repository: Arc<OpenMessageRepository>,
30    single_signature_repository: Arc<SingleSignatureRepository>,
31    certificate_repository: Arc<CertificateRepository>,
32    certificate_verifier: Arc<dyn CertificateVerifier>,
33    genesis_verifier: Arc<ProtocolGenesisVerifier>,
34    multi_signer: Arc<dyn MultiSigner>,
35    epoch_service: EpochServiceWrapper,
36    logger: Logger,
37}
38
39impl MithrilCertifierService {
40    /// instantiate the service
41    #[allow(clippy::too_many_arguments)]
42    pub fn new(
43        network: CardanoNetwork,
44        open_message_repository: Arc<OpenMessageRepository>,
45        single_signature_repository: Arc<SingleSignatureRepository>,
46        certificate_repository: Arc<CertificateRepository>,
47        certificate_verifier: Arc<dyn CertificateVerifier>,
48        genesis_verifier: Arc<ProtocolGenesisVerifier>,
49        multi_signer: Arc<dyn MultiSigner>,
50        epoch_service: EpochServiceWrapper,
51        logger: Logger,
52    ) -> Self {
53        Self {
54            network,
55            open_message_repository,
56            single_signature_repository,
57            certificate_repository,
58            multi_signer,
59            certificate_verifier,
60            genesis_verifier,
61            epoch_service,
62            logger: logger.new_with_component_name::<Self>(),
63        }
64    }
65
66    async fn get_open_message_record(
67        &self,
68        signed_entity_type: &SignedEntityType,
69    ) -> StdResult<Option<OpenMessageWithSingleSignaturesRecord>> {
70        debug!(
71            self.logger,
72            ">> get_open_message_record(signed_entity_type: {signed_entity_type:?})"
73        );
74
75        let open_message_with_single_signatures = self
76            .open_message_repository
77            .get_open_message_with_single_signatures(signed_entity_type)
78            .await
79            .with_context(|| format!("Certifier can not get open message with single signatures for signed entity type: '{signed_entity_type}'"))?;
80
81        Ok(open_message_with_single_signatures)
82    }
83}
84
85#[async_trait]
86impl CertifierService for MithrilCertifierService {
87    async fn inform_epoch(&self, epoch: Epoch) -> StdResult<()> {
88        debug!(self.logger, ">> inform_epoch(epoch: {epoch:?})");
89        let nb = self
90            .open_message_repository
91            .clean_epoch(epoch)
92            .await
93            .with_context(|| {
94                format!("Certifier can not clean open messages from epoch '{epoch}'")
95            })?;
96        info!(self.logger, "Informed of a new Epoch: {epoch:?}. Cleaned {nb} open messages along with their single signatures.");
97
98        Ok(())
99    }
100
101    async fn register_single_signature(
102        &self,
103        signed_entity_type: &SignedEntityType,
104        signature: &SingleSignatures,
105    ) -> StdResult<SignatureRegistrationStatus> {
106        debug!(self.logger, ">> register_single_signature(signed_entity_type: {signed_entity_type:?}, single_signatures: {signature:?}");
107        trace!(self.logger, ">> register_single_signature"; "complete_single_signatures" => #?signature);
108
109        let open_message = self
110            .get_open_message_record(signed_entity_type)
111            .await.with_context(|| format!("CertifierService can not get open message record for signed_entity_type: '{signed_entity_type}'"))?
112            .ok_or_else(|| {
113                warn!(self.logger, "register_single_signature: OpenMessage not found for type {signed_entity_type:?}.");
114                CertifierServiceError::NotFound(signed_entity_type.clone())
115            })?;
116
117        if open_message.is_certified {
118            warn!(self.logger, "register_single_signature: open message {signed_entity_type:?} is already certified, cannot register single signature.");
119
120            return Err(CertifierServiceError::AlreadyCertified(signed_entity_type.clone()).into());
121        }
122
123        if open_message.is_expired {
124            warn!(self.logger, "register_single_signature: open message {signed_entity_type:?} has expired, cannot register single signature.");
125
126            return Err(CertifierServiceError::Expired(signed_entity_type.clone()).into());
127        }
128
129        self.multi_signer
130            .verify_single_signature(&open_message.protocol_message.to_message(), signature)
131            .await
132            .map_err(|err| {
133                CertifierServiceError::InvalidSingleSignature(signed_entity_type.clone(), err)
134            })?;
135
136        let single_signature = self
137            .single_signature_repository
138            .create_single_signature(signature, &open_message.clone().into())
139            .await.with_context(|| format!("Certifier can not create the single signature from single_signature: '{signature:?}', open_message: '{open_message:?}'"))?;
140        info!(self.logger, "register_single_signature: created pool '{}' single signature for {signed_entity_type:?}.", single_signature.signer_id);
141        debug!(
142            self.logger,
143            "register_single_signature: created single signature for open message ID='{}'.",
144            single_signature.open_message_id
145        );
146
147        Ok(SignatureRegistrationStatus::Registered)
148    }
149
150    async fn create_open_message(
151        &self,
152        signed_entity_type: &SignedEntityType,
153        protocol_message: &ProtocolMessage,
154    ) -> StdResult<OpenMessage> {
155        debug!(
156            self.logger, ">> create_open_message(signed_entity_type: {signed_entity_type:?})";
157            "protocol_message" => ?protocol_message
158        );
159        let open_message = self
160            .open_message_repository
161            .create_open_message(
162                signed_entity_type.get_epoch_when_signed_entity_type_is_signed(),
163                signed_entity_type,
164                protocol_message,
165            )
166            .await
167            .with_context(|| {
168                format!(
169                    "Certifier can not create open message from protocol_message: '{:?}, epoch: '{}''",
170                    protocol_message,
171                    signed_entity_type.get_epoch_when_signed_entity_type_is_signed()
172                )
173            })?;
174        info!(
175            self.logger,
176            "create_open_message: created open message for {signed_entity_type:?}"
177        );
178        debug!(
179            self.logger,
180            "create_open_message: created open message ID='{}'", open_message.open_message_id
181        );
182
183        Ok(open_message.into())
184    }
185
186    async fn get_open_message(
187        &self,
188        signed_entity_type: &SignedEntityType,
189    ) -> StdResult<Option<OpenMessage>> {
190        debug!(
191            self.logger,
192            ">> get_open_message(signed_entity_type: {signed_entity_type:?})"
193        );
194
195        let open_message = self
196            .open_message_repository
197            .get_open_message_with_single_signatures(signed_entity_type)
198            .await
199            .with_context(|| format!("Certifier can not get open message with single signatures for signed entity type: '{signed_entity_type}'"))?
200            .map(|record| record.into());
201
202        Ok(open_message)
203    }
204
205    async fn mark_open_message_if_expired(
206        &self,
207        signed_entity_type: &SignedEntityType,
208    ) -> StdResult<Option<OpenMessage>> {
209        debug!(self.logger, ">> mark_open_message_if_expired");
210
211        let mut open_message_record = self
212            .open_message_repository
213            .get_expired_open_message(signed_entity_type)
214            .await
215            .with_context(|| "Certifier can not get expired open messages")?;
216        if let Some(open_message_record) = open_message_record.as_mut() {
217            open_message_record.is_expired = true;
218            self.open_message_repository
219                .update_open_message(open_message_record)
220                .await
221                .with_context(|| "Certifier can not update open message to mark it as expired")?;
222        }
223
224        Ok(open_message_record.map(|record| record.into()))
225    }
226
227    async fn create_certificate(
228        &self,
229        signed_entity_type: &SignedEntityType,
230    ) -> StdResult<Option<Certificate>> {
231        debug!(
232            self.logger,
233            ">> create_certificate(signed_entity_type: {signed_entity_type:?})"
234        );
235        let open_message_record = self
236            .get_open_message_record(signed_entity_type)
237            .await?
238            .ok_or_else(|| {
239                warn!(
240                    self.logger,
241                    "create_certificate: OpenMessage not found for type {signed_entity_type:?}."
242                );
243                CertifierServiceError::NotFound(signed_entity_type.clone())
244            })?;
245        let open_message: OpenMessage = open_message_record.clone().into();
246
247        if open_message.is_certified {
248            warn!(self.logger, "create_certificate: open message {signed_entity_type:?} is already certified, cannot create certificate.");
249
250            return Err(CertifierServiceError::AlreadyCertified(signed_entity_type.clone()).into());
251        }
252
253        if open_message.is_expired {
254            warn!(self.logger, "create_certificate: open message {signed_entity_type:?} is expired, cannot create certificate.");
255
256            return Err(CertifierServiceError::Expired(signed_entity_type.clone()).into());
257        }
258
259        let multi_signature = match self
260            .multi_signer
261            .create_multi_signature(&open_message)
262            .await?
263        {
264            None => {
265                debug!(self.logger, "create_certificate: No multi-signature could be created for open message {signed_entity_type:?}");
266                return Ok(None);
267            }
268            Some(signature) => {
269                info!(self.logger, "create_certificate: multi-signature created for open message {signed_entity_type:?}");
270                signature
271            }
272        };
273
274        let epoch_service = self.epoch_service.read().await;
275        let signer_ids = open_message.get_signers_id();
276        let signers = epoch_service
277            .current_signers_with_stake()?
278            .clone()
279            .into_iter()
280            .filter(|signer| signer_ids.contains(&signer.party_id))
281            .collect::<Vec<_>>();
282
283        let protocol_version = PROTOCOL_VERSION.to_string();
284        let initiated_at = open_message.created_at;
285        let sealed_at = Utc::now();
286        let metadata = CertificateMetadata::new(
287            self.network,
288            protocol_version,
289            epoch_service.current_protocol_parameters()?.clone(),
290            initiated_at,
291            sealed_at,
292            StakeDistributionParty::from_signers(signers),
293        );
294        let parent_certificate_hash = self
295            .certificate_repository
296            .get_master_certificate_for_epoch::<Certificate>(open_message.epoch)
297            .await
298            .with_context(|| {
299                format!(
300                    "Certifier can not get leader certificate for epoch: '{}'",
301                    open_message.epoch
302                )
303            })?
304            .map(|cert| cert.hash)
305            .ok_or_else(|| Box::new(CertifierServiceError::NoParentCertificateFound))?;
306
307        let certificate = Certificate::new(
308            parent_certificate_hash,
309            open_message.epoch,
310            metadata,
311            open_message.protocol_message.clone(),
312            epoch_service.current_aggregate_verification_key()?.clone(),
313            CertificateSignature::MultiSignature(signed_entity_type.clone(), multi_signature),
314        );
315
316        self.certificate_verifier
317            .verify_certificate(&certificate, &self.genesis_verifier.to_verification_key())
318            .await
319            .with_context(|| {
320                format!(
321                    "CertificateVerifier can not verify certificate with hash: '{}'",
322                    certificate.hash
323                )
324            })?;
325
326        let certificate = self
327            .certificate_repository
328            .create_certificate(certificate)
329            .await
330            .with_context(|| {format!(
331                "Certifier can not create certificate for signed entity type: '{signed_entity_type}'")
332            })?;
333
334        let mut open_message_certified: OpenMessageRecord = open_message_record.into();
335        open_message_certified.is_certified = true;
336        self.open_message_repository
337            .update_open_message(&open_message_certified)
338            .await
339            .with_context(|| format!("Certifier can not update open message for signed entity type: '{signed_entity_type}'"))
340            ?;
341
342        Ok(Some(certificate))
343    }
344
345    async fn get_certificate_by_hash(&self, hash: &str) -> StdResult<Option<Certificate>> {
346        self.certificate_repository.get_certificate(hash).await
347    }
348
349    async fn get_latest_certificates(&self, last_n: usize) -> StdResult<Vec<Certificate>> {
350        self.certificate_repository
351            .get_latest_certificates(last_n)
352            .await
353            .with_context(|| format!("Certifier can not get last '{last_n}' certificates"))
354    }
355
356    async fn verify_certificate_chain(&self, epoch: Epoch) -> StdResult<()> {
357        if let Some(certificate) = self
358            .certificate_repository
359            .get_latest_certificates::<Certificate>(1)
360            .await?
361            .first()
362        {
363            if epoch.has_gap_with(&certificate.epoch) {
364                return Err(CertifierServiceError::CertificateEpochGap {
365                    certificate_epoch: certificate.epoch,
366                    current_epoch: epoch,
367                }
368                .into());
369            }
370
371            self.certificate_verifier
372                .verify_certificate_chain(
373                    certificate.to_owned(),
374                    &self.genesis_verifier.to_verification_key(),
375                )
376                .await
377                .with_context(|| "CertificateVerifier can not verify certificate chain")?;
378
379            Ok(())
380        } else {
381            Err(CertifierServiceError::CouldNotFindLastCertificate.into())
382        }
383    }
384}
385
386#[cfg(test)]
387mod tests {
388    use std::path::PathBuf;
389
390    use crate::{
391        dependency_injection::DependenciesBuilder, multi_signer::MockMultiSigner,
392        services::FakeEpochService, test_tools::TestLogger, Configuration,
393    };
394    use chrono::{DateTime, Days};
395    use mithril_common::{
396        entities::{CardanoDbBeacon, ProtocolMessagePartKey},
397        temp_dir,
398        test_utils::{fake_data, MithrilFixture, MithrilFixtureBuilder},
399    };
400    use tokio::sync::RwLock;
401
402    use super::*;
403
404    impl MithrilCertifierService {
405        async fn from_deps(
406            network: CardanoNetwork,
407            mut dependency_builder: DependenciesBuilder,
408        ) -> Self {
409            let connection = dependency_builder.get_sqlite_connection().await.unwrap();
410            let open_message_repository = Arc::new(OpenMessageRepository::new(connection.clone()));
411            let single_signature_repository =
412                Arc::new(SingleSignatureRepository::new(connection.clone()));
413            let certificate_repository = Arc::new(CertificateRepository::new(connection));
414            let certificate_verifier = dependency_builder.get_certificate_verifier().await.unwrap();
415            let genesis_verifier = dependency_builder.get_genesis_verifier().await.unwrap();
416            let multi_signer = dependency_builder.get_multi_signer().await.unwrap();
417            let epoch_service = dependency_builder.get_epoch_service().await.unwrap();
418
419            Self::new(
420                network,
421                open_message_repository,
422                single_signature_repository,
423                certificate_repository,
424                certificate_verifier,
425                genesis_verifier,
426                multi_signer,
427                epoch_service,
428                TestLogger::stdout(),
429            )
430        }
431    }
432
433    /// Note: If current_epoch is provided the [EpochService] will be automatically initialized
434    async fn setup_certifier_service_with_network(
435        snapshot_directory: PathBuf,
436        network: CardanoNetwork,
437        fixture: &MithrilFixture,
438        epochs_with_signers: &[Epoch],
439        current_epoch: Option<Epoch>,
440    ) -> MithrilCertifierService {
441        let configuration = Configuration::new_sample(snapshot_directory);
442        let cardano_transactions_signing_config =
443            configuration.cardano_transactions_signing_config.clone();
444        let mut dependency_builder = DependenciesBuilder::new_with_stdout_logger(configuration);
445        if let Some(epoch) = current_epoch {
446            dependency_builder.epoch_service = Some(Arc::new(RwLock::new(
447                FakeEpochService::from_fixture(epoch, fixture),
448            )));
449        }
450
451        let dependency_manager = dependency_builder
452            .build_dependency_container()
453            .await
454            .unwrap();
455        dependency_manager
456            .init_state_from_fixture(
457                fixture,
458                &cardano_transactions_signing_config,
459                epochs_with_signers,
460            )
461            .await;
462
463        MithrilCertifierService::from_deps(network, dependency_builder).await
464    }
465
466    async fn setup_certifier_service(
467        snapshot_directory: PathBuf,
468        fixture: &MithrilFixture,
469        epochs_with_signers: &[Epoch],
470        current_epoch: Option<Epoch>,
471    ) -> MithrilCertifierService {
472        setup_certifier_service_with_network(
473            snapshot_directory,
474            fake_data::network(),
475            fixture,
476            epochs_with_signers,
477            current_epoch,
478        )
479        .await
480    }
481
482    #[tokio::test]
483    async fn should_clean_epoch_when_inform_epoch() {
484        let beacon = CardanoDbBeacon::new(1, 1);
485        let signed_entity_type = SignedEntityType::CardanoImmutableFilesFull(beacon.clone());
486        let protocol_message = ProtocolMessage::new();
487        let epoch = beacon.epoch;
488        let epochs_with_signers = (1..=5).map(Epoch).collect::<Vec<_>>();
489        let fixture = MithrilFixtureBuilder::default().with_signers(5).build();
490        let certifier_service =
491            setup_certifier_service(temp_dir!(), &fixture, &epochs_with_signers, None).await;
492        certifier_service
493            .create_open_message(&signed_entity_type, &protocol_message)
494            .await
495            .unwrap();
496        certifier_service.inform_epoch(epoch + 1).await.unwrap();
497        let open_message = certifier_service
498            .get_open_message(&signed_entity_type)
499            .await
500            .unwrap();
501        assert!(open_message.is_none());
502    }
503
504    #[tokio::test]
505    async fn should_mark_open_message_expired_when_exists() {
506        let beacon = CardanoDbBeacon::new(3, 1);
507        let signed_entity_type = SignedEntityType::CardanoImmutableFilesFull(beacon.clone());
508        let protocol_message = ProtocolMessage::new();
509        let epochs_with_signers = (1..=5).map(Epoch).collect::<Vec<_>>();
510        let fixture = MithrilFixtureBuilder::default().with_signers(1).build();
511        let certifier_service =
512            setup_certifier_service(temp_dir!(), &fixture, &epochs_with_signers, None).await;
513        let mut open_message = certifier_service
514            .open_message_repository
515            .create_open_message(beacon.epoch, &signed_entity_type, &protocol_message)
516            .await
517            .unwrap();
518        open_message.expires_at = Some(
519            DateTime::parse_from_rfc3339("2000-01-19T13:43:05.618857482Z")
520                .unwrap()
521                .with_timezone(&Utc),
522        );
523        certifier_service
524            .open_message_repository
525            .update_open_message(&open_message)
526            .await
527            .unwrap();
528
529        let open_message = certifier_service
530            .mark_open_message_if_expired(&signed_entity_type)
531            .await
532            .expect("mark_open_message_if_expired should not fail");
533        assert!(open_message.is_some());
534        assert!(open_message.unwrap().is_expired);
535    }
536
537    #[tokio::test]
538    async fn should_not_mark_open_message_expired_when_does_not_expire() {
539        let beacon = CardanoDbBeacon::new(3, 1);
540        let signed_entity_type = SignedEntityType::CardanoImmutableFilesFull(beacon.clone());
541        let protocol_message = ProtocolMessage::new();
542        let epochs_with_signers = (1..=5).map(Epoch).collect::<Vec<_>>();
543        let fixture = MithrilFixtureBuilder::default().with_signers(1).build();
544        let certifier_service =
545            setup_certifier_service(temp_dir!(), &fixture, &epochs_with_signers, None).await;
546        let mut open_message = certifier_service
547            .open_message_repository
548            .create_open_message(beacon.epoch, &signed_entity_type, &protocol_message)
549            .await
550            .unwrap();
551        open_message.expires_at = None;
552        certifier_service
553            .open_message_repository
554            .update_open_message(&open_message)
555            .await
556            .unwrap();
557
558        let open_message = certifier_service
559            .mark_open_message_if_expired(&signed_entity_type)
560            .await
561            .expect("mark_open_message_if_expired should not fail");
562        assert!(open_message.is_none());
563    }
564
565    #[tokio::test]
566    async fn should_not_mark_open_message_expired_when_has_not_expired_yet() {
567        let beacon = CardanoDbBeacon::new(3, 1);
568        let signed_entity_type = SignedEntityType::CardanoImmutableFilesFull(beacon.clone());
569        let protocol_message = ProtocolMessage::new();
570        let epochs_with_signers = (1..=5).map(Epoch).collect::<Vec<_>>();
571        let fixture = MithrilFixtureBuilder::default().with_signers(1).build();
572        let certifier_service =
573            setup_certifier_service(temp_dir!(), &fixture, &epochs_with_signers, None).await;
574        let mut open_message = certifier_service
575            .open_message_repository
576            .create_open_message(beacon.epoch, &signed_entity_type, &protocol_message)
577            .await
578            .unwrap();
579        open_message.expires_at = Some(Utc::now().checked_add_days(Days::new(1)).unwrap());
580        certifier_service
581            .open_message_repository
582            .update_open_message(&open_message)
583            .await
584            .unwrap();
585
586        let open_message = certifier_service
587            .mark_open_message_if_expired(&signed_entity_type)
588            .await
589            .expect("mark_open_message_if_expired should not fail");
590        assert!(open_message.is_none());
591    }
592
593    #[tokio::test]
594    async fn should_register_valid_single_signature() {
595        let beacon = CardanoDbBeacon::new(3, 1);
596        let signed_entity_type = SignedEntityType::CardanoImmutableFilesFull(beacon.clone());
597        let protocol_message = ProtocolMessage::new();
598        let epochs_with_signers = (1..=3).map(Epoch).collect::<Vec<_>>();
599        let fixture = MithrilFixtureBuilder::default().with_signers(1).build();
600        let certifier_service = setup_certifier_service(
601            temp_dir!(),
602            &fixture,
603            &epochs_with_signers,
604            Some(beacon.epoch),
605        )
606        .await;
607
608        certifier_service
609            .create_open_message(&signed_entity_type, &protocol_message)
610            .await
611            .unwrap();
612
613        let mut signatures = Vec::new();
614        for signer_fixture in fixture.signers_fixture() {
615            if let Some(signature) = signer_fixture.sign(&protocol_message) {
616                signatures.push(signature);
617            }
618        }
619        certifier_service
620            .register_single_signature(&signed_entity_type, &signatures[0])
621            .await
622            .unwrap();
623        let open_message = certifier_service
624            .get_open_message(&signed_entity_type)
625            .await
626            .unwrap()
627            .unwrap();
628        assert!(!open_message.single_signatures.is_empty());
629    }
630
631    #[tokio::test]
632    async fn should_not_register_invalid_single_signature() {
633        let beacon = CardanoDbBeacon::new(3, 1);
634        let signed_entity_type = SignedEntityType::CardanoImmutableFilesFull(beacon.clone());
635        let mut protocol_message = ProtocolMessage::new();
636        let epochs_with_signers = (1..=5).map(Epoch).collect::<Vec<_>>();
637        let fixture = MithrilFixtureBuilder::default().with_signers(1).build();
638        let certifier_service = setup_certifier_service(
639            temp_dir!(),
640            &fixture,
641            &epochs_with_signers,
642            Some(beacon.epoch),
643        )
644        .await;
645
646        certifier_service
647            .create_open_message(&signed_entity_type, &protocol_message)
648            .await
649            .unwrap();
650
651        protocol_message.set_message_part(
652            ProtocolMessagePartKey::SnapshotDigest,
653            "snapshot-digest-123".to_string(),
654        );
655
656        let mut signatures = Vec::new();
657        for signer_fixture in fixture.signers_fixture() {
658            if let Some(signature) = signer_fixture.sign(&protocol_message) {
659                signatures.push(signature);
660            }
661        }
662        let err = certifier_service
663            .register_single_signature(&signed_entity_type, &signatures[0])
664            .await
665            .expect_err("register_single_signature should fail");
666
667        assert!(
668            matches!(
669                err.downcast_ref::<CertifierServiceError>(),
670                Some(CertifierServiceError::InvalidSingleSignature(..))
671            ),
672            "Expected CertifierServiceError::InvalidSingleSignature, got: '{err:?}'"
673        );
674    }
675
676    #[tokio::test]
677    async fn should_not_register_single_signature_for_certified_open_message() {
678        let beacon = CardanoDbBeacon::new(3, 1);
679        let signed_entity_type = SignedEntityType::CardanoImmutableFilesFull(beacon.clone());
680        let protocol_message = ProtocolMessage::new();
681        let epochs_with_signers = (1..=5).map(Epoch).collect::<Vec<_>>();
682        let fixture = MithrilFixtureBuilder::default().with_signers(1).build();
683        let certifier_service =
684            setup_certifier_service(temp_dir!(), &fixture, &epochs_with_signers, None).await;
685        let mut open_message = certifier_service
686            .open_message_repository
687            .create_open_message(beacon.epoch, &signed_entity_type, &protocol_message)
688            .await
689            .unwrap();
690        open_message.is_certified = true;
691        certifier_service
692            .open_message_repository
693            .update_open_message(&open_message)
694            .await
695            .unwrap();
696
697        let mut signatures = Vec::new();
698        for signer_fixture in fixture.signers_fixture() {
699            if let Some(signature) = signer_fixture.sign(&protocol_message) {
700                signatures.push(signature);
701            }
702        }
703        certifier_service
704            .register_single_signature(&signed_entity_type, &signatures[0])
705            .await
706            .expect_err("register_single_signature should fail");
707    }
708
709    #[tokio::test]
710    async fn should_not_register_single_signature_for_expired_open_message() {
711        let beacon = CardanoDbBeacon::new(3, 1);
712        let signed_entity_type = SignedEntityType::CardanoImmutableFilesFull(beacon.clone());
713        let protocol_message = ProtocolMessage::new();
714        let epochs_with_signers = (1..=5).map(Epoch).collect::<Vec<_>>();
715        let fixture = MithrilFixtureBuilder::default().with_signers(1).build();
716        let certifier_service =
717            setup_certifier_service(temp_dir!(), &fixture, &epochs_with_signers, None).await;
718        let mut open_message = certifier_service
719            .open_message_repository
720            .create_open_message(beacon.epoch, &signed_entity_type, &protocol_message)
721            .await
722            .unwrap();
723        open_message.is_expired = true;
724        certifier_service
725            .open_message_repository
726            .update_open_message(&open_message)
727            .await
728            .unwrap();
729
730        let mut signatures = Vec::new();
731        for signer_fixture in fixture.signers_fixture() {
732            if let Some(signature) = signer_fixture.sign(&protocol_message) {
733                signatures.push(signature);
734            }
735        }
736        certifier_service
737            .register_single_signature(&signed_entity_type, &signatures[0])
738            .await
739            .expect_err("register_single_signature should fail");
740    }
741
742    #[tokio::test]
743    async fn should_create_certificate_when_multi_signature_produced() {
744        let network = fake_data::network();
745        let beacon = CardanoDbBeacon::new(3, 1);
746        let signed_entity_type = SignedEntityType::CardanoImmutableFilesFull(beacon.clone());
747        let mut protocol_message = ProtocolMessage::new();
748        protocol_message.set_message_part(ProtocolMessagePartKey::CurrentEpoch, "3".to_string());
749        let epochs_with_signers = (1..=3).map(Epoch).collect::<Vec<_>>();
750        let fixture = MithrilFixtureBuilder::default().with_signers(3).build();
751        let certifier_service = setup_certifier_service_with_network(
752            temp_dir!(),
753            network,
754            &fixture,
755            &epochs_with_signers,
756            Some(beacon.epoch),
757        )
758        .await;
759
760        certifier_service
761            .create_open_message(&signed_entity_type, &protocol_message)
762            .await
763            .unwrap();
764
765        let genesis_certificate = fixture.create_genesis_certificate(network, beacon.epoch - 1);
766        certifier_service
767            .certificate_repository
768            .create_certificate(genesis_certificate)
769            .await
770            .unwrap();
771
772        let mut signatures = Vec::new();
773        for signer_fixture in fixture.signers_fixture() {
774            if let Some(signature) = signer_fixture.sign(&protocol_message) {
775                signatures.push(signature);
776            }
777        }
778        for signature in signatures {
779            certifier_service
780                .register_single_signature(&signed_entity_type, &signature)
781                .await
782                .expect("register_single_signature should not fail");
783        }
784
785        let create_certificate_result = certifier_service
786            .create_certificate(&signed_entity_type)
787            .await
788            .unwrap();
789        assert!(create_certificate_result.is_some());
790
791        let certificate_created = create_certificate_result.unwrap();
792        certifier_service
793            .certificate_verifier
794            .verify_certificate(
795                &certificate_created,
796                &certifier_service.genesis_verifier.to_verification_key(),
797            )
798            .await
799            .unwrap();
800
801        let open_message = certifier_service
802            .get_open_message(&signed_entity_type)
803            .await
804            .unwrap()
805            .unwrap();
806        assert!(open_message.is_certified);
807
808        let certificate_retrieved = certifier_service
809            .get_certificate_by_hash(&certificate_created.hash)
810            .await
811            .unwrap()
812            .unwrap();
813        assert_eq!(certificate_created, certificate_retrieved);
814
815        let latest_certificates = certifier_service.get_latest_certificates(10).await.unwrap();
816        assert!(!latest_certificates.is_empty());
817    }
818
819    #[tokio::test]
820    async fn should_not_create_certificate_for_open_message_not_created() {
821        let beacon = CardanoDbBeacon::new(1, 1);
822        let signed_entity_type = SignedEntityType::CardanoImmutableFilesFull(beacon.clone());
823        let epochs_with_signers = (1..=5).map(Epoch).collect::<Vec<_>>();
824        let fixture = MithrilFixtureBuilder::default().with_signers(5).build();
825        let certifier_service =
826            setup_certifier_service(temp_dir!(), &fixture, &epochs_with_signers, None).await;
827        certifier_service
828            .create_certificate(&signed_entity_type)
829            .await
830            .expect_err("create_certificate should fail");
831    }
832
833    #[tokio::test]
834    async fn should_not_create_certificate_for_open_message_already_certified() {
835        let beacon = CardanoDbBeacon::new(1, 1);
836        let signed_entity_type = SignedEntityType::CardanoImmutableFilesFull(beacon.clone());
837        let protocol_message = ProtocolMessage::new();
838        let epoch = beacon.epoch;
839        let epochs_with_signers = (1..=5).map(Epoch).collect::<Vec<_>>();
840        let fixture = MithrilFixtureBuilder::default().with_signers(5).build();
841        let certifier_service =
842            setup_certifier_service(temp_dir!(), &fixture, &epochs_with_signers, None).await;
843        certifier_service
844            .open_message_repository
845            .create_open_message(epoch, &signed_entity_type, &protocol_message)
846            .await
847            .unwrap();
848        certifier_service
849            .create_certificate(&signed_entity_type)
850            .await
851            .expect_err("create_certificate should fail");
852    }
853
854    #[tokio::test]
855    async fn should_not_create_certificate_when_no_multi_signature_produced() {
856        let mut mock_multi_signer = MockMultiSigner::new();
857        mock_multi_signer
858            .expect_create_multi_signature()
859            .return_once(move |_| Ok(None));
860        let beacon = CardanoDbBeacon::new(1, 1);
861        let signed_entity_type = SignedEntityType::CardanoImmutableFilesFull(beacon.clone());
862        let protocol_message = ProtocolMessage::new();
863        let epochs_with_signers = (1..=5).map(Epoch).collect::<Vec<_>>();
864        let fixture = MithrilFixtureBuilder::default().with_signers(5).build();
865        let mut certifier_service =
866            setup_certifier_service(temp_dir!(), &fixture, &epochs_with_signers, None).await;
867        certifier_service.multi_signer = Arc::new(mock_multi_signer);
868        certifier_service
869            .create_open_message(&signed_entity_type, &protocol_message)
870            .await
871            .unwrap();
872        let create_certificate_result = certifier_service
873            .create_certificate(&signed_entity_type)
874            .await
875            .unwrap();
876        assert!(create_certificate_result.is_none());
877    }
878
879    #[tokio::test]
880    async fn test_epoch_gap_certificate_chain() {
881        let builder = MithrilFixtureBuilder::default();
882        let certifier_service =
883            setup_certifier_service(temp_dir!(), &builder.build(), &[], None).await;
884        let certificate = fake_data::genesis_certificate("whatever");
885        let epoch = certificate.epoch + 2;
886        certifier_service
887            .certificate_repository
888            .create_certificate(certificate)
889            .await
890            .unwrap();
891        let error = certifier_service
892            .verify_certificate_chain(epoch)
893            .await
894            .unwrap_err();
895
896        if let Some(err) = error.downcast_ref::<CertifierServiceError>() {
897            assert!(
898                matches!(err, CertifierServiceError::CertificateEpochGap {certificate_epoch: _, current_epoch} if *current_epoch == epoch)
899            );
900        } else {
901            panic!("Unexpected error {error:?}");
902        }
903    }
904
905    #[tokio::test]
906    async fn test_epoch_gap_certificate_chain_ok() {
907        let builder = MithrilFixtureBuilder::default();
908        let certifier_service =
909            setup_certifier_service(temp_dir!(), &builder.build(), &[], None).await;
910        let certificate = fake_data::genesis_certificate("whatever");
911        let epoch = certificate.epoch + 1;
912        certifier_service
913            .certificate_repository
914            .create_certificate(certificate)
915            .await
916            .unwrap();
917        let error = certifier_service
918            .verify_certificate_chain(epoch)
919            .await
920            .unwrap_err();
921
922        if let Some(err) = error.downcast_ref::<CertifierServiceError>() {
923            assert!(!matches!(
924                err,
925                CertifierServiceError::CertificateEpochGap {
926                    certificate_epoch: _,
927                    current_epoch: _
928                }
929            ));
930        }
931    }
932}