mithril_aggregator/services/signable_builder/
signable_seed_builder.rs

1//! ## AggregatorSignableSeedBuilder
2//!
3//! This service is responsible for computing the seed protocol message
4//! that is used by the [SignableBuilder] to compute the final protocol message.
5//!
6use anyhow::Context;
7use async_trait::async_trait;
8use std::sync::Arc;
9use tokio::sync::RwLock;
10
11use mithril_common::{
12    entities::ProtocolMessagePartValue, signable_builder::SignableSeedBuilder, StdResult,
13};
14
15use crate::services::EpochService;
16
17/// SignableSeedBuilder aggregator implementation
18pub struct AggregatorSignableSeedBuilder {
19    epoch_service: Arc<RwLock<dyn EpochService>>,
20}
21
22impl AggregatorSignableSeedBuilder {
23    /// AggregatorSignableSeedBuilder factory
24    pub fn new(epoch_service: Arc<RwLock<dyn EpochService>>) -> Self {
25        Self { epoch_service }
26    }
27}
28
29#[async_trait]
30impl SignableSeedBuilder for AggregatorSignableSeedBuilder {
31    async fn compute_next_aggregate_verification_key(&self) -> StdResult<ProtocolMessagePartValue> {
32        let epoch_service = self.epoch_service.read().await;
33        let next_aggregate_verification_key = (*epoch_service)
34            .next_aggregate_verification_key()?
35            .to_json_hex()
36            .with_context(|| "convert next avk to json hex failure")?
37            .to_string();
38
39        Ok(next_aggregate_verification_key)
40    }
41
42    async fn compute_next_protocol_parameters(&self) -> StdResult<ProtocolMessagePartValue> {
43        let epoch_service = self.epoch_service.read().await;
44        let next_protocol_parameters = epoch_service.next_protocol_parameters()?.compute_hash();
45
46        Ok(next_protocol_parameters)
47    }
48
49    async fn compute_current_epoch(&self) -> StdResult<ProtocolMessagePartValue> {
50        let epoch_service = self.epoch_service.read().await;
51        let current_epoch = epoch_service.epoch_of_current_data()?.to_string();
52
53        Ok(current_epoch)
54    }
55}
56
57#[cfg(test)]
58mod tests {
59    use mithril_common::{
60        entities::Epoch,
61        test_utils::{MithrilFixture, MithrilFixtureBuilder},
62    };
63
64    use crate::{entities::AggregatorEpochSettings, services::FakeEpochServiceBuilder};
65
66    use super::*;
67
68    fn build_signable_builder_service(
69        epoch: Epoch,
70        fixture: &MithrilFixture,
71        next_fixture: &MithrilFixture,
72    ) -> AggregatorSignableSeedBuilder {
73        let epoch_service = Arc::new(RwLock::new(
74            FakeEpochServiceBuilder {
75                current_epoch_settings: AggregatorEpochSettings {
76                    protocol_parameters: fixture.protocol_parameters(),
77                    ..AggregatorEpochSettings::dummy()
78                },
79                next_epoch_settings: AggregatorEpochSettings {
80                    protocol_parameters: next_fixture.protocol_parameters(),
81                    ..AggregatorEpochSettings::dummy()
82                },
83                signer_registration_epoch_settings: AggregatorEpochSettings {
84                    protocol_parameters: next_fixture.protocol_parameters(),
85                    ..AggregatorEpochSettings::dummy()
86                },
87                current_signers_with_stake: fixture.signers_with_stake(),
88                next_signers_with_stake: next_fixture.signers_with_stake(),
89                ..FakeEpochServiceBuilder::dummy(epoch)
90            }
91            .build(),
92        ));
93
94        AggregatorSignableSeedBuilder::new(epoch_service)
95    }
96
97    #[tokio::test]
98    async fn test_compute_next_aggregate_verification_key_protocol_message_value() {
99        let epoch = Epoch(5);
100        let fixture = MithrilFixtureBuilder::default().with_signers(5).build();
101        let next_fixture = MithrilFixtureBuilder::default().with_signers(4).build();
102        let signable_seed_builder = build_signable_builder_service(epoch, &fixture, &next_fixture);
103        let expected_next_aggregate_verification_key = next_fixture.compute_and_encode_avk();
104
105        let next_aggregate_verification_key = signable_seed_builder
106            .compute_next_aggregate_verification_key()
107            .await
108            .unwrap();
109
110        assert_eq!(
111            next_aggregate_verification_key,
112            expected_next_aggregate_verification_key
113        );
114    }
115
116    #[tokio::test]
117    async fn test_compute_next_protocol_parameters_protocol_message_value() {
118        let epoch = Epoch(5);
119        let fixture = MithrilFixtureBuilder::default().with_signers(5).build();
120        let next_fixture = MithrilFixtureBuilder::default().with_signers(4).build();
121        let signable_seed_builder = build_signable_builder_service(epoch, &fixture, &next_fixture);
122        let expected_next_protocol_parameters = next_fixture.protocol_parameters().compute_hash();
123
124        let next_protocol_parameters = signable_seed_builder
125            .compute_next_protocol_parameters()
126            .await
127            .unwrap();
128
129        assert_eq!(next_protocol_parameters, expected_next_protocol_parameters);
130    }
131
132    #[tokio::test]
133    async fn test_compute_current_epoch_protocol_message_value() {
134        let epoch = Epoch(5);
135        let fixture = MithrilFixtureBuilder::default().with_signers(5).build();
136        let next_fixture = MithrilFixtureBuilder::default().with_signers(4).build();
137        let signable_seed_builder = build_signable_builder_service(epoch, &fixture, &next_fixture);
138        let expected_current_epoch = epoch.to_string();
139
140        let current_epoch = signable_seed_builder.compute_current_epoch().await.unwrap();
141
142        assert_eq!(current_epoch, expected_current_epoch);
143    }
144}