mithril_aggregator/services/certifier/
interface.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
use async_trait::async_trait;
use thiserror::Error;

use mithril_common::entities::{
    Certificate, Epoch, ProtocolMessage, SignedEntityType, SignedEntityTypeDiscriminants,
    SingleSignatures,
};
use mithril_common::{StdError, StdResult};

use crate::entities::OpenMessage;

/// Errors dedicated to the CertifierService.
#[derive(Debug, Error)]
pub enum CertifierServiceError {
    /// OpenMessage not found.
    #[error("The open message was not found for beacon {0:?}.")]
    NotFound(SignedEntityType),

    /// The open message is already certified, no more single signatures may be
    /// attached to it nor be certified again.
    #[error("Open message for beacon {0:?} already certified.")]
    AlreadyCertified(SignedEntityType),

    /// The open message is expired, no more single signatures may be
    /// attached to it nor be certified again.
    #[error("Open message for beacon {0:?} is expired.")]
    Expired(SignedEntityType),

    /// An invalid signature was provided.
    #[error("Invalid single signature for {0:?}.")]
    InvalidSingleSignature(SignedEntityType, #[source] StdError),

    /// No parent certificate could be found, this certifier cannot create genesis certificates.
    #[error(
        "No parent certificate could be found, this certifier cannot create genesis certificates."
    )]
    NoParentCertificateFound,

    /// No certificate for this epoch
    #[error("There is an epoch gap between the last certificate epoch ({certificate_epoch:?}) and current epoch ({current_epoch:?})")]
    CertificateEpochGap {
        /// Epoch of the last issued certificate
        certificate_epoch: Epoch,

        /// Given current epoch
        current_epoch: Epoch,
    },

    /// Could not verify certificate chain because could not find last certificate.
    #[error("No certificate found.")]
    CouldNotFindLastCertificate,
}

/// Status of a successful registration of a single signature.
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum SignatureRegistrationStatus {
    /// The signature was registered and will be used for the next certificate.
    Registered,

    /// The signature was buffered, it will be used later.
    Buffered,
}

/// ## CertifierService
///
/// This service manages the open message and their beacon transitions. It can
/// ultimately transform open messages into certificates.
#[cfg_attr(test, mockall::automock)]
#[async_trait]
pub trait CertifierService: Sync + Send {
    /// Inform the certifier I have detected a new epoch, it may clear its state
    /// and prepare the new signature round. If the given Epoch is equal or less
    /// than the previous informed Epoch, nothing is done.
    async fn inform_epoch(&self, epoch: Epoch) -> StdResult<()>;

    /// Add a new single signature for the open message at the given beacon. If
    /// the open message does not exist or the open message has been certified
    /// since then, an error is returned.
    async fn register_single_signature(
        &self,
        signed_entity_type: &SignedEntityType,
        signature: &SingleSignatures,
    ) -> StdResult<SignatureRegistrationStatus>;

    /// Create an open message at the given beacon. If the open message does not
    /// exist or exists at an older beacon, the older open messages are cleared
    /// along with their associated single signatures and the new open message
    /// is created. If the message already exists, an error is returned.
    async fn create_open_message(
        &self,
        signed_entity_type: &SignedEntityType,
        protocol_message: &ProtocolMessage,
    ) -> StdResult<OpenMessage>;

    /// Return the open message at the given Beacon. If the message does not
    /// exist, None is returned.
    async fn get_open_message(
        &self,
        signed_entity_type: &SignedEntityType,
    ) -> StdResult<Option<OpenMessage>>;

    /// Mark the open message if it has expired.
    async fn mark_open_message_if_expired(
        &self,
        signed_entity_type: &SignedEntityType,
    ) -> StdResult<Option<OpenMessage>>;

    /// Create a certificate if possible. If the pointed open message does
    /// not exist or has been already certified, an error is raised. If a multi
    /// signature is created then the flag `is_certified` of the open
    /// message is set to true. The Certificate is created.
    /// If the stake quorum of the single signatures is
    /// not reached for the multisignature to be created, the certificate is not
    /// created and None is returned. If the certificate can be created, the
    /// list of the registered signers for the given epoch is used.
    async fn create_certificate(
        &self,
        signed_entity_type: &SignedEntityType,
    ) -> StdResult<Option<Certificate>>;

    /// Returns a certificate from its hash.
    async fn get_certificate_by_hash(&self, hash: &str) -> StdResult<Option<Certificate>>;

    /// Returns the list of the latest created certificates.
    async fn get_latest_certificates(&self, last_n: usize) -> StdResult<Vec<Certificate>>;

    /// Verify the certificate chain and epoch gap. This will return an error if
    /// there is at least an epoch between the given epoch and the most recent
    /// certificate.
    async fn verify_certificate_chain(&self, epoch: Epoch) -> StdResult<()>;
}

/// ## BufferedSingleSignatureStore
///
/// Allow to buffer single signatures for later use when an open message isn't available yet.
#[cfg_attr(test, mockall::automock)]
#[async_trait]
pub trait BufferedSingleSignatureStore: Sync + Send {
    /// Buffer a single signature for later use.
    async fn buffer_signature(
        &self,
        signed_entity_type_discriminant: SignedEntityTypeDiscriminants,
        signature: &SingleSignatures,
    ) -> StdResult<()>;

    /// Get the buffered single signatures for the given signed entity discriminant.
    async fn get_buffered_signatures(
        &self,
        signed_entity_type_discriminant: SignedEntityTypeDiscriminants,
    ) -> StdResult<Vec<SingleSignatures>>;

    /// Remove the given single signatures from the buffer.
    async fn remove_buffered_signatures(
        &self,
        signed_entity_type_discriminant: SignedEntityTypeDiscriminants,
        single_signatures: Vec<SingleSignatures>,
    ) -> StdResult<()>;
}