mithril_signer/services/cardano_transactions/importer/
importer_with_pruner.rs1use std::sync::Arc;
2
3use async_trait::async_trait;
4use slog::{debug, Logger};
5
6use mithril_common::entities::BlockNumber;
7use mithril_common::logging::LoggerExtensions;
8use mithril_common::signable_builder::TransactionsImporter;
9use mithril_common::StdResult;
10
11#[cfg_attr(test, mockall::automock)]
13#[async_trait]
14pub trait TransactionPruner: Send + Sync {
15 async fn prune(&self, number_of_blocks_to_keep: BlockNumber) -> StdResult<()>;
17}
18
19pub struct TransactionsImporterWithPruner {
24 number_of_blocks_to_keep: Option<BlockNumber>,
25 transaction_pruner: Arc<dyn TransactionPruner>,
26 wrapped_importer: Arc<dyn TransactionsImporter>,
27 logger: Logger,
28}
29
30impl TransactionsImporterWithPruner {
31 pub fn new(
33 number_of_blocks_to_keep: Option<BlockNumber>,
34 transaction_pruner: Arc<dyn TransactionPruner>,
35 wrapped_importer: Arc<dyn TransactionsImporter>,
36 logger: Logger,
37 ) -> Self {
38 Self {
39 number_of_blocks_to_keep,
40 transaction_pruner,
41 wrapped_importer,
42 logger: logger.new_with_component_name::<Self>(),
43 }
44 }
45}
46
47#[async_trait]
48impl TransactionsImporter for TransactionsImporterWithPruner {
49 async fn import(&self, up_to_beacon: BlockNumber) -> StdResult<()> {
50 self.wrapped_importer.import(up_to_beacon).await?;
51
52 if let Some(number_of_blocks_to_keep) = self.number_of_blocks_to_keep {
53 debug!(
54 self.logger,
55 "Transaction Import finished - Pruning transactions included in block range roots";
56 "number_of_blocks_to_keep" => *number_of_blocks_to_keep,
57 );
58 self.transaction_pruner
59 .prune(number_of_blocks_to_keep)
60 .await?;
61 }
62
63 Ok(())
64 }
65}
66
67#[cfg(test)]
68mod tests {
69 use mockall::mock;
70 use mockall::predicate::eq;
71
72 use crate::test_tools::TestLogger;
73
74 use super::*;
75
76 mock! {
77 pub TransactionImporterImpl {}
78
79 #[async_trait]
80 impl TransactionsImporter for TransactionImporterImpl {
81 async fn import(&self, up_to_beacon: BlockNumber) -> StdResult<()>;
82 }
83 }
84
85 impl TransactionsImporterWithPruner {
86 pub(crate) fn new_with_mock<P, I>(
87 number_of_blocks_to_keep: Option<BlockNumber>,
88 transaction_pruner_mock_config: P,
89 importer_mock_config: I,
90 ) -> Self
91 where
92 P: FnOnce(&mut MockTransactionPruner),
93 I: FnOnce(&mut MockTransactionImporterImpl),
94 {
95 let mut transaction_pruner = MockTransactionPruner::new();
96 transaction_pruner_mock_config(&mut transaction_pruner);
97 let mut transaction_importer = MockTransactionImporterImpl::new();
98 importer_mock_config(&mut transaction_importer);
99
100 Self::new(
101 number_of_blocks_to_keep,
102 Arc::new(transaction_pruner),
103 Arc::new(transaction_importer),
104 TestLogger::stdout(),
105 )
106 }
107 }
108
109 #[tokio::test]
110 async fn test_does_not_prune_if_none_is_configured() {
111 let importer = TransactionsImporterWithPruner::new_with_mock(
112 None,
113 |mock| {
114 mock.expect_prune().never();
115 },
116 |mock| {
117 mock.expect_import().once().returning(|_| Ok(()));
118 },
119 );
120
121 importer
122 .import(BlockNumber(100))
123 .await
124 .expect("Import should not fail");
125 }
126
127 #[tokio::test]
128 async fn test_does_prune_if_a_block_number_is_configured() {
129 let expected_block_number = BlockNumber(5);
130 let importer = TransactionsImporterWithPruner::new_with_mock(
131 Some(expected_block_number),
132 |mock| {
133 mock.expect_prune()
134 .with(eq(expected_block_number))
135 .once()
136 .returning(|_| Ok(()));
137 },
138 |mock| {
139 mock.expect_import().once().returning(|_| Ok(()));
140 },
141 );
142
143 importer
144 .import(BlockNumber(100))
145 .await
146 .expect("Import should not fail");
147 }
148}