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    StdResult, entities::ProtocolMessagePartValue, signable_builder::SignableSeedBuilder,
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::{
62            builder::{MithrilFixture, MithrilFixtureBuilder},
63            double::Dummy,
64        },
65    };
66
67    use crate::{entities::AggregatorEpochSettings, services::FakeEpochServiceBuilder};
68
69    use super::*;
70
71    fn build_signable_builder_service(
72        epoch: Epoch,
73        fixture: &MithrilFixture,
74        next_fixture: &MithrilFixture,
75    ) -> AggregatorSignableSeedBuilder {
76        let epoch_service = Arc::new(RwLock::new(
77            FakeEpochServiceBuilder {
78                current_epoch_settings: AggregatorEpochSettings {
79                    protocol_parameters: fixture.protocol_parameters(),
80                    ..AggregatorEpochSettings::dummy()
81                },
82                next_epoch_settings: AggregatorEpochSettings {
83                    protocol_parameters: next_fixture.protocol_parameters(),
84                    ..AggregatorEpochSettings::dummy()
85                },
86                signer_registration_epoch_settings: AggregatorEpochSettings {
87                    protocol_parameters: next_fixture.protocol_parameters(),
88                    ..AggregatorEpochSettings::dummy()
89                },
90                current_signers_with_stake: fixture.signers_with_stake(),
91                next_signers_with_stake: next_fixture.signers_with_stake(),
92                ..FakeEpochServiceBuilder::dummy(epoch)
93            }
94            .build(),
95        ));
96
97        AggregatorSignableSeedBuilder::new(epoch_service)
98    }
99
100    #[tokio::test]
101    async fn test_compute_next_aggregate_verification_key_protocol_message_value() {
102        let epoch = Epoch(5);
103        let fixture = MithrilFixtureBuilder::default().with_signers(5).build();
104        let next_fixture = MithrilFixtureBuilder::default().with_signers(4).build();
105        let signable_seed_builder = build_signable_builder_service(epoch, &fixture, &next_fixture);
106        let expected_next_aggregate_verification_key = next_fixture.compute_and_encode_avk();
107
108        let next_aggregate_verification_key = signable_seed_builder
109            .compute_next_aggregate_verification_key()
110            .await
111            .unwrap();
112
113        assert_eq!(
114            next_aggregate_verification_key,
115            expected_next_aggregate_verification_key
116        );
117    }
118
119    #[tokio::test]
120    async fn test_compute_next_protocol_parameters_protocol_message_value() {
121        let epoch = Epoch(5);
122        let fixture = MithrilFixtureBuilder::default().with_signers(5).build();
123        let next_fixture = MithrilFixtureBuilder::default().with_signers(4).build();
124        let signable_seed_builder = build_signable_builder_service(epoch, &fixture, &next_fixture);
125        let expected_next_protocol_parameters = next_fixture.protocol_parameters().compute_hash();
126
127        let next_protocol_parameters = signable_seed_builder
128            .compute_next_protocol_parameters()
129            .await
130            .unwrap();
131
132        assert_eq!(next_protocol_parameters, expected_next_protocol_parameters);
133    }
134
135    #[tokio::test]
136    async fn test_compute_current_epoch_protocol_message_value() {
137        let epoch = Epoch(5);
138        let fixture = MithrilFixtureBuilder::default().with_signers(5).build();
139        let next_fixture = MithrilFixtureBuilder::default().with_signers(4).build();
140        let signable_seed_builder = build_signable_builder_service(epoch, &fixture, &next_fixture);
141        let expected_current_epoch = epoch.to_string();
142
143        let current_epoch = signable_seed_builder.compute_current_epoch().await.unwrap();
144
145        assert_eq!(current_epoch, expected_current_epoch);
146    }
147}