mithril_aggregator/services/certifier/
certifier_service.rs

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