snarkos_node_bft/helpers/
ready.rs1use snarkvm::{
17 console::prelude::*,
18 ledger::{
19 block::Transaction,
20 narwhal::{Data, Transmission, TransmissionID},
21 puzzle::{Solution, SolutionID},
22 },
23};
24
25use indexmap::{IndexMap, IndexSet};
26use std::collections::{HashMap, VecDeque, hash_map::Entry::Vacant};
27
28#[derive(Clone, Debug)]
30pub struct Ready<N: Network> {
31 transmission_ids: HashMap<TransmissionID<N>, i64>,
34 transmissions: VecDeque<(TransmissionID<N>, Transmission<N>)>,
36 offset: i64,
39}
40
41impl<N: Network> Default for Ready<N> {
42 fn default() -> Self {
44 Self::new()
45 }
46}
47
48impl<N: Network> Ready<N> {
49 pub fn new() -> Self {
51 Self { transmission_ids: Default::default(), transmissions: Default::default(), offset: Default::default() }
52 }
53
54 pub fn is_empty(&self) -> bool {
56 self.transmissions.is_empty()
57 }
58
59 pub fn num_transmissions(&self) -> usize {
61 self.transmissions.len()
62 }
63
64 pub fn num_ratifications(&self) -> usize {
66 self.transmission_ids.keys().filter(|id| matches!(id, TransmissionID::Ratification)).count()
67 }
68
69 pub fn num_solutions(&self) -> usize {
71 self.transmission_ids.keys().filter(|id| matches!(id, TransmissionID::Solution(..))).count()
72 }
73
74 pub fn num_transactions(&self) -> usize {
76 self.transmission_ids.keys().filter(|id| matches!(id, TransmissionID::Transaction(..))).count()
77 }
78
79 pub fn transmission_ids(&self) -> IndexSet<TransmissionID<N>> {
81 self.transmission_ids.keys().copied().collect()
82 }
83
84 pub fn transmissions(&self) -> IndexMap<TransmissionID<N>, Transmission<N>> {
86 self.transmissions.iter().cloned().collect()
87 }
88
89 pub fn solutions(&self) -> Vec<(SolutionID<N>, Data<Solution<N>>)> {
91 self.transmissions
92 .iter()
93 .filter_map(|(id, transmission)| match (id, transmission) {
94 (TransmissionID::Solution(id, _), Transmission::Solution(solution)) => Some((*id, solution.clone())),
95 _ => None,
96 })
97 .collect()
98 }
99
100 pub fn transactions(&self) -> Vec<(N::TransactionID, Data<Transaction<N>>)> {
102 self.transmissions
103 .iter()
104 .filter_map(|(id, transmission)| match (id, transmission) {
105 (TransmissionID::Transaction(id, _), Transmission::Transaction(tx)) => Some((*id, tx.clone())),
106 _ => None,
107 })
108 .collect()
109 }
110}
111
112impl<N: Network> Ready<N> {
113 pub fn contains(&self, transmission_id: impl Into<TransmissionID<N>>) -> bool {
115 self.transmission_ids.contains_key(&transmission_id.into())
116 }
117
118 pub fn get(&self, transmission_id: impl Into<TransmissionID<N>>) -> Option<Transmission<N>> {
120 self.transmission_ids
121 .get(&transmission_id.into())
122 .and_then(|&index| self.transmissions.get((index - self.offset) as usize))
123 .map(|(_, transmission)| transmission.clone())
124 }
125
126 pub fn insert(&mut self, transmission_id: impl Into<TransmissionID<N>>, transmission: Transmission<N>) -> bool {
129 let physical_index = self.transmissions.len();
130 let transmission_id = transmission_id.into();
131
132 if let Vacant(entry) = self.transmission_ids.entry(transmission_id) {
133 entry.insert(physical_index as i64 + self.offset);
134 self.transmissions.push_back((transmission_id, transmission));
135 true
136 } else {
137 false
138 }
139 }
140
141 pub fn insert_front(
145 &mut self,
146 transmission_id: impl Into<TransmissionID<N>>,
147 transmission: Transmission<N>,
148 ) -> bool {
149 let transmission_id = transmission_id.into();
150 if let Vacant(entry) = self.transmission_ids.entry(transmission_id) {
151 self.offset -= 1;
152 let index = self.offset;
153
154 entry.insert(index);
155 self.transmissions.push_front((transmission_id, transmission));
156 true
157 } else {
158 false
159 }
160 }
161
162 pub fn remove_front(&mut self) -> Option<(TransmissionID<N>, Transmission<N>)> {
164 if let Some((transmission_id, transmission)) = self.transmissions.pop_front() {
165 self.transmission_ids.remove(&transmission_id);
166
167 if self.transmission_ids.is_empty() {
168 debug_assert!(self.transmissions.is_empty());
169 self.offset = 0;
170 } else {
171 self.offset += 1;
172 }
173
174 Some((transmission_id, transmission))
175 } else {
176 None
177 }
178 }
179
180 pub fn clear_solutions(&mut self) {
182 self.transmissions.retain(|(_, transmission)| !matches!(transmission, Transmission::Solution(_)));
183
184 self.transmission_ids.clear();
186 self.offset = 0;
187 for (i, (id, _)) in self.transmissions.iter().enumerate() {
188 self.transmission_ids.insert(*id, i as i64);
189 }
190 }
191}
192
193#[cfg(test)]
194mod tests {
195 use super::*;
196 use snarkvm::{ledger::narwhal::Data, prelude::Field};
197
198 use ::bytes::Bytes;
199
200 type CurrentNetwork = snarkvm::prelude::MainnetV0;
201
202 #[test]
203 fn test_ready() {
204 let rng = &mut TestRng::default();
205
206 let data =
208 |rng: &mut TestRng| Data::Buffer(Bytes::from((0..512).map(|_| rng.r#gen::<u8>()).collect::<Vec<_>>()));
209
210 let mut ready = Ready::<CurrentNetwork>::new();
212
213 let solution_id_1 = TransmissionID::Solution(
215 rng.r#gen::<u64>().into(),
216 rng.r#gen::<<CurrentNetwork as Network>::TransmissionChecksum>(),
217 );
218 let solution_id_2 = TransmissionID::Solution(
219 rng.r#gen::<u64>().into(),
220 rng.r#gen::<<CurrentNetwork as Network>::TransmissionChecksum>(),
221 );
222 let solution_id_3 = TransmissionID::Solution(
223 rng.r#gen::<u64>().into(),
224 rng.r#gen::<<CurrentNetwork as Network>::TransmissionChecksum>(),
225 );
226
227 let solution_1 = Transmission::Solution(data(rng));
229 let solution_2 = Transmission::Solution(data(rng));
230 let solution_3 = Transmission::Solution(data(rng));
231
232 assert!(ready.insert(solution_id_1, solution_1.clone()));
234 assert!(ready.insert(solution_id_2, solution_2.clone()));
235 assert!(ready.insert(solution_id_3, solution_3.clone()));
236
237 assert_eq!(ready.num_transmissions(), 3);
239
240 let transmission_ids = vec![solution_id_1, solution_id_2, solution_id_3].into_iter().collect::<IndexSet<_>>();
242 assert_eq!(ready.transmission_ids(), transmission_ids);
243 transmission_ids.iter().for_each(|id| assert!(ready.contains(*id)));
244
245 let solution_id_unknown = TransmissionID::Solution(
247 rng.r#gen::<u64>().into(),
248 rng.r#gen::<<CurrentNetwork as Network>::TransmissionChecksum>(),
249 );
250 assert!(!ready.contains(solution_id_unknown));
251
252 assert_eq!(ready.get(solution_id_1), Some(solution_1.clone()));
254 assert_eq!(ready.get(solution_id_2), Some(solution_2.clone()));
255 assert_eq!(ready.get(solution_id_3), Some(solution_3.clone()));
256 assert_eq!(ready.get(solution_id_unknown), None);
257
258 let mut transmissions = Vec::with_capacity(3);
260 for _ in 0..3 {
261 transmissions.push(ready.remove_front().unwrap())
262 }
263
264 assert!(ready.is_empty());
266 assert_eq!(ready.transmission_ids(), IndexSet::new());
268 assert_eq!(transmissions, vec![
270 (solution_id_1, solution_1),
271 (solution_id_2, solution_2),
272 (solution_id_3, solution_3)
273 ]);
274 }
275
276 #[test]
277 fn test_ready_duplicate() {
278 use rand::RngCore;
279 let rng = &mut TestRng::default();
280
281 let mut vec = vec![0u8; 512];
283 rng.fill_bytes(&mut vec);
284 let data = Data::Buffer(Bytes::from(vec));
285
286 let mut ready = Ready::<CurrentNetwork>::new();
288
289 let solution_id = TransmissionID::Solution(
291 rng.r#gen::<u64>().into(),
292 rng.r#gen::<<CurrentNetwork as Network>::TransmissionChecksum>(),
293 );
294
295 let solution = Transmission::Solution(data);
297
298 assert!(ready.insert(solution_id, solution.clone()));
300 assert!(!ready.insert(solution_id, solution));
301
302 assert_eq!(ready.num_transmissions(), 1);
304 }
305
306 #[test]
307 fn test_insert_front() {
308 let rng = &mut TestRng::default();
309 let data =
310 |rng: &mut TestRng| Data::Buffer(Bytes::from((0..512).map(|_| rng.r#gen::<u8>()).collect::<Vec<_>>()));
311
312 let mut ready = Ready::<CurrentNetwork>::new();
314
315 let solution_id_1 = TransmissionID::Solution(
317 rng.r#gen::<u64>().into(),
318 rng.r#gen::<<CurrentNetwork as Network>::TransmissionChecksum>(),
319 );
320 let solution_id_2 = TransmissionID::Solution(
321 rng.r#gen::<u64>().into(),
322 rng.r#gen::<<CurrentNetwork as Network>::TransmissionChecksum>(),
323 );
324
325 let solution_1 = Transmission::Solution(data(rng));
327 let solution_2 = Transmission::Solution(data(rng));
328
329 assert!(ready.insert_front(solution_id_1, solution_1.clone()));
331 assert_eq!(ready.offset, -1);
332 assert!(ready.insert_front(solution_id_2, solution_2.clone()));
333 assert_eq!(ready.offset, -2);
334
335 assert_eq!(ready.get(solution_id_1), Some(solution_1.clone()));
337 assert_eq!(ready.get(solution_id_2), Some(solution_2.clone()));
338
339 let removed_solution = ready.remove_front().unwrap();
341 assert_eq!(removed_solution, (solution_id_2, solution_2));
342 assert_eq!(ready.offset, -1);
343
344 let removed_solution = ready.remove_front().unwrap();
346 assert_eq!(removed_solution, (solution_id_1, solution_1));
347 assert_eq!(ready.offset, 0);
348 }
349
350 #[test]
351 fn test_clear_solutions() {
352 let rng = &mut TestRng::default();
353 let solution_data =
354 |rng: &mut TestRng| Data::Buffer(Bytes::from((0..512).map(|_| rng.r#gen::<u8>()).collect::<Vec<_>>()));
355 let transaction_data =
356 |rng: &mut TestRng| Data::Buffer(Bytes::from((0..512).map(|_| rng.r#gen::<u8>()).collect::<Vec<_>>()));
357
358 let mut ready = Ready::<CurrentNetwork>::new();
360
361 let solution_id_1 = TransmissionID::Solution(
363 rng.r#gen::<u64>().into(),
364 rng.r#gen::<<CurrentNetwork as Network>::TransmissionChecksum>(),
365 );
366 let solution_id_2 = TransmissionID::Solution(
367 rng.r#gen::<u64>().into(),
368 rng.r#gen::<<CurrentNetwork as Network>::TransmissionChecksum>(),
369 );
370 let transaction_id = TransmissionID::Transaction(
371 <CurrentNetwork as Network>::TransactionID::from(Field::rand(rng)),
372 <CurrentNetwork as Network>::TransmissionChecksum::from(rng.r#gen::<u128>()),
373 );
374
375 let solution_1 = Transmission::Solution(solution_data(rng));
377 let solution_2 = Transmission::Solution(solution_data(rng));
378 let transaction = Transmission::Transaction(transaction_data(rng));
379
380 assert!(ready.insert_front(solution_id_1, solution_1.clone()));
382 assert_eq!(ready.offset, -1);
383
384 assert!(ready.insert(transaction_id, transaction.clone()));
386 assert_eq!(ready.offset, -1);
387 assert!(ready.insert(solution_id_2, solution_2.clone()));
388 assert_eq!(ready.offset, -1);
389
390 ready.clear_solutions();
392 assert_eq!(ready.num_transmissions(), 1);
394 assert_eq!(ready.offset, 0);
396 assert_eq!(ready.get(transaction_id), Some(transaction));
398 }
399}