mithril_signer/services/signature_publisher/
delayer.rs1use std::{sync::Arc, time::Duration};
2
3use mithril_common::{
4 entities::{ProtocolMessage, SignedEntityType, SingleSignature},
5 logging::LoggerExtensions,
6 StdResult,
7};
8use slog::{error, Logger};
9
10use super::SignaturePublisher;
11
12pub struct SignaturePublisherDelayer {
15 first_publisher: Arc<dyn SignaturePublisher>,
16 second_publisher: Arc<dyn SignaturePublisher>,
17 delay_between_publish: Duration,
18 logger: Logger,
19}
20
21impl SignaturePublisherDelayer {
22 pub fn new(
24 first_publisher: Arc<dyn SignaturePublisher>,
25 second_publisher: Arc<dyn SignaturePublisher>,
26 delay_between_publish: Duration,
27 logger: Logger,
28 ) -> Self {
29 Self {
30 first_publisher,
31 second_publisher,
32 delay_between_publish,
33 logger: logger.new_with_component_name::<Self>(),
34 }
35 }
36}
37
38#[async_trait::async_trait]
39impl SignaturePublisher for SignaturePublisherDelayer {
40 async fn publish(
41 &self,
42 signed_entity_type: &SignedEntityType,
43 signature: &SingleSignature,
44 protocol_message: &ProtocolMessage,
45 ) -> StdResult<()> {
46 if let Err(e) = self
47 .first_publisher
48 .publish(signed_entity_type, signature, protocol_message)
49 .await
50 {
51 error!(
52 self.logger,
53 "Delayer failed to publish first signature";
54 "error" => ?e
55 );
56 }
57
58 tokio::time::sleep(self.delay_between_publish).await;
59
60 if let Err(e) = self
61 .second_publisher
62 .publish(signed_entity_type, signature, protocol_message)
63 .await
64 {
65 error!(
66 self.logger,
67 "Delayer failed to publish second signature";
68 "error" => ?e
69 );
70 return Err(e);
71 }
72
73 Ok(())
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use mithril_common::{entities::Epoch, test_utils::fake_data};
80
81 use crate::{services::MockSignaturePublisher, test_tools::TestLogger};
82
83 use super::*;
84
85 #[tokio::test]
86 async fn should_call_both_publishers_when_first_succeeds() {
87 let mut first_publisher = MockSignaturePublisher::new();
88 first_publisher
89 .expect_publish()
90 .once()
91 .returning(|_, _, _| Ok(()));
92
93 let mut second_publisher = MockSignaturePublisher::new();
94 second_publisher
95 .expect_publish()
96 .once()
97 .returning(|_, _, _| Ok(()));
98
99 let delayer = SignaturePublisherDelayer::new(
100 Arc::new(first_publisher),
101 Arc::new(second_publisher),
102 Duration::from_millis(0),
103 TestLogger::stdout(),
104 );
105
106 delayer
107 .publish(
108 &SignedEntityType::MithrilStakeDistribution(Epoch(1)),
109 &fake_data::single_signature(vec![1]),
110 &ProtocolMessage::default(),
111 )
112 .await
113 .unwrap();
114 }
115
116 #[tokio::test]
117 async fn should_call_second_publisher_even_if_first_fails_and_log_error() {
118 let (logger, log_inspector) = TestLogger::memory();
119 let mut first_publisher = MockSignaturePublisher::new();
120 first_publisher
121 .expect_publish()
122 .once()
123 .returning(|_, _, _| Err(anyhow::anyhow!("first publisher failure")));
124
125 let mut second_publisher = MockSignaturePublisher::new();
126 second_publisher
127 .expect_publish()
128 .once()
129 .returning(|_, _, _| Ok(()));
130
131 let delayer = SignaturePublisherDelayer::new(
132 Arc::new(first_publisher),
133 Arc::new(second_publisher),
134 Duration::from_millis(0),
135 logger,
136 );
137
138 delayer
139 .publish(
140 &SignedEntityType::MithrilStakeDistribution(Epoch(1)),
141 &fake_data::single_signature(vec![1]),
142 &ProtocolMessage::default(),
143 )
144 .await
145 .unwrap();
146
147 assert!(log_inspector.contains_log("Delayer failed to publish first signature"));
148 assert!(log_inspector.contains_log("first publisher failure"));
149 }
150
151 #[tokio::test]
152 async fn should_return_and_log_error_if_second_publisher_fails() {
153 let (logger, log_inspector) = TestLogger::memory();
154 let mut first_publisher = MockSignaturePublisher::new();
155 first_publisher
156 .expect_publish()
157 .once()
158 .returning(|_, _, _| Ok(()));
159
160 let mut second_publisher = MockSignaturePublisher::new();
161 second_publisher
162 .expect_publish()
163 .once()
164 .returning(|_, _, _| Err(anyhow::anyhow!("second publisher failure")));
165
166 let delayer = SignaturePublisherDelayer::new(
167 Arc::new(first_publisher),
168 Arc::new(second_publisher),
169 Duration::from_millis(0),
170 logger,
171 );
172
173 delayer
174 .publish(
175 &SignedEntityType::MithrilStakeDistribution(Epoch(1)),
176 &fake_data::single_signature(vec![1]),
177 &ProtocolMessage::default(),
178 )
179 .await
180 .expect_err("Expected error when delayed publisher failed");
181
182 assert!(log_inspector.contains_log("Delayer failed to publish second signature"));
183 assert!(log_inspector.contains_log("second publisher failure"));
184 }
185
186 #[tokio::test]
187 async fn should_wait_before_calling_second_publisher() {
188 let mut first_publisher = MockSignaturePublisher::new();
189 first_publisher
190 .expect_publish()
191 .once()
192 .returning(|_, _, _| Ok(()));
193
194 let mut second_publisher = MockSignaturePublisher::new();
195 second_publisher
196 .expect_publish()
197 .once()
198 .returning(|_, _, _| Ok(()));
199
200 let delay = Duration::from_millis(50);
201 let delayer = SignaturePublisherDelayer::new(
202 Arc::new(first_publisher),
203 Arc::new(second_publisher),
204 delay,
205 TestLogger::stdout(),
206 );
207
208 let start_time = std::time::Instant::now();
209 delayer
210 .publish(
211 &SignedEntityType::MithrilStakeDistribution(Epoch(1)),
212 &fake_data::single_signature(vec![1]),
213 &ProtocolMessage::default(),
214 )
215 .await
216 .unwrap();
217
218 let elapsed_time = start_time.elapsed();
219 assert!(
220 elapsed_time >= delay,
221 "Expected at least {delay:?} time elapsed, but got {elapsed_time:?}"
222 );
223 assert!(
224 elapsed_time < delay * 2,
225 "Expected less than {:?} time elapsed, but got {:?}",
226 delay * 2,
227 elapsed_time
228 );
229 }
230}