zebra_chain/chain_tip/
mock.rs1use std::sync::Arc;
4
5use chrono::{DateTime, Utc};
6use futures::TryFutureExt;
7use tokio::sync::watch;
8
9use crate::{block, chain_tip::ChainTip, parameters::Network, transaction, BoxError};
10
11pub struct MockChainTipSender {
15 best_tip_height: watch::Sender<Option<block::Height>>,
17
18 best_tip_hash: watch::Sender<Option<block::Hash>>,
20
21 best_tip_block_time: watch::Sender<Option<DateTime<Utc>>>,
23
24 estimated_distance_to_network_chain_tip: watch::Sender<Option<block::HeightDiff>>,
26}
27
28#[derive(Clone, Debug)]
30pub struct MockChainTip {
31 best_tip_height: watch::Receiver<Option<block::Height>>,
33
34 best_tip_hash: watch::Receiver<Option<block::Hash>>,
36
37 best_tip_block_time: watch::Receiver<Option<DateTime<Utc>>>,
39
40 estimated_distance_to_network_chain_tip: watch::Receiver<Option<block::HeightDiff>>,
42}
43
44impl MockChainTip {
45 pub fn new() -> (Self, MockChainTipSender) {
52 let (height_sender, height_receiver) = watch::channel(None);
53 let (hash_sender, hash_receiver) = watch::channel(None);
54 let (time_sender, time_receiver) = watch::channel(None);
55 let (estimated_distance_to_tip_sender, estimated_distance_to_tip_receiver) =
56 watch::channel(None);
57
58 let mock_chain_tip = MockChainTip {
59 best_tip_height: height_receiver,
60 best_tip_hash: hash_receiver,
61 best_tip_block_time: time_receiver,
62 estimated_distance_to_network_chain_tip: estimated_distance_to_tip_receiver,
63 };
64
65 let mock_chain_tip_sender = MockChainTipSender {
66 best_tip_height: height_sender,
67 best_tip_hash: hash_sender,
68 best_tip_block_time: time_sender,
69 estimated_distance_to_network_chain_tip: estimated_distance_to_tip_sender,
70 };
71
72 (mock_chain_tip, mock_chain_tip_sender)
73 }
74}
75
76impl ChainTip for MockChainTip {
77 fn best_tip_height(&self) -> Option<block::Height> {
78 *self.best_tip_height.borrow()
79 }
80
81 fn best_tip_hash(&self) -> Option<block::Hash> {
82 *self.best_tip_hash.borrow()
83 }
84
85 fn best_tip_height_and_hash(&self) -> Option<(block::Height, block::Hash)> {
86 let height = (*self.best_tip_height.borrow())?;
87 let hash = (*self.best_tip_hash.borrow())?;
88
89 Some((height, hash))
90 }
91
92 fn best_tip_block_time(&self) -> Option<DateTime<Utc>> {
93 *self.best_tip_block_time.borrow()
94 }
95
96 fn best_tip_height_and_block_time(&self) -> Option<(block::Height, DateTime<Utc>)> {
97 let height = (*self.best_tip_height.borrow())?;
98 let block_time = (*self.best_tip_block_time.borrow())?;
99
100 Some((height, block_time))
101 }
102
103 fn best_tip_mined_transaction_ids(&self) -> Arc<[transaction::Hash]> {
104 Arc::new([])
105 }
106
107 fn estimate_distance_to_network_chain_tip(
108 &self,
109 _network: &Network,
110 ) -> Option<(block::HeightDiff, block::Height)> {
111 self.estimated_distance_to_network_chain_tip
112 .borrow()
113 .and_then(|estimated_distance| {
114 self.best_tip_height()
115 .map(|tip_height| (estimated_distance, tip_height))
116 })
117 }
118
119 async fn best_tip_changed(&mut self) -> Result<(), BoxError> {
126 tokio::select! {
130 result = self.best_tip_height.changed().err_into() => result.map(|_| ()),
131 result = self.best_tip_hash.changed().err_into() => result.map(|_| ()),
132 result = self.best_tip_block_time.changed().err_into() => result.map(|_| ()),
133 result = self.estimated_distance_to_network_chain_tip.changed().err_into() => result.map(|_| ()),
134 }
135 }
136
137 fn mark_best_tip_seen(&mut self) {
139 self.best_tip_height.borrow_and_update();
140 self.best_tip_hash.borrow_and_update();
141 self.best_tip_block_time.borrow_and_update();
142 self.estimated_distance_to_network_chain_tip
143 .borrow_and_update();
144 }
145}
146
147impl MockChainTipSender {
148 pub fn send_best_tip_height(&self, height: impl Into<Option<block::Height>>) {
150 self.best_tip_height
151 .send(height.into())
152 .expect("attempt to send a best tip height to a dropped `MockChainTip`");
153 }
154
155 pub fn send_best_tip_hash(&self, hash: impl Into<Option<block::Hash>>) {
157 self.best_tip_hash
158 .send(hash.into())
159 .expect("attempt to send a best tip hash to a dropped `MockChainTip`");
160 }
161
162 pub fn send_best_tip_block_time(&self, block_time: impl Into<Option<DateTime<Utc>>>) {
164 self.best_tip_block_time
165 .send(block_time.into())
166 .expect("attempt to send a best tip block time to a dropped `MockChainTip`");
167 }
168
169 pub fn send_estimated_distance_to_network_chain_tip(
171 &self,
172 distance: impl Into<Option<block::HeightDiff>>,
173 ) {
174 self.estimated_distance_to_network_chain_tip
175 .send(distance.into())
176 .expect("attempt to send a best tip height to a dropped `MockChainTip`");
177 }
178}