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 chrono::{DateTime, Days};
413 use std::path::PathBuf;
414 use tokio::sync::RwLock;
415
416 use mithril_cardano_node_chain::test::double::FakeChainObserver;
417 use mithril_common::{
418 entities::{CardanoDbBeacon, ProtocolMessagePartKey, TimePoint},
419 temp_dir,
420 test::{
421 builder::{MithrilFixture, MithrilFixtureBuilder},
422 double::{Dummy, fake_data},
423 },
424 };
425
426 use crate::{
427 ServeCommandConfiguration, dependency_injection::DependenciesBuilder,
428 multi_signer::MockMultiSigner, services::FakeEpochService, test::TestLogger,
429 };
430
431 use super::*;
432
433 impl MithrilCertifierService {
434 async fn from_deps(
435 network: CardanoNetwork,
436 mut dependency_builder: DependenciesBuilder,
437 ) -> Self {
438 let connection = dependency_builder.get_sqlite_connection().await.unwrap();
439 let open_message_repository = Arc::new(OpenMessageRepository::new(connection.clone()));
440 let single_signature_repository =
441 Arc::new(SingleSignatureRepository::new(connection.clone()));
442 let certificate_repository = Arc::new(CertificateRepository::new(connection));
443 let certificate_verifier = dependency_builder.get_certificate_verifier().await.unwrap();
444 let genesis_verifier = dependency_builder.get_genesis_verifier().await.unwrap();
445 let multi_signer = dependency_builder.get_multi_signer().await.unwrap();
446 let epoch_service = dependency_builder.get_epoch_service().await.unwrap();
447
448 Self::new(
449 network,
450 open_message_repository,
451 single_signature_repository,
452 certificate_repository,
453 certificate_verifier,
454 genesis_verifier,
455 multi_signer,
456 epoch_service,
457 TestLogger::stdout(),
458 )
459 }
460 }
461
462 async fn setup_certifier_service(
464 snapshot_directory: PathBuf,
465 fixture: &MithrilFixture,
466 current_epoch: Epoch,
467 ) -> MithrilCertifierService {
468 let configuration = ServeCommandConfiguration::new_sample(snapshot_directory);
469 let mut dependency_builder =
470 DependenciesBuilder::new_with_stdout_logger(Arc::new(configuration));
471 dependency_builder.epoch_service = Some(Arc::new(RwLock::new(
472 FakeEpochService::from_fixture(current_epoch, fixture),
473 )));
474 dependency_builder.chain_observer =
475 Some(Arc::new(FakeChainObserver::new(Some(TimePoint {
476 epoch: current_epoch,
477 ..Dummy::dummy()
478 }))));
479
480 let dependency_manager =
481 dependency_builder.build_serve_dependencies_container().await.unwrap();
482 dependency_manager
483 .init_state_from_fixture(fixture, current_epoch)
484 .await;
485
486 MithrilCertifierService::from_deps(fake_data::network(), dependency_builder).await
487 }
488
489 #[tokio::test]
490 async fn should_clean_epoch_when_inform_epoch() {
491 let beacon = CardanoDbBeacon::new(1, 1);
492 let signed_entity_type = SignedEntityType::CardanoImmutableFilesFull(beacon.clone());
493 let protocol_message = ProtocolMessage::new();
494 let epoch = beacon.epoch;
495 let fixture = MithrilFixtureBuilder::default().with_signers(5).build();
496 let certifier_service = setup_certifier_service(temp_dir!(), &fixture, beacon.epoch).await;
497 certifier_service
498 .create_open_message(&signed_entity_type, &protocol_message)
499 .await
500 .unwrap();
501 certifier_service.inform_epoch(epoch + 1).await.unwrap();
502 let open_message = certifier_service.get_open_message(&signed_entity_type).await.unwrap();
503 assert!(open_message.is_none());
504 }
505
506 #[tokio::test]
507 async fn should_mark_open_message_expired_when_exists() {
508 let beacon = CardanoDbBeacon::new(3, 1);
509 let signed_entity_type = SignedEntityType::CardanoImmutableFilesFull(beacon.clone());
510 let protocol_message = ProtocolMessage::new();
511 let fixture = MithrilFixtureBuilder::default().with_signers(1).build();
512 let certifier_service = setup_certifier_service(temp_dir!(), &fixture, beacon.epoch).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 fixture = MithrilFixtureBuilder::default().with_signers(1).build();
543 let certifier_service = setup_certifier_service(temp_dir!(), &fixture, beacon.epoch).await;
544 let mut open_message = certifier_service
545 .open_message_repository
546 .create_open_message(beacon.epoch, &signed_entity_type, &protocol_message)
547 .await
548 .unwrap();
549 open_message.expires_at = None;
550 certifier_service
551 .open_message_repository
552 .update_open_message(&open_message)
553 .await
554 .unwrap();
555
556 let open_message = certifier_service
557 .mark_open_message_if_expired(&signed_entity_type)
558 .await
559 .expect("mark_open_message_if_expired should not fail");
560 assert!(open_message.is_none());
561 }
562
563 #[tokio::test]
564 async fn should_not_mark_open_message_expired_when_has_not_expired_yet() {
565 let beacon = CardanoDbBeacon::new(3, 1);
566 let signed_entity_type = SignedEntityType::CardanoImmutableFilesFull(beacon.clone());
567 let protocol_message = ProtocolMessage::new();
568 let fixture = MithrilFixtureBuilder::default().with_signers(1).build();
569 let certifier_service = setup_certifier_service(temp_dir!(), &fixture, beacon.epoch).await;
570 let mut open_message = certifier_service
571 .open_message_repository
572 .create_open_message(beacon.epoch, &signed_entity_type, &protocol_message)
573 .await
574 .unwrap();
575 open_message.expires_at = Some(Utc::now().checked_add_days(Days::new(1)).unwrap());
576 certifier_service
577 .open_message_repository
578 .update_open_message(&open_message)
579 .await
580 .unwrap();
581
582 let open_message = certifier_service
583 .mark_open_message_if_expired(&signed_entity_type)
584 .await
585 .expect("mark_open_message_if_expired should not fail");
586 assert!(open_message.is_none());
587 }
588
589 #[tokio::test]
590 async fn should_register_valid_single_signature() {
591 let beacon = CardanoDbBeacon::new(3, 1);
592 let signed_entity_type = SignedEntityType::CardanoImmutableFilesFull(beacon.clone());
593 let protocol_message = ProtocolMessage::new();
594 let fixture = MithrilFixtureBuilder::default().with_signers(1).build();
595 let certifier_service = setup_certifier_service(temp_dir!(), &fixture, beacon.epoch).await;
596
597 certifier_service
598 .create_open_message(&signed_entity_type, &protocol_message)
599 .await
600 .unwrap();
601
602 let mut signatures = Vec::new();
603 for signer_fixture in fixture.signers_fixture() {
604 if let Some(signature) = signer_fixture.sign(&protocol_message) {
605 signatures.push(signature);
606 }
607 }
608 certifier_service
609 .register_single_signature(&signed_entity_type, &signatures[0])
610 .await
611 .unwrap();
612 let open_message = certifier_service
613 .get_open_message(&signed_entity_type)
614 .await
615 .unwrap()
616 .unwrap();
617 assert!(!open_message.single_signatures.is_empty());
618 }
619
620 #[tokio::test]
621 async fn should_not_register_invalid_single_signature() {
622 let beacon = CardanoDbBeacon::new(3, 1);
623 let signed_entity_type = SignedEntityType::CardanoImmutableFilesFull(beacon.clone());
624 let mut protocol_message = ProtocolMessage::new();
625 let fixture = MithrilFixtureBuilder::default().with_signers(1).build();
626 let certifier_service = setup_certifier_service(temp_dir!(), &fixture, beacon.epoch).await;
627
628 certifier_service
629 .create_open_message(&signed_entity_type, &protocol_message)
630 .await
631 .unwrap();
632
633 protocol_message.set_message_part(
634 ProtocolMessagePartKey::SnapshotDigest,
635 "snapshot-digest-123".to_string(),
636 );
637
638 let mut signatures = Vec::new();
639 for signer_fixture in fixture.signers_fixture() {
640 if let Some(signature) = signer_fixture.sign(&protocol_message) {
641 signatures.push(signature);
642 }
643 }
644 let err = certifier_service
645 .register_single_signature(&signed_entity_type, &signatures[0])
646 .await
647 .expect_err("register_single_signature should fail");
648
649 assert!(
650 matches!(
651 err.downcast_ref::<CertifierServiceError>(),
652 Some(CertifierServiceError::InvalidSingleSignature(..))
653 ),
654 "Expected CertifierServiceError::InvalidSingleSignature, got: '{err:?}'"
655 );
656 }
657
658 #[tokio::test]
659 async fn should_not_register_single_signature_for_certified_open_message() {
660 let beacon = CardanoDbBeacon::new(3, 1);
661 let signed_entity_type = SignedEntityType::CardanoImmutableFilesFull(beacon.clone());
662 let protocol_message = ProtocolMessage::new();
663 let fixture = MithrilFixtureBuilder::default().with_signers(1).build();
664 let certifier_service = setup_certifier_service(temp_dir!(), &fixture, beacon.epoch).await;
665 let mut open_message = certifier_service
666 .open_message_repository
667 .create_open_message(beacon.epoch, &signed_entity_type, &protocol_message)
668 .await
669 .unwrap();
670 open_message.is_certified = true;
671 certifier_service
672 .open_message_repository
673 .update_open_message(&open_message)
674 .await
675 .unwrap();
676
677 let mut signatures = Vec::new();
678 for signer_fixture in fixture.signers_fixture() {
679 if let Some(signature) = signer_fixture.sign(&protocol_message) {
680 signatures.push(signature);
681 }
682 }
683 certifier_service
684 .register_single_signature(&signed_entity_type, &signatures[0])
685 .await
686 .expect_err("register_single_signature should fail");
687 }
688
689 #[tokio::test]
690 async fn should_not_register_single_signature_for_expired_open_message() {
691 let beacon = CardanoDbBeacon::new(3, 1);
692 let signed_entity_type = SignedEntityType::CardanoImmutableFilesFull(beacon.clone());
693 let protocol_message = ProtocolMessage::new();
694 let fixture = MithrilFixtureBuilder::default().with_signers(1).build();
695 let certifier_service = setup_certifier_service(temp_dir!(), &fixture, beacon.epoch).await;
696 let mut open_message = certifier_service
697 .open_message_repository
698 .create_open_message(beacon.epoch, &signed_entity_type, &protocol_message)
699 .await
700 .unwrap();
701 open_message.is_expired = true;
702 certifier_service
703 .open_message_repository
704 .update_open_message(&open_message)
705 .await
706 .unwrap();
707
708 let mut signatures = Vec::new();
709 for signer_fixture in fixture.signers_fixture() {
710 if let Some(signature) = signer_fixture.sign(&protocol_message) {
711 signatures.push(signature);
712 }
713 }
714 certifier_service
715 .register_single_signature(&signed_entity_type, &signatures[0])
716 .await
717 .expect_err("register_single_signature should fail");
718 }
719
720 #[tokio::test]
721 async fn should_create_certificate_when_multi_signature_produced() {
722 let beacon = CardanoDbBeacon::new(3, 1);
723 let signed_entity_type = SignedEntityType::CardanoImmutableFilesFull(beacon.clone());
724 let mut protocol_message = ProtocolMessage::new();
725 protocol_message.set_message_part(ProtocolMessagePartKey::CurrentEpoch, "3".to_string());
726 let fixture = MithrilFixtureBuilder::default().with_signers(3).build();
727 let certifier_service = setup_certifier_service(temp_dir!(), &fixture, beacon.epoch).await;
728
729 certifier_service
730 .create_open_message(&signed_entity_type, &protocol_message)
731 .await
732 .unwrap();
733
734 let genesis_certificate =
735 fixture.create_genesis_certificate(certifier_service.network, beacon.epoch - 1);
736 certifier_service
737 .certificate_repository
738 .create_certificate(genesis_certificate)
739 .await
740 .unwrap();
741
742 let mut signatures = Vec::new();
743 for signer_fixture in fixture.signers_fixture() {
744 if let Some(signature) = signer_fixture.sign(&protocol_message) {
745 signatures.push(signature);
746 }
747 }
748 for signature in signatures {
749 certifier_service
750 .register_single_signature(&signed_entity_type, &signature)
751 .await
752 .expect("register_single_signature should not fail");
753 }
754
755 let create_certificate_result = certifier_service
756 .create_certificate(&signed_entity_type)
757 .await
758 .unwrap();
759 assert!(create_certificate_result.is_some());
760
761 let certificate_created = create_certificate_result.unwrap();
762 certifier_service
763 .certificate_verifier
764 .verify_certificate(
765 &certificate_created,
766 &certifier_service.genesis_verifier.to_verification_key(),
767 )
768 .await
769 .unwrap();
770
771 let open_message = certifier_service
772 .get_open_message(&signed_entity_type)
773 .await
774 .unwrap()
775 .unwrap();
776 assert!(open_message.is_certified);
777
778 let certificate_retrieved = certifier_service
779 .get_certificate_by_hash(&certificate_created.hash)
780 .await
781 .unwrap()
782 .unwrap();
783 assert_eq!(certificate_created, certificate_retrieved);
784
785 let latest_certificates = certifier_service.get_latest_certificates(10).await.unwrap();
786 assert!(!latest_certificates.is_empty());
787 }
788
789 #[tokio::test]
790 async fn should_not_create_certificate_for_open_message_not_created() {
791 let beacon = CardanoDbBeacon::new(1, 1);
792 let signed_entity_type = SignedEntityType::CardanoImmutableFilesFull(beacon.clone());
793 let fixture = MithrilFixtureBuilder::default().with_signers(5).build();
794 let certifier_service = setup_certifier_service(temp_dir!(), &fixture, beacon.epoch).await;
795 certifier_service
796 .create_certificate(&signed_entity_type)
797 .await
798 .expect_err("create_certificate should fail");
799 }
800
801 #[tokio::test]
802 async fn should_not_create_certificate_for_open_message_already_certified() {
803 let beacon = CardanoDbBeacon::new(1, 1);
804 let signed_entity_type = SignedEntityType::CardanoImmutableFilesFull(beacon.clone());
805 let protocol_message = ProtocolMessage::new();
806 let epoch = beacon.epoch;
807 let fixture = MithrilFixtureBuilder::default().with_signers(5).build();
808 let certifier_service = setup_certifier_service(temp_dir!(), &fixture, beacon.epoch).await;
809 let mut record = certifier_service
810 .open_message_repository
811 .create_open_message(epoch, &signed_entity_type, &protocol_message)
812 .await
813 .unwrap();
814 record.is_certified = true;
815 certifier_service
816 .open_message_repository
817 .update_open_message(&record)
818 .await
819 .unwrap();
820
821 let error = certifier_service
822 .create_certificate(&signed_entity_type)
823 .await
824 .expect_err("create_certificate should fail");
825
826 if let Some(err) = error.downcast_ref::<CertifierServiceError>() {
827 assert!(matches!(
828 err,
829 CertifierServiceError::AlreadyCertified(signed_entity) if signed_entity == &signed_entity_type
830 ),);
831 } else {
832 panic!("Unexpected error {error:?}");
833 }
834 }
835
836 #[tokio::test]
837 async fn should_not_create_certificate_when_no_multi_signature_produced() {
838 let mut mock_multi_signer = MockMultiSigner::new();
839 mock_multi_signer
840 .expect_create_multi_signature()
841 .return_once(move |_| Ok(None));
842 let beacon = CardanoDbBeacon::new(1, 1);
843 let signed_entity_type = SignedEntityType::CardanoImmutableFilesFull(beacon.clone());
844 let protocol_message = ProtocolMessage::new();
845 let fixture = MithrilFixtureBuilder::default().with_signers(5).build();
846 let mut certifier_service =
847 setup_certifier_service(temp_dir!(), &fixture, beacon.epoch).await;
848 certifier_service.multi_signer = Arc::new(mock_multi_signer);
849 certifier_service
850 .create_open_message(&signed_entity_type, &protocol_message)
851 .await
852 .unwrap();
853 let create_certificate_result = certifier_service
854 .create_certificate(&signed_entity_type)
855 .await
856 .unwrap();
857 assert!(create_certificate_result.is_none());
858 }
859
860 #[tokio::test]
861 async fn test_epoch_gap_certificate_chain() {
862 let builder = MithrilFixtureBuilder::default();
863 let certificate = fake_data::genesis_certificate("whatever");
864 let epoch = certificate.epoch + 2;
865 let certifier_service = setup_certifier_service(temp_dir!(), &builder.build(), epoch).await;
866 certifier_service
867 .certificate_repository
868 .create_certificate(certificate)
869 .await
870 .unwrap();
871 let error = certifier_service.verify_certificate_chain(epoch).await.unwrap_err();
872
873 if let Some(err) = error.downcast_ref::<CertifierServiceError>() {
874 assert!(
875 matches!(err, CertifierServiceError::CertificateEpochGap {certificate_epoch: _, current_epoch} if *current_epoch == epoch)
876 );
877 } else {
878 panic!("Unexpected error {error:?}");
879 }
880 }
881
882 #[tokio::test]
883 async fn test_epoch_gap_certificate_chain_ok() {
884 let builder = MithrilFixtureBuilder::default();
885 let certificate = fake_data::genesis_certificate("whatever");
886 let epoch = certificate.epoch + 1;
887 let certifier_service = setup_certifier_service(temp_dir!(), &builder.build(), epoch).await;
888 certifier_service
889 .certificate_repository
890 .create_certificate(certificate)
891 .await
892 .unwrap();
893 let error = certifier_service.verify_certificate_chain(epoch).await.unwrap_err();
894
895 if let Some(err) = error.downcast_ref::<CertifierServiceError>() {
896 assert!(!matches!(
897 err,
898 CertifierServiceError::CertificateEpochGap {
899 certificate_epoch: _,
900 current_epoch: _
901 }
902 ));
903 }
904 }
905}