mithril_common/certificate_chain/
certificate_genesis.rs

1//! A module used to create a Genesis Certificate
2//!
3use std::sync::Arc;
4
5use chrono::prelude::*;
6use thiserror::Error;
7
8use crate::{
9    StdResult,
10    crypto_helper::{
11        PROTOCOL_VERSION, ProtocolAggregateVerificationKey, ProtocolGenesisSignature,
12        ProtocolGenesisSigner, ProtocolKey,
13    },
14    entities::{
15        Certificate, CertificateMetadata, CertificateSignature, Epoch, ProtocolMessage,
16        ProtocolMessagePartKey, ProtocolParameters,
17    },
18    protocol::ToMessage,
19};
20
21/// [CertificateGenesisProducer] related errors.
22#[derive(Error, Debug)]
23pub enum CertificateGenesisProducerError {
24    /// Error raised when there is no genesis signer available
25    #[error("missing genesis signer error")]
26    MissingGenesisSigner(),
27}
28
29/// CertificateGenesisProducer is in charge of producing a Genesis Certificate
30#[derive(Debug)]
31pub struct CertificateGenesisProducer {
32    genesis_signer: Option<Arc<ProtocolGenesisSigner>>,
33}
34
35impl CertificateGenesisProducer {
36    /// CertificateGenesisProducer factory
37    pub fn new(genesis_signer: Option<Arc<ProtocolGenesisSigner>>) -> Self {
38        Self { genesis_signer }
39    }
40
41    /// Create the Genesis protocol message
42    pub fn create_genesis_protocol_message(
43        genesis_protocol_parameters: &ProtocolParameters,
44        genesis_avk: &ProtocolAggregateVerificationKey,
45        genesis_epoch: &Epoch,
46    ) -> StdResult<ProtocolMessage> {
47        let genesis_aggregate_verification_key_for_concatenation =
48            ProtocolKey::new(genesis_avk.to_concatenation_aggregate_verification_key().to_owned());
49        let genesis_avk = genesis_aggregate_verification_key_for_concatenation.to_json_hex()?;
50        let mut protocol_message = ProtocolMessage::new();
51        protocol_message.set_message_part(
52            ProtocolMessagePartKey::NextAggregateVerificationKey,
53            genesis_avk,
54        );
55        protocol_message.set_message_part(
56            ProtocolMessagePartKey::NextProtocolParameters,
57            genesis_protocol_parameters.compute_hash(),
58        );
59        protocol_message.set_message_part(
60            ProtocolMessagePartKey::CurrentEpoch,
61            genesis_epoch.to_string(),
62        );
63        Ok(protocol_message)
64    }
65
66    /// Sign the Genesis protocol message (test only)
67    pub fn sign_genesis_protocol_message<T: ToMessage>(
68        &self,
69        genesis_message: T,
70    ) -> Result<ProtocolGenesisSignature, CertificateGenesisProducerError> {
71        Ok(self
72            .genesis_signer
73            .as_ref()
74            .ok_or_else(CertificateGenesisProducerError::MissingGenesisSigner)?
75            .sign(genesis_message.to_message().as_bytes()))
76    }
77
78    /// Create a Genesis Certificate
79    pub fn create_genesis_certificate<T: Into<String>>(
80        protocol_parameters: ProtocolParameters,
81        network: T,
82        epoch: Epoch,
83        genesis_avk: ProtocolAggregateVerificationKey,
84        genesis_signature: ProtocolGenesisSignature,
85    ) -> StdResult<Certificate> {
86        let protocol_version = PROTOCOL_VERSION.to_string();
87        let initiated_at = Utc::now();
88        let sealed_at = Utc::now();
89        let signers = vec![];
90        let metadata = CertificateMetadata::new(
91            network,
92            protocol_version,
93            protocol_parameters.clone(),
94            initiated_at,
95            sealed_at,
96            signers,
97        );
98        let previous_hash = "".to_string();
99        let genesis_protocol_message =
100            Self::create_genesis_protocol_message(&protocol_parameters, &genesis_avk, &epoch)?;
101        Ok(Certificate::new(
102            previous_hash,
103            epoch,
104            metadata,
105            genesis_protocol_message,
106            genesis_avk,
107            CertificateSignature::GenesisSignature(genesis_signature),
108        ))
109    }
110}
111
112#[cfg(test)]
113mod tests {
114    use super::*;
115
116    use crate::{entities::ProtocolMessagePartKey, test::builder::MithrilFixtureBuilder};
117
118    #[test]
119    fn test_create_genesis_protocol_message_has_expected_keys_and_values() {
120        let fixture = MithrilFixtureBuilder::default().with_signers(5).build();
121        let genesis_protocol_parameters = fixture.protocol_parameters();
122        let genesis_avk = fixture.compute_aggregate_verification_key();
123        let genesis_epoch = Epoch(123);
124        let protocol_message = CertificateGenesisProducer::create_genesis_protocol_message(
125            &genesis_protocol_parameters,
126            &genesis_avk,
127            &genesis_epoch,
128        )
129        .unwrap();
130
131        let expected_genesis_avk_value =
132            fixture.compute_and_encode_concatenation_aggregate_verification_key();
133        assert_eq!(
134            protocol_message
135                .get_message_part(&ProtocolMessagePartKey::NextAggregateVerificationKey),
136            Some(&expected_genesis_avk_value)
137        );
138
139        let expected_genesis_protocol_parameters_value = genesis_protocol_parameters.compute_hash();
140        assert_eq!(
141            protocol_message.get_message_part(&ProtocolMessagePartKey::NextProtocolParameters),
142            Some(&expected_genesis_protocol_parameters_value)
143        );
144
145        let expected_genesis_epoch = genesis_epoch.to_string();
146        assert_eq!(
147            protocol_message.get_message_part(&ProtocolMessagePartKey::CurrentEpoch),
148            Some(&expected_genesis_epoch)
149        );
150    }
151}