mithril_cardano_node_chain/chain_scanner/
block_scanner.rs

1use std::sync::Arc;
2use std::time::Duration;
3
4use async_trait::async_trait;
5use slog::Logger;
6use tokio::sync::Mutex;
7
8use mithril_common::StdResult;
9use mithril_common::entities::BlockNumber;
10
11use crate::chain_reader::ChainBlockReader;
12use crate::chain_scanner::block_streamer_with_throttling::BlockStreamerWithThrottling;
13use crate::chain_scanner::{BlockScanner, BlockStreamer};
14use crate::entities::RawCardanoPoint;
15
16use super::ChainReaderBlockStreamer;
17
18/// Cardano block scanner
19///
20/// This scanner reads the blocks with a chain block reader
21pub struct CardanoBlockScanner {
22    chain_reader: Arc<Mutex<dyn ChainBlockReader>>,
23    max_roll_forwards_per_poll: usize,
24    throttling_interval: Option<Duration>,
25    logger: Logger,
26}
27
28impl CardanoBlockScanner {
29    /// Factory
30    pub fn new(
31        chain_reader: Arc<Mutex<dyn ChainBlockReader>>,
32        max_roll_forwards_per_poll: usize,
33        logger: Logger,
34    ) -> Self {
35        Self {
36            chain_reader,
37            max_roll_forwards_per_poll,
38            throttling_interval: None,
39            logger,
40        }
41    }
42
43    /// Set the optional throttling interval for the block scanner
44    ///
45    /// This ensures that the scanner will not poll the chain reader more frequently than the
46    /// specified interval.
47    pub fn set_throttling_interval(mut self, interval: Option<Duration>) -> Self {
48        if interval.is_none_or(|i| i.is_zero()) {
49            self.throttling_interval = None;
50        } else {
51            self.throttling_interval = interval;
52        }
53        self
54    }
55}
56
57#[async_trait]
58impl BlockScanner for CardanoBlockScanner {
59    async fn scan(
60        &self,
61        from: Option<RawCardanoPoint>,
62        until: BlockNumber,
63    ) -> StdResult<Box<dyn BlockStreamer>> {
64        let streamer = Box::new(
65            ChainReaderBlockStreamer::try_new(
66                self.chain_reader.clone(),
67                from,
68                until,
69                self.max_roll_forwards_per_poll,
70                self.logger.clone(),
71            )
72            .await?,
73        );
74
75        match self.throttling_interval {
76            Some(interval) => Ok(Box::new(BlockStreamerWithThrottling::new(
77                streamer, interval,
78            ))),
79            None => Ok(streamer),
80        }
81    }
82}
83
84#[cfg(test)]
85mod tests {
86    use crate::test::TestLogger;
87    use crate::test::double::FakeChainReader;
88
89    use super::*;
90
91    #[test]
92    fn setting_interval_of_zero_is_same_as_setting_it_to_none() {
93        let scanner = CardanoBlockScanner::new(
94            Arc::new(Mutex::new(FakeChainReader::new(vec![]))),
95            100,
96            TestLogger::stdout(),
97        );
98
99        assert!(scanner.throttling_interval.is_none());
100
101        let scanner = scanner.set_throttling_interval(Some(Duration::from_secs(0)));
102        assert!(scanner.throttling_interval.is_none());
103    }
104}