mithril_cardano_node_chain/test/double/
chain_observer.rs1use async_trait::async_trait;
2use tokio::sync::RwLock;
3
4use mithril_common::crypto_helper::{KesPeriod, OpCert};
5use mithril_common::entities::{
6 BlockNumber, ChainPoint, Epoch, SignerWithStake, SlotNumber, StakeDistribution, TimePoint,
7};
8
9use crate::chain_observer::{ChainObserver, ChainObserverError};
10use crate::entities::{ChainAddress, TxDatum};
11
12pub struct FakeChainObserver {
14 pub signers: RwLock<Vec<SignerWithStake>>,
18
19 pub current_time_point: RwLock<Option<TimePoint>>,
23
24 pub datums: RwLock<Vec<TxDatum>>,
28
29 pub current_era: RwLock<String>,
33}
34
35impl FakeChainObserver {
36 pub fn new(current_time_point: Option<TimePoint>) -> Self {
38 Self {
39 signers: RwLock::new(vec![]),
40 current_time_point: RwLock::new(current_time_point.clone()),
41 datums: RwLock::new(vec![]),
42 current_era: RwLock::new(String::new()),
43 }
44 }
45
46 pub async fn next_epoch(&self) -> Option<Epoch> {
48 let mut current_time_point = self.current_time_point.write().await;
49 *current_time_point = current_time_point.as_ref().map(|time_point| TimePoint {
50 epoch: time_point.epoch + 1,
51 ..time_point.clone()
52 });
53
54 current_time_point.as_ref().map(|b| b.epoch)
55 }
56
57 pub async fn increase_block_number(&self, increment: u64) -> Option<BlockNumber> {
60 self.change_block_number(|actual_block_number| actual_block_number + increment)
61 .await
62 }
63
64 pub async fn decrease_block_number(&self, decrement: u64) -> Option<BlockNumber> {
67 self.change_block_number(|actual_block_number| actual_block_number - decrement)
68 .await
69 }
70
71 async fn change_block_number(
72 &self,
73 change_to_apply: impl Fn(BlockNumber) -> BlockNumber,
74 ) -> Option<BlockNumber> {
75 let mut current_time_point = self.current_time_point.write().await;
76
77 *current_time_point = current_time_point.as_ref().map(|time_point| TimePoint {
78 chain_point: ChainPoint {
79 block_number: change_to_apply(time_point.chain_point.block_number),
80 ..time_point.chain_point.clone()
81 },
82 ..time_point.clone()
83 });
84
85 current_time_point.as_ref().map(|b| b.chain_point.block_number)
86 }
87
88 pub async fn increase_slot_number(&self, increment: u64) -> Option<SlotNumber> {
91 self.change_slot_number(|actual_slot_number| actual_slot_number + increment)
92 .await
93 }
94
95 pub async fn decrease_slot_number(&self, decrement: u64) -> Option<SlotNumber> {
98 self.change_slot_number(|actual_slot_number| actual_slot_number - decrement)
99 .await
100 }
101
102 async fn change_slot_number(
103 &self,
104 change_to_apply: impl Fn(SlotNumber) -> SlotNumber,
105 ) -> Option<SlotNumber> {
106 let mut current_time_point = self.current_time_point.write().await;
107
108 *current_time_point = current_time_point.as_ref().map(|time_point| TimePoint {
109 chain_point: ChainPoint {
110 slot_number: change_to_apply(time_point.chain_point.slot_number),
111 ..time_point.chain_point.clone()
112 },
113 ..time_point.clone()
114 });
115
116 current_time_point.as_ref().map(|b| b.chain_point.slot_number)
117 }
118
119 pub async fn set_signers(&self, new_signers: Vec<SignerWithStake>) {
122 let mut signers = self.signers.write().await;
123 *signers = new_signers;
124 }
125
126 pub async fn set_current_time_point(&self, new_current_time_point: Option<TimePoint>) {
128 let mut current_time_point = self.current_time_point.write().await;
129 *current_time_point = new_current_time_point;
130 }
131
132 pub async fn set_datums(&self, new_datums: Vec<TxDatum>) {
135 let mut datums = self.datums.write().await;
136 *datums = new_datums;
137 }
138
139 pub async fn set_current_era(&self, new_current_era: String) {
142 let mut current_era = self.current_era.write().await;
143 *current_era = new_current_era;
144 }
145}
146
147impl Default for FakeChainObserver {
148 fn default() -> Self {
149 let mut observer = Self::new(Some(TimePoint::new(
150 10,
151 100,
152 ChainPoint::new(SlotNumber(1000), BlockNumber(100), "hash"),
153 )));
154 observer.signers = RwLock::new(Vec::new());
155
156 observer
157 }
158}
159
160#[async_trait]
161impl ChainObserver for FakeChainObserver {
162 async fn get_current_datums(
163 &self,
164 _address: &ChainAddress,
165 ) -> Result<Vec<TxDatum>, ChainObserverError> {
166 let datums = self.datums.read().await;
167 Ok(datums.to_vec())
168 }
169
170 async fn get_current_era(&self) -> Result<Option<String>, ChainObserverError> {
171 Ok(Some(self.current_era.read().await.clone()))
172 }
173
174 async fn get_current_epoch(&self) -> Result<Option<Epoch>, ChainObserverError> {
175 Ok(self
176 .current_time_point
177 .read()
178 .await
179 .as_ref()
180 .map(|time_point| time_point.epoch))
181 }
182
183 async fn get_current_chain_point(&self) -> Result<Option<ChainPoint>, ChainObserverError> {
184 Ok(self
185 .current_time_point
186 .read()
187 .await
188 .as_ref()
189 .map(|time_point| time_point.chain_point.clone()))
190 }
191
192 async fn get_current_stake_distribution(
193 &self,
194 ) -> Result<Option<StakeDistribution>, ChainObserverError> {
195 Ok(Some(
196 self.signers
197 .read()
198 .await
199 .iter()
200 .map(|signer| (signer.party_id.clone(), signer.stake))
201 .collect::<StakeDistribution>(),
202 ))
203 }
204
205 async fn get_current_kes_period(
206 &self,
207 _opcert: &OpCert,
208 ) -> Result<Option<KesPeriod>, ChainObserverError> {
209 Ok(Some(0))
210 }
211}
212
213#[cfg(test)]
214mod tests {
215 use mithril_common::test_utils::fake_data;
216
217 use super::*;
218
219 #[tokio::test]
220 async fn test_get_current_epoch() {
221 let time_point = TimePoint::dummy();
222 let fake_observer = FakeChainObserver::new(Some(time_point.clone()));
223 let current_epoch = fake_observer.get_current_epoch().await.unwrap();
224
225 assert_eq!(Some(time_point.epoch), current_epoch);
226 }
227
228 #[tokio::test]
229 async fn test_get_current_chain_point() {
230 let fake_observer = FakeChainObserver::new(None);
231 fake_observer.set_current_time_point(Some(TimePoint::dummy())).await;
232 let chain_point = fake_observer.get_current_chain_point().await.unwrap();
233
234 assert_eq!(
235 Some(TimePoint::dummy().chain_point),
236 chain_point,
237 "get current chain point should not fail"
238 );
239 }
240
241 #[tokio::test]
242 async fn test_get_current_stake_distribution() {
243 let fake_observer = FakeChainObserver::new(None);
244 fake_observer.set_signers(fake_data::signers_with_stakes(2)).await;
245 let stake_distribution = fake_observer.get_current_stake_distribution().await;
246
247 assert_eq!(
248 2,
249 stake_distribution.unwrap().unwrap().len(),
250 "get current stake distribution should not fail and should not be empty"
251 );
252 }
253
254 #[tokio::test]
255 async fn test_get_current_datums() {
256 let fake_address = "addr_test_123456".to_string();
257 let fake_datums =
258 vec![TxDatum("tx_datum_1".to_string()), TxDatum("tx_datum_2".to_string())];
259 let fake_observer = FakeChainObserver::new(None);
260 fake_observer.set_datums(fake_datums.clone()).await;
261 let datums = fake_observer
262 .get_current_datums(&fake_address)
263 .await
264 .expect("get_current_datums should not fail");
265
266 assert_eq!(fake_datums, datums);
267 }
268
269 #[tokio::test]
270 async fn test_increase_block_number() {
271 let fake_observer = FakeChainObserver::new(None);
272 fake_observer.set_current_time_point(Some(TimePoint::dummy())).await;
273 fake_observer.increase_block_number(375).await;
274
275 let chain_point = fake_observer.get_current_chain_point().await.unwrap();
276 assert_eq!(
277 Some(ChainPoint {
278 block_number: TimePoint::dummy().chain_point.block_number + 375,
279 ..TimePoint::dummy().chain_point
280 }),
281 chain_point,
282 "get current chain point should not fail"
283 );
284 }
285
286 #[tokio::test]
287 async fn test_decrease_block_number() {
288 let fake_observer = FakeChainObserver::new(None);
289 fake_observer
290 .set_current_time_point(Some(TimePoint {
291 chain_point: ChainPoint {
292 block_number: BlockNumber(1000),
293 ..TimePoint::dummy().chain_point
294 },
295 ..TimePoint::dummy()
296 }))
297 .await;
298 fake_observer.decrease_block_number(800).await;
299
300 let chain_point = fake_observer.get_current_chain_point().await.unwrap();
301 assert_eq!(
302 Some(ChainPoint {
303 block_number: BlockNumber(200),
304 ..TimePoint::dummy().chain_point
305 }),
306 chain_point,
307 "get current chain point should not fail"
308 );
309 }
310
311 #[tokio::test]
312 async fn test_increase_slot_number() {
313 let fake_observer = FakeChainObserver::new(None);
314 fake_observer.set_current_time_point(Some(TimePoint::dummy())).await;
315 fake_observer.increase_slot_number(375).await;
316
317 let chain_point = fake_observer.get_current_chain_point().await.unwrap();
318 assert_eq!(
319 Some(ChainPoint {
320 slot_number: TimePoint::dummy().chain_point.slot_number + 375,
321 ..TimePoint::dummy().chain_point
322 }),
323 chain_point,
324 "get current chain point should not fail"
325 );
326 }
327
328 #[tokio::test]
329 async fn test_decrease_slot_number() {
330 let fake_observer = FakeChainObserver::new(None);
331 fake_observer
332 .set_current_time_point(Some(TimePoint {
333 chain_point: ChainPoint {
334 slot_number: SlotNumber(1000),
335 ..TimePoint::dummy().chain_point
336 },
337 ..TimePoint::dummy()
338 }))
339 .await;
340 fake_observer.decrease_slot_number(800).await;
341
342 let chain_point = fake_observer.get_current_chain_point().await.unwrap();
343 assert_eq!(
344 Some(ChainPoint {
345 slot_number: SlotNumber(200),
346 ..TimePoint::dummy().chain_point
347 }),
348 chain_point,
349 "get current chain point should not fail"
350 );
351 }
352
353 #[tokio::test]
354 async fn test_get_current_era() {
355 let fake_observer = FakeChainObserver::new(None);
356
357 let current_era = fake_observer
358 .get_current_era()
359 .await
360 .expect("get_current_era should not fail");
361 assert_ne!(Some("Conway".to_string()), current_era);
362
363 fake_observer.set_current_era("Conway".to_string()).await;
364 let current_era = fake_observer
365 .get_current_era()
366 .await
367 .expect("get_current_era should not fail");
368 assert_eq!(Some("Conway".to_string()), current_era);
369 }
370}