mithril_aggregator/database/record/
signer_registration.rs

1use chrono::{DateTime, Utc};
2
3use mithril_common::crypto_helper::KesPeriod;
4use mithril_common::entities::{
5    Epoch, HexEncodedOpCert, HexEncodedVerificationKey, HexEncodedVerificationKeySignature, Signer,
6    SignerWithStake, Stake,
7};
8use mithril_persistence::sqlite::{HydrationError, Projection, SqLiteEntity};
9
10/// SignerRegistration record is the representation of a stored signer_registration.
11#[derive(Debug, PartialEq, Clone)]
12pub struct SignerRegistrationRecord {
13    /// Signer id.
14    pub signer_id: String,
15
16    /// Epoch of creation of the signer_registration.
17    pub epoch_settings_id: Epoch,
18
19    /// Verification key of the signer
20    pub verification_key: HexEncodedVerificationKey,
21
22    /// Signature of the verification key of the signer
23    pub verification_key_signature: Option<HexEncodedVerificationKeySignature>,
24
25    /// Operational certificate of the stake pool operator associated to the signer
26    pub operational_certificate: Option<HexEncodedOpCert>,
27
28    /// The kes period used to compute the verification key signature
29    pub kes_period: Option<KesPeriod>,
30
31    /// The stake associated to the signer
32    pub stake: Option<Stake>,
33
34    /// Date and time when the signer_registration was created
35    pub created_at: DateTime<Utc>,
36}
37
38impl SignerRegistrationRecord {
39    pub(crate) fn from_signer_with_stake(other: SignerWithStake, epoch: Epoch) -> Self {
40        SignerRegistrationRecord {
41            signer_id: other.party_id,
42            epoch_settings_id: epoch,
43            verification_key: other.verification_key.to_json_hex().unwrap(),
44            verification_key_signature: other
45                .verification_key_signature
46                .map(|k| k.to_json_hex().unwrap()),
47            operational_certificate: other
48                .operational_certificate
49                .map(|o| o.to_json_hex().unwrap()),
50            kes_period: other.kes_period,
51            stake: Some(other.stake),
52            created_at: Utc::now(),
53        }
54    }
55}
56
57impl From<SignerRegistrationRecord> for Signer {
58    fn from(other: SignerRegistrationRecord) -> Self {
59        Self {
60            party_id: other.signer_id,
61            verification_key: other.verification_key.try_into().unwrap(),
62            verification_key_signature: other
63                .verification_key_signature
64                .map(|k| (k.try_into().unwrap())),
65            operational_certificate: other.operational_certificate.map(|o| (o.try_into().unwrap())),
66            kes_period: other.kes_period,
67        }
68    }
69}
70
71impl From<SignerRegistrationRecord> for SignerWithStake {
72    fn from(other: SignerRegistrationRecord) -> Self {
73        Self {
74            party_id: other.signer_id,
75            verification_key: other.verification_key.try_into().unwrap(),
76            verification_key_signature: other
77                .verification_key_signature
78                .map(|k| (k.try_into().unwrap())),
79            operational_certificate: other.operational_certificate.map(|o| (o.try_into().unwrap())),
80            kes_period: other.kes_period,
81            stake: other.stake.unwrap_or_default(),
82        }
83    }
84}
85
86impl SqLiteEntity for SignerRegistrationRecord {
87    fn hydrate(row: sqlite::Row) -> Result<Self, HydrationError>
88    where
89        Self: Sized,
90    {
91        let signer_id = row.read::<&str, _>(0).to_string();
92        let epoch_settings_id_int = row.read::<i64, _>(1);
93        let verification_key = row.read::<&str, _>(2).to_string();
94        let verification_key_signature = row.read::<Option<&str>, _>(3).map(|s| s.to_owned());
95        let operational_certificate = row.read::<Option<&str>, _>(4).map(|s| s.to_owned());
96        let kes_period_int = row.read::<Option<i64>, _>(5);
97        let stake_int = row.read::<Option<i64>, _>(6);
98        let created_at = row.read::<&str, _>(7);
99
100        let signer_registration_record = Self {
101            signer_id,
102            epoch_settings_id: Epoch(epoch_settings_id_int.try_into().map_err(|e| {
103                HydrationError::InvalidData(format!(
104                    "Could not cast i64 ({epoch_settings_id_int}) to u64. Error: '{e}'"
105                ))
106            })?),
107            verification_key,
108            verification_key_signature,
109            operational_certificate,
110            kes_period: match kes_period_int {
111                Some(kes_period_int) => Some(kes_period_int.try_into().map_err(|e| {
112                    HydrationError::InvalidData(format!(
113                        "Could not cast i64 ({kes_period_int}) to u64. Error: '{e}'"
114                    ))
115                })?),
116                None => None,
117            },
118            stake: match stake_int {
119                Some(stake_int) => Some(stake_int.try_into().map_err(|e| {
120                    HydrationError::InvalidData(format!(
121                        "Could not cast i64 ({stake_int}) to u64. Error: '{e}'"
122                    ))
123                })?),
124                None => None,
125            },
126            created_at: DateTime::parse_from_rfc3339(created_at)
127                .map_err(|e| {
128                    HydrationError::InvalidData(format!(
129                        "Could not turn string '{created_at}' to rfc3339 Datetime. Error: {e}"
130                    ))
131                })?
132                .with_timezone(&Utc),
133        };
134
135        Ok(signer_registration_record)
136    }
137
138    fn get_projection() -> Projection {
139        let mut projection = Projection::default();
140        projection.add_field("signer_id", "{:signer_registration:}.signer_id", "text");
141        projection.add_field(
142            "epoch_setting_id",
143            "{:signer_registration:}.epoch_setting_id",
144            "integer",
145        );
146        projection.add_field(
147            "verification_key",
148            "{:signer_registration:}.verification_key",
149            "text",
150        );
151        projection.add_field(
152            "verification_key_signature",
153            "{:signer_registration:}.verification_key_signature",
154            "text",
155        );
156        projection.add_field(
157            "operational_certificate",
158            "{:signer_registration:}.operational_certificate",
159            "text",
160        );
161        projection.add_field(
162            "kes_period",
163            "{:signer_registration:}.kes_period",
164            "integer",
165        );
166        projection.add_field("stake", "{:signer_registration:}.stake", "integer");
167        projection.add_field("created_at", "{:signer_registration:}.created_at", "text");
168
169        projection
170    }
171}
172
173#[cfg(test)]
174mod tests {
175    use mithril_common::test_utils::MithrilFixtureBuilder;
176
177    use super::*;
178
179    #[test]
180    fn test_convert_signer_registrations() {
181        let fixture = MithrilFixtureBuilder::default().with_signers(5).build();
182        let signer_with_stakes = fixture.signers_with_stake();
183
184        let mut signer_registration_records: Vec<SignerRegistrationRecord> = Vec::new();
185        for signer_with_stake in signer_with_stakes.clone() {
186            signer_registration_records.push(SignerRegistrationRecord::from_signer_with_stake(
187                signer_with_stake,
188                Epoch(1),
189            ));
190        }
191        let mut signer_with_stakes_new: Vec<SignerWithStake> = Vec::new();
192        for signer_registration_record in signer_registration_records {
193            signer_with_stakes_new.push(signer_registration_record.into());
194        }
195        assert_eq!(signer_with_stakes, signer_with_stakes_new);
196    }
197}