mithril_common/signable_builder/
cardano_database.rs

1use std::{
2    path::{Path, PathBuf},
3    sync::Arc,
4};
5
6use anyhow::Context;
7use async_trait::async_trait;
8use slog::{info, Logger};
9
10use crate::{
11    digesters::ImmutableDigester,
12    entities::{CardanoDbBeacon, ProtocolMessage, ProtocolMessagePartKey},
13    logging::LoggerExtensions,
14    signable_builder::SignableBuilder,
15    StdResult,
16};
17
18/// This structure is responsible for calculating the message for incremental Cardano database.
19pub struct CardanoDatabaseSignableBuilder {
20    digester: Arc<dyn ImmutableDigester>,
21    logger: Logger,
22    dirpath: PathBuf,
23}
24
25impl CardanoDatabaseSignableBuilder {
26    /// Constructor
27    pub fn new(digester: Arc<dyn ImmutableDigester>, dirpath: &Path, logger: Logger) -> Self {
28        Self {
29            digester,
30            logger: logger.new_with_component_name::<Self>(),
31            dirpath: dirpath.to_owned(),
32        }
33    }
34}
35
36#[async_trait]
37impl SignableBuilder<CardanoDbBeacon> for CardanoDatabaseSignableBuilder {
38    async fn compute_protocol_message(
39        &self,
40        beacon: CardanoDbBeacon,
41    ) -> StdResult<ProtocolMessage> {
42        let merkle_tree = self
43            .digester
44            .compute_merkle_tree(&self.dirpath, &beacon)
45            .await
46            .with_context(|| {
47                format!(
48                    "Cardano Database Signable Builder can not compute merkle tree of '{}'",
49                    &self.dirpath.display()
50                )
51            })?;
52
53        let merkle_root = merkle_tree.compute_root()?.to_hex();
54        info!(
55            self.logger,
56            "Computed Cardano database Merkle root = '{merkle_root}'"
57        );
58
59        let mut protocol_message = ProtocolMessage::new();
60        protocol_message.set_message_part(
61            ProtocolMessagePartKey::CardanoDatabaseMerkleRoot,
62            merkle_root,
63        );
64
65        Ok(protocol_message)
66    }
67}
68
69#[cfg(test)]
70mod tests {
71    use std::path::Path;
72
73    use crate::{
74        crypto_helper::{MKTree, MKTreeStoreInMemory},
75        digesters::DumbImmutableDigester,
76        entities::{CardanoDbBeacon, ProtocolMessagePartKey},
77        test_utils::TestLogger,
78    };
79
80    use super::*;
81
82    #[tokio::test]
83    async fn compute_signable() {
84        let digests = vec!["digest-1".to_string(), "digest-2".to_string()];
85        let digester = DumbImmutableDigester::default().with_merkle_tree(digests.clone());
86        let signable_builder = CardanoDatabaseSignableBuilder::new(
87            Arc::new(digester),
88            Path::new(""),
89            TestLogger::stdout(),
90        );
91
92        let protocol_message = signable_builder
93            .compute_protocol_message(CardanoDbBeacon::default())
94            .await
95            .unwrap();
96
97        let expected_mktree: MKTree<MKTreeStoreInMemory> = MKTree::new(&digests).unwrap();
98        let mut expected_message = ProtocolMessage::new();
99        expected_message.set_message_part(
100            ProtocolMessagePartKey::CardanoDatabaseMerkleRoot,
101            expected_mktree.compute_root().unwrap().to_hex(),
102        );
103        assert_eq!(expected_message, protocol_message);
104    }
105}