mithril_aggregator/database/record/
signer_registration.rs1use 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#[derive(Debug, PartialEq, Clone)]
12pub struct SignerRegistrationRecord {
13 pub signer_id: String,
15
16 pub epoch_settings_id: Epoch,
18
19 pub verification_key: HexEncodedVerificationKey,
21
22 pub verification_key_signature: Option<HexEncodedVerificationKeySignature>,
24
25 pub operational_certificate: Option<HexEncodedOpCert>,
27
28 pub kes_period: Option<KesPeriod>,
30
31 pub stake: Option<Stake>,
33
34 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}