mithril_cardano_node_chain/test/double/
chain_observer.rs1use async_trait::async_trait;
2use tokio::sync::RwLock;
3
4use mithril_common::crypto_helper::KesPeriod;
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(&self) -> Result<Option<KesPeriod>, ChainObserverError> {
206 Ok(Some(0))
207 }
208}
209
210#[cfg(test)]
211mod tests {
212 use mithril_common::test::double::{Dummy, fake_data};
213
214 use super::*;
215
216 #[tokio::test]
217 async fn test_get_current_epoch() {
218 let time_point = TimePoint::dummy();
219 let fake_observer = FakeChainObserver::new(Some(time_point.clone()));
220 let current_epoch = fake_observer.get_current_epoch().await.unwrap();
221
222 assert_eq!(Some(time_point.epoch), current_epoch);
223 }
224
225 #[tokio::test]
226 async fn test_get_current_chain_point() {
227 let fake_observer = FakeChainObserver::new(None);
228 fake_observer.set_current_time_point(Some(TimePoint::dummy())).await;
229 let chain_point = fake_observer.get_current_chain_point().await.unwrap();
230
231 assert_eq!(
232 Some(TimePoint::dummy().chain_point),
233 chain_point,
234 "get current chain point should not fail"
235 );
236 }
237
238 #[tokio::test]
239 async fn test_get_current_stake_distribution() {
240 let fake_observer = FakeChainObserver::new(None);
241 fake_observer.set_signers(fake_data::signers_with_stakes(2)).await;
242 let stake_distribution = fake_observer.get_current_stake_distribution().await;
243
244 assert_eq!(
245 2,
246 stake_distribution.unwrap().unwrap().len(),
247 "get current stake distribution should not fail and should not be empty"
248 );
249 }
250
251 #[tokio::test]
252 async fn test_get_current_datums() {
253 let fake_address = "addr_test_123456".to_string();
254 let fake_datums =
255 vec![TxDatum("tx_datum_1".to_string()), TxDatum("tx_datum_2".to_string())];
256 let fake_observer = FakeChainObserver::new(None);
257 fake_observer.set_datums(fake_datums.clone()).await;
258 let datums = fake_observer
259 .get_current_datums(&fake_address)
260 .await
261 .expect("get_current_datums should not fail");
262
263 assert_eq!(fake_datums, datums);
264 }
265
266 #[tokio::test]
267 async fn test_increase_block_number() {
268 let fake_observer = FakeChainObserver::new(None);
269 fake_observer.set_current_time_point(Some(TimePoint::dummy())).await;
270 fake_observer.increase_block_number(375).await;
271
272 let chain_point = fake_observer.get_current_chain_point().await.unwrap();
273 assert_eq!(
274 Some(ChainPoint {
275 block_number: TimePoint::dummy().chain_point.block_number + 375,
276 ..TimePoint::dummy().chain_point
277 }),
278 chain_point,
279 "get current chain point should not fail"
280 );
281 }
282
283 #[tokio::test]
284 async fn test_decrease_block_number() {
285 let fake_observer = FakeChainObserver::new(None);
286 fake_observer
287 .set_current_time_point(Some(TimePoint {
288 chain_point: ChainPoint {
289 block_number: BlockNumber(1000),
290 ..TimePoint::dummy().chain_point
291 },
292 ..TimePoint::dummy()
293 }))
294 .await;
295 fake_observer.decrease_block_number(800).await;
296
297 let chain_point = fake_observer.get_current_chain_point().await.unwrap();
298 assert_eq!(
299 Some(ChainPoint {
300 block_number: BlockNumber(200),
301 ..TimePoint::dummy().chain_point
302 }),
303 chain_point,
304 "get current chain point should not fail"
305 );
306 }
307
308 #[tokio::test]
309 async fn test_increase_slot_number() {
310 let fake_observer = FakeChainObserver::new(None);
311 fake_observer.set_current_time_point(Some(TimePoint::dummy())).await;
312 fake_observer.increase_slot_number(375).await;
313
314 let chain_point = fake_observer.get_current_chain_point().await.unwrap();
315 assert_eq!(
316 Some(ChainPoint {
317 slot_number: TimePoint::dummy().chain_point.slot_number + 375,
318 ..TimePoint::dummy().chain_point
319 }),
320 chain_point,
321 "get current chain point should not fail"
322 );
323 }
324
325 #[tokio::test]
326 async fn test_decrease_slot_number() {
327 let fake_observer = FakeChainObserver::new(None);
328 fake_observer
329 .set_current_time_point(Some(TimePoint {
330 chain_point: ChainPoint {
331 slot_number: SlotNumber(1000),
332 ..TimePoint::dummy().chain_point
333 },
334 ..TimePoint::dummy()
335 }))
336 .await;
337 fake_observer.decrease_slot_number(800).await;
338
339 let chain_point = fake_observer.get_current_chain_point().await.unwrap();
340 assert_eq!(
341 Some(ChainPoint {
342 slot_number: SlotNumber(200),
343 ..TimePoint::dummy().chain_point
344 }),
345 chain_point,
346 "get current chain point should not fail"
347 );
348 }
349
350 #[tokio::test]
351 async fn test_get_current_era() {
352 let fake_observer = FakeChainObserver::new(None);
353
354 let current_era = fake_observer
355 .get_current_era()
356 .await
357 .expect("get_current_era should not fail");
358 assert_ne!(Some("Conway".to_string()), current_era);
359
360 fake_observer.set_current_era("Conway".to_string()).await;
361 let current_era = fake_observer
362 .get_current_era()
363 .await
364 .expect("get_current_era should not fail");
365 assert_eq!(Some("Conway".to_string()), current_era);
366 }
367}