mithril_aggregator/services/signer_registration/
verifier.rs

1use std::sync::Arc;
2
3use anyhow::{Context, anyhow};
4use async_trait::async_trait;
5
6use mithril_cardano_node_chain::chain_observer::ChainObserver;
7use mithril_common::{
8    StdResult,
9    crypto_helper::{KesPeriod, ProtocolKeyRegistration},
10    entities::{Signer, SignerWithStake, StakeDistribution},
11};
12
13use super::SignerRegistrationVerifier;
14
15/// Implementation of a [SignerRegistrationVerifier]
16pub struct MithrilSignerRegistrationVerifier {
17    /// Chain observer service.
18    chain_observer: Arc<dyn ChainObserver>,
19}
20
21impl MithrilSignerRegistrationVerifier {
22    /// Creates a new [MithrilSignerRegistrationVerifier].
23    pub fn new(chain_observer: Arc<dyn ChainObserver>) -> Self {
24        Self { chain_observer }
25    }
26}
27
28#[async_trait]
29impl SignerRegistrationVerifier for MithrilSignerRegistrationVerifier {
30    async fn verify(
31        &self,
32        signer: &Signer,
33        stake_distribution: &StakeDistribution,
34    ) -> StdResult<SignerWithStake> {
35        let mut key_registration = ProtocolKeyRegistration::init(
36            &stake_distribution
37                .iter()
38                .map(|(k, v)| (k.to_owned(), *v))
39                .collect::<Vec<_>>(),
40        );
41        let party_id_register = match signer.party_id.as_str() {
42            "" => None,
43            party_id => Some(party_id.to_string()),
44        };
45        let kes_period = match &signer.operational_certificate {
46            Some(operational_certificate) => Some(
47                self.chain_observer
48                    .get_current_kes_period(operational_certificate)
49                    .await?
50                    .unwrap_or_default()
51                    - operational_certificate.start_kes_period as KesPeriod,
52            ),
53            None => None,
54        };
55        let party_id_registered = key_registration
56            .register(
57                party_id_register.clone(),
58                signer.operational_certificate.clone(),
59                signer.verification_key_signature,
60                kes_period,
61                signer.verification_key,
62            )
63            .with_context(|| {
64                format!(
65                    "KeyRegwrapper can not register signer with party_id: '{party_id_register:?}'"
66                )
67            })
68            .map_err(|e| anyhow!(e))?;
69        let party_id_registered_stake = *stake_distribution
70            .get(&party_id_registered)
71            .ok_or(anyhow!("Stake not found"))?;
72
73        Ok(SignerWithStake {
74            party_id: party_id_registered,
75            ..SignerWithStake::from_signer(signer.to_owned(), party_id_registered_stake)
76        })
77    }
78}
79
80#[cfg(test)]
81mod tests {
82    use mithril_cardano_node_chain::test::double::FakeChainObserver;
83    use mithril_common::{entities::TimePoint, test_utils::MithrilFixtureBuilder};
84
85    use super::*;
86
87    #[tokio::test]
88    async fn verify_succeeds_with_valid_signer_registration() {
89        let fixture = MithrilFixtureBuilder::default().with_signers(1).build();
90        let signer_to_register: Signer = fixture.signers()[0].to_owned();
91        let signer_registration_verifier = MithrilSignerRegistrationVerifier::new(Arc::new(
92            FakeChainObserver::new(Some(TimePoint::dummy())),
93        ));
94
95        signer_registration_verifier
96            .verify(&signer_to_register, &fixture.stake_distribution())
97            .await
98            .unwrap();
99    }
100
101    #[tokio::test]
102    async fn verify_fails_with_invalid_signer_registration() {
103        let fixture = MithrilFixtureBuilder::default().with_signers(2).build();
104        let signer_to_register: Signer = Signer {
105            verification_key_signature: fixture.signers()[1].verification_key_signature,
106            ..fixture.signers()[0].to_owned()
107        };
108        let signer_registration_verifier = MithrilSignerRegistrationVerifier::new(Arc::new(
109            FakeChainObserver::new(Some(TimePoint::dummy())),
110        ));
111
112        signer_registration_verifier
113            .verify(&signer_to_register, &fixture.stake_distribution())
114            .await
115            .expect_err("Verification should fail");
116    }
117}