mithril_common/signable_builder/
signable_builder_service.rs1use anyhow::Context;
2use async_trait::async_trait;
3use slog::{Logger, debug};
4use std::sync::Arc;
5
6use crate::{
7 StdResult,
8 entities::{
9 BlockNumber, CardanoDbBeacon, Epoch, ProtocolMessage, ProtocolMessagePartKey,
10 SignedEntityType,
11 },
12 logging::LoggerExtensions,
13 signable_builder::{SignableBuilder, SignableSeedBuilder},
14};
15
16#[cfg_attr(test, mockall::automock)]
18#[async_trait]
19pub trait SignableBuilderService: Send + Sync {
20 async fn compute_protocol_message(
22 &self,
23 signed_entity_type: SignedEntityType,
24 ) -> StdResult<ProtocolMessage>;
25}
26
27pub struct MithrilSignableBuilderService {
29 seed_signable_builder: Arc<dyn SignableSeedBuilder>,
30 mithril_stake_distribution_builder: Arc<dyn SignableBuilder<Epoch>>,
31 immutable_signable_builder: Arc<dyn SignableBuilder<CardanoDbBeacon>>,
32 cardano_transactions_signable_builder: Arc<dyn SignableBuilder<BlockNumber>>,
33 cardano_blocks_transactions_signable_builder: Arc<dyn SignableBuilder<BlockNumber>>,
34 cardano_stake_distribution_builder: Arc<dyn SignableBuilder<Epoch>>,
35 cardano_database_signable_builder: Arc<dyn SignableBuilder<CardanoDbBeacon>>,
36 logger: Logger,
37}
38
39pub struct SignableBuilderServiceDependencies {
41 mithril_stake_distribution_builder: Arc<dyn SignableBuilder<Epoch>>,
42 immutable_signable_builder: Arc<dyn SignableBuilder<CardanoDbBeacon>>,
43 cardano_transactions_signable_builder: Arc<dyn SignableBuilder<BlockNumber>>,
44 cardano_blocks_transactions_signable_builder: Arc<dyn SignableBuilder<BlockNumber>>,
45 cardano_stake_distribution_builder: Arc<dyn SignableBuilder<Epoch>>,
46 cardano_database_signable_builder: Arc<dyn SignableBuilder<CardanoDbBeacon>>,
47}
48
49impl SignableBuilderServiceDependencies {
50 pub fn new(
52 mithril_stake_distribution_builder: Arc<dyn SignableBuilder<Epoch>>,
53 immutable_signable_builder: Arc<dyn SignableBuilder<CardanoDbBeacon>>,
54 cardano_transactions_signable_builder: Arc<dyn SignableBuilder<BlockNumber>>,
55 cardano_blocks_transactions_signable_builder: Arc<dyn SignableBuilder<BlockNumber>>,
56 cardano_stake_distribution_builder: Arc<dyn SignableBuilder<Epoch>>,
57 cardano_database_signable_builder: Arc<dyn SignableBuilder<CardanoDbBeacon>>,
58 ) -> Self {
59 Self {
60 mithril_stake_distribution_builder,
61 immutable_signable_builder,
62 cardano_transactions_signable_builder,
63 cardano_blocks_transactions_signable_builder,
64 cardano_stake_distribution_builder,
65 cardano_database_signable_builder,
66 }
67 }
68}
69
70impl MithrilSignableBuilderService {
71 pub fn new(
73 seed_signable_builder: Arc<dyn SignableSeedBuilder>,
74 dependencies: SignableBuilderServiceDependencies,
75 logger: Logger,
76 ) -> Self {
77 Self {
78 seed_signable_builder,
79 mithril_stake_distribution_builder: dependencies.mithril_stake_distribution_builder,
80 immutable_signable_builder: dependencies.immutable_signable_builder,
81 cardano_transactions_signable_builder: dependencies
82 .cardano_transactions_signable_builder,
83 cardano_blocks_transactions_signable_builder: dependencies
84 .cardano_blocks_transactions_signable_builder,
85 cardano_stake_distribution_builder: dependencies.cardano_stake_distribution_builder,
86 cardano_database_signable_builder: dependencies.cardano_database_signable_builder,
87 logger: logger.new_with_component_name::<Self>(),
88 }
89 }
90
91 async fn compute_signed_entity_protocol_message(
92 &self,
93 signed_entity_type: SignedEntityType,
94 ) -> StdResult<ProtocolMessage> {
95 debug!(
96 self.logger,
97 "Compute protocol message for signed entity type: '{signed_entity_type:?}'"
98 );
99
100 let protocol_message = match &signed_entity_type {
101 SignedEntityType::MithrilStakeDistribution(e) => {
102 self.mithril_stake_distribution_builder
103 .compute_protocol_message(*e)
104 .await
105 }
106 SignedEntityType::CardanoImmutableFilesFull(beacon) => {
107 self.immutable_signable_builder
108 .compute_protocol_message(beacon.clone())
109 .await
110 }
111 SignedEntityType::CardanoStakeDistribution(e) => {
112 self.cardano_stake_distribution_builder
113 .compute_protocol_message(*e)
114 .await
115 }
116 SignedEntityType::CardanoTransactions(_, block_number) => {
117 self.cardano_transactions_signable_builder
118 .compute_protocol_message(*block_number)
119 .await
120 }
121 SignedEntityType::CardanoBlocksTransactions(_, block_number) => {
122 self.cardano_blocks_transactions_signable_builder
123 .compute_protocol_message(*block_number)
124 .await
125 }
126 SignedEntityType::CardanoDatabase(beacon) => {
127 self.cardano_database_signable_builder
128 .compute_protocol_message(beacon.clone())
129 .await
130 }
131 }
132 .with_context(|| {
133 format!("Signable builder service can not compute protocol message for signed entity type: '{signed_entity_type:?}'")
134 })?;
135
136 Ok(protocol_message)
137 }
138
139 async fn compute_seeded_protocol_message(
140 &self,
141 protocol_message: ProtocolMessage,
142 ) -> StdResult<ProtocolMessage> {
143 let mut protocol_message = protocol_message;
144 let next_aggregate_verification_key = self
145 .seed_signable_builder
146 .compute_next_aggregate_verification_key_for_concatenation()
147 .await?;
148 protocol_message.set_message_part(
149 ProtocolMessagePartKey::NextAggregateVerificationKey,
150 next_aggregate_verification_key,
151 );
152
153 let next_protocol_parameters =
154 self.seed_signable_builder.compute_next_protocol_parameters().await?;
155 protocol_message.set_message_part(
156 ProtocolMessagePartKey::NextProtocolParameters,
157 next_protocol_parameters,
158 );
159 let current_epoch = self.seed_signable_builder.compute_current_epoch().await?;
160 protocol_message.set_message_part(ProtocolMessagePartKey::CurrentEpoch, current_epoch);
161
162 Ok(protocol_message)
163 }
164}
165
166#[async_trait]
167impl SignableBuilderService for MithrilSignableBuilderService {
168 async fn compute_protocol_message(
169 &self,
170 signed_entity_type: SignedEntityType,
171 ) -> StdResult<ProtocolMessage> {
172 let protocol_message = self
173 .compute_signed_entity_protocol_message(signed_entity_type)
174 .await?;
175 let protocol_message = self.compute_seeded_protocol_message(protocol_message).await?;
176
177 Ok(protocol_message)
178 }
179}
180
181#[cfg(test)]
182mod tests {
183 use super::*;
184
185 use crate::{
186 StdResult,
187 entities::{BlockNumber, Epoch, ProtocolMessage},
188 signable_builder::{Beacon as Beaconnable, MockSignableSeedBuilder, SignableBuilder},
189 test::TestLogger,
190 };
191
192 use async_trait::async_trait;
193 use mockall::mock;
194
195 mock! {
196 SignableBuilderImpl<U> { }
197
198 #[async_trait]
199 impl<U> SignableBuilder<U> for SignableBuilderImpl<U> where U: Beaconnable,
200 {
201 async fn compute_protocol_message(&self, beacon: U) -> StdResult<ProtocolMessage>;
202 }
203 }
204
205 struct MockDependencyInjector {
206 mock_signable_seed_builder: MockSignableSeedBuilder,
207 mock_mithril_stake_distribution_signable_builder: MockSignableBuilderImpl<Epoch>,
208 mock_cardano_immutable_files_full_signable_builder:
209 MockSignableBuilderImpl<CardanoDbBeacon>,
210 mock_cardano_transactions_signable_builder: MockSignableBuilderImpl<BlockNumber>,
211 mock_cardano_blocks_transactions_signable_builder: MockSignableBuilderImpl<BlockNumber>,
212 mock_cardano_stake_distribution_signable_builder: MockSignableBuilderImpl<Epoch>,
213 mock_cardano_database_signable_builder: MockSignableBuilderImpl<CardanoDbBeacon>,
214 }
215
216 impl MockDependencyInjector {
217 fn new() -> MockDependencyInjector {
218 MockDependencyInjector {
219 mock_signable_seed_builder: MockSignableSeedBuilder::new(),
220 mock_mithril_stake_distribution_signable_builder: MockSignableBuilderImpl::new(),
221 mock_cardano_immutable_files_full_signable_builder: MockSignableBuilderImpl::new(),
222 mock_cardano_transactions_signable_builder: MockSignableBuilderImpl::new(),
223 mock_cardano_blocks_transactions_signable_builder: MockSignableBuilderImpl::new(),
224 mock_cardano_stake_distribution_signable_builder: MockSignableBuilderImpl::new(),
225 mock_cardano_database_signable_builder: MockSignableBuilderImpl::new(),
226 }
227 }
228
229 fn build_signable_builder_service(self) -> MithrilSignableBuilderService {
230 let dependencies = SignableBuilderServiceDependencies::new(
231 Arc::new(self.mock_mithril_stake_distribution_signable_builder),
232 Arc::new(self.mock_cardano_immutable_files_full_signable_builder),
233 Arc::new(self.mock_cardano_transactions_signable_builder),
234 Arc::new(self.mock_cardano_blocks_transactions_signable_builder),
235 Arc::new(self.mock_cardano_stake_distribution_signable_builder),
236 Arc::new(self.mock_cardano_database_signable_builder),
237 );
238
239 MithrilSignableBuilderService::new(
240 Arc::new(self.mock_signable_seed_builder),
241 dependencies,
242 TestLogger::stdout(),
243 )
244 }
245 }
246
247 fn build_mock_container() -> MockDependencyInjector {
248 let mut mock_container = MockDependencyInjector::new();
249 mock_container
250 .mock_signable_seed_builder
251 .expect_compute_next_aggregate_verification_key_for_concatenation()
252 .once()
253 .return_once(move || Ok("next-avk-123".to_string()));
254 mock_container
255 .mock_signable_seed_builder
256 .expect_compute_next_protocol_parameters()
257 .once()
258 .return_once(move || Ok("protocol-params-hash-123".to_string()));
259 mock_container
260 .mock_signable_seed_builder
261 .expect_compute_current_epoch()
262 .once()
263 .return_once(move || Ok("epoch-123".to_string()));
264
265 mock_container
266 }
267
268 #[tokio::test]
269 async fn build_mithril_stake_distribution_signable_when_given_mithril_stake_distribution_entity_type()
270 {
271 let mut mock_container = build_mock_container();
272 mock_container
273 .mock_mithril_stake_distribution_signable_builder
274 .expect_compute_protocol_message()
275 .once()
276 .return_once(|_| Ok(ProtocolMessage::new()));
277 let signable_builder_service = mock_container.build_signable_builder_service();
278 let signed_entity_type = SignedEntityType::MithrilStakeDistribution(Epoch(1));
279
280 signable_builder_service
281 .compute_protocol_message(signed_entity_type)
282 .await
283 .unwrap();
284 }
285
286 #[tokio::test]
287 async fn build_snapshot_signable_when_given_cardano_immutable_files_full_entity_type() {
288 let mut mock_container = build_mock_container();
289 mock_container
290 .mock_cardano_immutable_files_full_signable_builder
291 .expect_compute_protocol_message()
292 .once()
293 .return_once(|_| Ok(ProtocolMessage::new()));
294 let signable_builder_service = mock_container.build_signable_builder_service();
295 let signed_entity_type =
296 SignedEntityType::CardanoImmutableFilesFull(CardanoDbBeacon::default());
297
298 signable_builder_service
299 .compute_protocol_message(signed_entity_type)
300 .await
301 .unwrap();
302 }
303
304 #[tokio::test]
305 async fn build_transactions_signable_when_given_cardano_transactions_entity_type() {
306 let mut mock_container = build_mock_container();
307 mock_container
308 .mock_cardano_transactions_signable_builder
309 .expect_compute_protocol_message()
310 .once()
311 .return_once(|_| Ok(ProtocolMessage::new()));
312 let signable_builder_service = mock_container.build_signable_builder_service();
313 let signed_entity_type = SignedEntityType::CardanoTransactions(Epoch(5), BlockNumber(1000));
314
315 signable_builder_service
316 .compute_protocol_message(signed_entity_type)
317 .await
318 .unwrap();
319 }
320
321 #[tokio::test]
322 async fn build_blocks_transactions_signable_when_given_cardano_blocks_transactions_entity_type()
323 {
324 let mut mock_container = build_mock_container();
325 mock_container
326 .mock_cardano_blocks_transactions_signable_builder
327 .expect_compute_protocol_message()
328 .once()
329 .return_once(|_| Ok(ProtocolMessage::new()));
330 let signable_builder_service = mock_container.build_signable_builder_service();
331 let signed_entity_type =
332 SignedEntityType::CardanoBlocksTransactions(Epoch(6), BlockNumber(1010));
333
334 signable_builder_service
335 .compute_protocol_message(signed_entity_type)
336 .await
337 .unwrap();
338 }
339
340 #[tokio::test]
341 async fn build_cardano_stake_distribution_signable_when_given_cardano_stake_distribution_entity_type()
342 {
343 let mut mock_container = build_mock_container();
344 mock_container
345 .mock_cardano_stake_distribution_signable_builder
346 .expect_compute_protocol_message()
347 .once()
348 .return_once(|_| Ok(ProtocolMessage::new()));
349 let signable_builder_service = mock_container.build_signable_builder_service();
350 let signed_entity_type = SignedEntityType::CardanoStakeDistribution(Epoch(5));
351
352 signable_builder_service
353 .compute_protocol_message(signed_entity_type)
354 .await
355 .unwrap();
356 }
357
358 #[tokio::test]
359 async fn build_cardano_database_signable_when_given_cardano_database_entity_type() {
360 let mut mock_container = build_mock_container();
361 mock_container
362 .mock_cardano_database_signable_builder
363 .expect_compute_protocol_message()
364 .once()
365 .return_once(|_| Ok(ProtocolMessage::new()));
366 let signable_builder_service = mock_container.build_signable_builder_service();
367 let signed_entity_type = SignedEntityType::CardanoDatabase(CardanoDbBeacon::default());
368
369 signable_builder_service
370 .compute_protocol_message(signed_entity_type)
371 .await
372 .unwrap();
373 }
374}