mithril_common/signable_builder/
signable_builder_service.rs

1use 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/// ArtifactBuilder Service trait
17#[cfg_attr(test, mockall::automock)]
18#[async_trait]
19pub trait SignableBuilderService: Send + Sync {
20    /// Compute signable from signed entity type
21    async fn compute_protocol_message(
22        &self,
23        signed_entity_type: SignedEntityType,
24    ) -> StdResult<ProtocolMessage>;
25}
26
27/// Mithril Signable Builder Service
28pub 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
39/// SignableBuilders dependencies required by the [MithrilSignableBuilderService].
40pub 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    /// Create a new instance of [SignableBuilderServiceDependencies].
51    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    /// MithrilSignableBuilderService factory
72    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}