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
26pub 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 #[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 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}