mithril_signer/services/cardano_transactions/importer/
importer_with_pruner.rs1use std::sync::Arc;
2
3use async_trait::async_trait;
4use slog::{Logger, debug};
5
6use mithril_common::StdResult;
7use mithril_common::entities::BlockNumber;
8use mithril_common::logging::LoggerExtensions;
9use mithril_common::signable_builder::TransactionsImporter;
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.prune(number_of_blocks_to_keep).await?;
59 }
60
61 Ok(())
62 }
63}
64
65#[cfg(test)]
66mod tests {
67 use mockall::mock;
68 use mockall::predicate::eq;
69
70 use crate::test_tools::TestLogger;
71
72 use super::*;
73
74 mock! {
75 pub TransactionImporterImpl {}
76
77 #[async_trait]
78 impl TransactionsImporter for TransactionImporterImpl {
79 async fn import(&self, up_to_beacon: BlockNumber) -> StdResult<()>;
80 }
81 }
82
83 impl TransactionsImporterWithPruner {
84 pub(crate) fn new_with_mock<P, I>(
85 number_of_blocks_to_keep: Option<BlockNumber>,
86 transaction_pruner_mock_config: P,
87 importer_mock_config: I,
88 ) -> Self
89 where
90 P: FnOnce(&mut MockTransactionPruner),
91 I: FnOnce(&mut MockTransactionImporterImpl),
92 {
93 let mut transaction_pruner = MockTransactionPruner::new();
94 transaction_pruner_mock_config(&mut transaction_pruner);
95 let mut transaction_importer = MockTransactionImporterImpl::new();
96 importer_mock_config(&mut transaction_importer);
97
98 Self::new(
99 number_of_blocks_to_keep,
100 Arc::new(transaction_pruner),
101 Arc::new(transaction_importer),
102 TestLogger::stdout(),
103 )
104 }
105 }
106
107 #[tokio::test]
108 async fn test_does_not_prune_if_none_is_configured() {
109 let importer = TransactionsImporterWithPruner::new_with_mock(
110 None,
111 |mock| {
112 mock.expect_prune().never();
113 },
114 |mock| {
115 mock.expect_import().once().returning(|_| Ok(()));
116 },
117 );
118
119 importer
120 .import(BlockNumber(100))
121 .await
122 .expect("Import should not fail");
123 }
124
125 #[tokio::test]
126 async fn test_does_prune_if_a_block_number_is_configured() {
127 let expected_block_number = BlockNumber(5);
128 let importer = TransactionsImporterWithPruner::new_with_mock(
129 Some(expected_block_number),
130 |mock| {
131 mock.expect_prune()
132 .with(eq(expected_block_number))
133 .once()
134 .returning(|_| Ok(()));
135 },
136 |mock| {
137 mock.expect_import().once().returning(|_| Ok(()));
138 },
139 );
140
141 importer
142 .import(BlockNumber(100))
143 .await
144 .expect("Import should not fail");
145 }
146}