1use std::{
2 cmp::Ordering,
3 fmt::{Display, Formatter, Result},
4 ops::{Deref, Range, RangeInclusive},
5};
6
7use anyhow::anyhow;
8use serde::{Deserialize, Serialize};
9
10use crate::{
11 StdResult,
12 crypto_helper::{MKMapKey, MKTreeNode},
13 entities::BlockNumber,
14};
15
16pub type BlockRangeLength = BlockNumber;
18
19#[derive(Serialize, Deserialize, Clone, Eq, PartialEq, Debug, Hash)]
21pub struct BlockRange {
22 inner_range: Range<BlockNumber>,
23}
24
25impl BlockRange {
26 pub const LENGTH: BlockRangeLength = BlockNumber(15);
29
30 pub fn start(number: BlockNumber) -> BlockNumber {
32 Self::start_with_length(number, Self::LENGTH)
33 }
34
35 pub fn all_block_ranges_in(interval: RangeInclusive<BlockNumber>) -> BlockRangesSequence {
37 BlockRangesSequence::new(interval)
38 }
39
40 pub fn from_block_number(number: BlockNumber) -> Self {
42 Self::from_block_number_and_length(number, Self::LENGTH).unwrap()
44 }
45
46 pub(crate) fn from_block_number_and_length(
48 number: BlockNumber,
49 length: BlockRangeLength,
50 ) -> StdResult<Self> {
51 if length == 0 {
52 return Err(anyhow!(
53 "BlockRange cannot be be computed with a length of 0"
54 ));
55 }
56 let block_range_start = Self::start_with_length(number, length);
57 let block_range_end = block_range_start + length;
58 Ok(Self::from(*block_range_start..*block_range_end))
59 }
60
61 fn start_with_length(number: BlockNumber, length: BlockRangeLength) -> BlockNumber {
63 (number / length) * length
66 }
67}
68
69impl Display for BlockRange {
70 fn fmt(&self, f: &mut Formatter) -> Result {
71 write!(f, "[{},{}[", self.inner_range.start, self.inner_range.end)
72 }
73}
74
75impl Deref for BlockRange {
76 type Target = Range<BlockNumber>;
77
78 fn deref(&self) -> &Self::Target {
79 &self.inner_range
80 }
81}
82
83impl PartialOrd for BlockRange {
84 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
85 Some(std::cmp::Ord::cmp(self, other))
86 }
87}
88
89impl Ord for BlockRange {
90 fn cmp(&self, other: &Self) -> Ordering {
91 match self.inner_range.start.cmp(&other.inner_range.start) {
93 Ordering::Equal => self.inner_range.end.cmp(&other.inner_range.end),
94 order => order,
95 }
96 }
97}
98
99impl From<Range<u64>> for BlockRange {
100 fn from(other: Range<u64>) -> Self {
101 BlockRange {
102 inner_range: BlockNumber(other.start)..BlockNumber(other.end),
103 }
104 }
105}
106
107impl From<BlockRange> for MKTreeNode {
108 fn from(other: BlockRange) -> Self {
109 let start = other.start.to_string();
110 let end = other.end.to_string();
111 let mut bytes = vec![];
112 bytes.extend_from_slice(start.as_bytes());
113 bytes.extend_from_slice("-".as_bytes());
114 bytes.extend_from_slice(end.as_bytes());
115 MKTreeNode::new(bytes)
116 }
117}
118
119impl MKMapKey for BlockRange {}
120
121#[derive(Debug, Clone, Eq, PartialEq)]
126pub struct BlockRangesSequence {
127 start: BlockNumber,
128 end: BlockNumber,
129}
130
131impl BlockRangesSequence {
132 pub fn new(interval: RangeInclusive<BlockNumber>) -> Self {
136 let start = if (*interval.start() % BlockRange::LENGTH) == 0 {
137 *interval.start()
138 } else {
139 BlockRange::start(*interval.start()) + BlockRange::LENGTH
140 };
141 let end = BlockRange::start(*interval.end() + 1);
143
144 if start >= end {
145 Self {
146 start: BlockNumber(0),
147 end: BlockNumber(0),
148 }
149 } else {
150 Self { start, end }
151 }
152 }
153
154 pub fn start(&self) -> BlockNumber {
156 self.start
157 }
158
159 pub fn end(&self) -> BlockNumber {
161 self.end
162 }
163
164 pub fn contains(&self, range: &Range<BlockNumber>) -> bool {
166 self.start <= range.start && range.end <= self.end
167 }
168
169 pub fn is_empty(&self) -> bool {
171 self.start >= self.end
172 }
173
174 pub fn into_vec(self) -> Vec<BlockRange> {
176 self.into_iter().collect()
177 }
178}
179
180impl Iterator for BlockRangesSequence {
181 type Item = BlockRange;
182
183 fn next(&mut self) -> Option<Self::Item> {
184 if BlockRangesSequence::is_empty(self) {
185 return None;
186 }
187
188 let block_range = BlockRange::from_block_number(self.start);
189 self.start = block_range.end;
190 Some(block_range)
191 }
192
193 fn size_hint(&self) -> (usize, Option<usize>) {
194 (*self.start as usize, Some(*self.end as usize))
195 }
196}
197
198impl ExactSizeIterator for BlockRangesSequence {
199 fn len(&self) -> usize {
200 *((self.end - self.start) / BlockRange::LENGTH) as usize
201 }
202}
203
204#[cfg(any(test, feature = "test_tools"))]
205mod test_extensions {
206 use crate::test::entities_extensions::BlockRangeTestExtension;
207
208 use super::*;
209
210 impl BlockRangeTestExtension for BlockRange {
211 fn new(start: u64, end: u64) -> Self {
212 Self {
213 inner_range: BlockNumber(start)..BlockNumber(end),
214 }
215 }
216
217 fn try_add(&self, other: &BlockRange) -> StdResult<BlockRange> {
218 if self.inner_range.end.max(other.inner_range.end)
219 < self.inner_range.start.min(other.inner_range.start)
220 {
221 return Err(anyhow!(
222 "BlockRange cannot be added as they don't strictly overlap"
223 ));
224 }
225
226 Ok(Self {
227 inner_range: Range {
228 start: self.inner_range.start.min(other.inner_range.start),
229 end: self.inner_range.end.max(other.inner_range.end),
230 },
231 })
232 }
233 }
234}
235
236#[cfg(test)]
237mod tests {
238 use std::ops::Not;
239
240 use crate::test::entities_extensions::BlockRangeTestExtension;
241
242 use super::*;
243
244 #[test]
245 fn test_block_range_contains() {
246 let block_range = BlockRange::new(1, 10);
247
248 assert!(block_range.contains(&BlockNumber(1)));
249 assert!(block_range.contains(&BlockNumber(6)));
250 assert!(block_range.contains(&BlockNumber(9)));
251
252 assert!(block_range.contains(&BlockNumber(0)).not());
253 assert!(block_range.contains(&BlockNumber(10)).not());
255 }
256
257 #[test]
258 fn test_block_range_cmp() {
259 assert_eq!(BlockRange::new(1, 10), BlockRange::new(1, 10));
260 assert_ne!(BlockRange::new(1, 10), BlockRange::new(1, 11));
261 assert_ne!(BlockRange::new(1, 10), BlockRange::new(2, 10));
262 assert_ne!(BlockRange::new(1, 11), BlockRange::new(2, 10));
263
264 assert!(BlockRange::new(1, 10) < BlockRange::new(1, 11));
265 assert!(BlockRange::new(1, 10) < BlockRange::new(2, 10));
266 assert!(BlockRange::new(1, 11) < BlockRange::new(2, 10));
267 }
268
269 #[test]
270 fn test_block_range_try_add() {
271 assert_eq!(
272 BlockRange::new(1, 10).try_add(&BlockRange::new(1, 10)).unwrap(),
273 BlockRange::new(1, 10)
274 );
275 assert_eq!(
276 BlockRange::new(1, 10).try_add(&BlockRange::new(1, 11)).unwrap(),
277 BlockRange::new(1, 11)
278 );
279 assert_eq!(
280 BlockRange::new(1, 10).try_add(&BlockRange::new(2, 10)).unwrap(),
281 BlockRange::new(1, 10)
282 );
283 }
284
285 #[test]
286 fn test_block_range_start() {
287 assert_eq!(BlockRange::start(BlockNumber(0)), 0);
288 assert_eq!(BlockRange::start(BlockNumber(1)), 0);
289 assert_eq!(BlockRange::start(BlockNumber(14)), 0);
290 assert_eq!(BlockRange::start(BlockNumber(15)), 15);
291 assert_eq!(BlockRange::start(BlockNumber(16)), 15);
292 assert_eq!(BlockRange::start(BlockNumber(29)), 15);
293 }
294
295 #[test]
296 fn test_block_range_all_block_ranges_in() {
297 assert_eq!(
298 BlockRange::all_block_ranges_in(BlockNumber(0)..=BlockNumber(0)).into_vec(),
299 vec![]
300 );
301 assert_eq!(
302 BlockRange::all_block_ranges_in(BlockNumber(0)..=BlockNumber(1)).into_vec(),
303 vec![]
304 );
305 assert_eq!(
306 BlockRange::all_block_ranges_in(BlockNumber(0)..=BlockNumber(13)).into_vec(),
307 vec![]
308 );
309 assert_eq!(
310 BlockRange::all_block_ranges_in(BlockNumber(1)..=BlockNumber(14)).into_vec(),
311 vec![]
312 );
313 assert_eq!(
314 BlockRange::all_block_ranges_in(BlockNumber(0)..=BlockNumber(14)).into_vec(),
315 vec![BlockRange::new(0, 15)]
316 );
317 assert_eq!(
318 BlockRange::all_block_ranges_in(BlockNumber(0)..=BlockNumber(15)).into_vec(),
319 vec![BlockRange::new(0, 15)]
320 );
321 assert_eq!(
322 BlockRange::all_block_ranges_in(BlockNumber(14)..=BlockNumber(29)).into_vec(),
323 vec![BlockRange::new(15, 30)]
324 );
325 assert_eq!(
326 BlockRange::all_block_ranges_in(BlockNumber(14)..=BlockNumber(30)).into_vec(),
327 vec![BlockRange::new(15, 30)]
328 );
329 assert_eq!(
330 BlockRange::all_block_ranges_in(BlockNumber(14)..=BlockNumber(60)).into_vec(),
331 vec![
332 BlockRange::new(15, 30),
333 BlockRange::new(30, 45),
334 BlockRange::new(45, 60)
335 ]
336 );
337 }
338
339 #[test]
340 fn test_block_ranges_sequence_is_empty() {
341 assert!(BlockRange::all_block_ranges_in(BlockNumber(0)..=BlockNumber(0)).is_empty());
342 assert!(BlockRange::all_block_ranges_in(BlockNumber(0)..=BlockNumber(1)).is_empty());
343 assert!(BlockRange::all_block_ranges_in(BlockNumber(0)..=BlockNumber(13)).is_empty());
344 assert!(BlockRange::all_block_ranges_in(BlockNumber(1)..=BlockNumber(14)).is_empty());
345 assert!(
346 BlockRange::all_block_ranges_in(BlockNumber(0)..=BlockNumber(14))
347 .is_empty()
348 .not()
349 );
350 assert!(
351 BlockRange::all_block_ranges_in(BlockNumber(0)..=BlockNumber(15))
352 .is_empty()
353 .not()
354 );
355 assert!(
356 BlockRange::all_block_ranges_in(BlockNumber(14)..=BlockNumber(29))
357 .is_empty()
358 .not()
359 );
360 assert!(
361 BlockRange::all_block_ranges_in(BlockNumber(14)..=BlockNumber(30))
362 .is_empty()
363 .not()
364 );
365 assert!(
366 BlockRange::all_block_ranges_in(BlockNumber(14)..=BlockNumber(60))
367 .is_empty()
368 .not()
369 );
370 }
371
372 #[test]
373 fn test_block_ranges_sequence_len() {
374 assert_eq!(
375 BlockRange::all_block_ranges_in(BlockNumber(0)..=(BlockRange::LENGTH - 2)).len(),
376 0
377 );
378 assert_eq!(
379 BlockRange::all_block_ranges_in(BlockNumber(0)..=(BlockRange::LENGTH - 1)).len(),
380 1
381 );
382 assert_eq!(
383 BlockRange::all_block_ranges_in(BlockNumber(0)..=(BlockRange::LENGTH * 15)).len(),
384 15
385 );
386 }
387
388 #[test]
389 fn test_block_ranges_sequence_contains() {
390 let block_range = BlockRange::new(15, 30);
391 assert!(
392 BlockRange::all_block_ranges_in(BlockNumber(0)..=BlockNumber(14))
393 .contains(&block_range)
394 .not()
395 );
396 assert!(
397 BlockRange::all_block_ranges_in(BlockNumber(30)..=BlockNumber(59))
398 .contains(&block_range)
399 .not()
400 );
401 assert!(
402 BlockRange::all_block_ranges_in(BlockNumber(0)..=BlockNumber(29))
403 .contains(&block_range)
404 );
405 assert!(
406 BlockRange::all_block_ranges_in(BlockNumber(15)..=BlockNumber(29))
407 .contains(&block_range)
408 );
409 assert!(
410 BlockRange::all_block_ranges_in(BlockNumber(15)..=BlockNumber(44))
411 .contains(&block_range)
412 );
413 }
414
415 #[test]
416 fn test_block_range_from_number() {
417 assert_eq!(
418 BlockRange::from_block_number(BlockNumber(0)),
419 BlockRange::new(0, 15)
420 );
421 assert_eq!(
422 BlockRange::from_block_number(BlockNumber(1)),
423 BlockRange::new(0, 15)
424 );
425 assert_eq!(
426 BlockRange::from_block_number(BlockNumber(14)),
427 BlockRange::new(0, 15)
428 );
429 assert_eq!(
430 BlockRange::from_block_number(BlockNumber(15)),
431 BlockRange::new(15, 30)
432 );
433 assert_eq!(
434 BlockRange::from_block_number(BlockNumber(16)),
435 BlockRange::new(15, 30)
436 );
437 assert_eq!(
438 BlockRange::from_block_number(BlockNumber(29)),
439 BlockRange::new(15, 30)
440 );
441 }
442
443 #[test]
444 fn test_block_range_from_number_and_length_with_valid_input() {
445 assert_eq!(
446 BlockRange::from_block_number_and_length(BlockNumber(0), BlockNumber(10)).unwrap(),
447 BlockRange::new(0, 10)
448 );
449 assert_eq!(
450 BlockRange::from_block_number_and_length(BlockNumber(1), BlockNumber(10)).unwrap(),
451 BlockRange::new(0, 10)
452 );
453 assert_eq!(
454 BlockRange::from_block_number_and_length(BlockNumber(9), BlockNumber(10)).unwrap(),
455 BlockRange::new(0, 10)
456 );
457 assert_eq!(
458 BlockRange::from_block_number_and_length(BlockNumber(10), BlockNumber(10)).unwrap(),
459 BlockRange::new(10, 20)
460 );
461 assert_eq!(
462 BlockRange::from_block_number_and_length(BlockNumber(11), BlockNumber(10)).unwrap(),
463 BlockRange::new(10, 20)
464 );
465 assert_eq!(
466 BlockRange::from_block_number_and_length(BlockNumber(19), BlockNumber(10)).unwrap(),
467 BlockRange::new(10, 20)
468 );
469 }
470
471 #[test]
472 fn test_block_range_from_number_and_length_with_invalid_input() {
473 BlockRange::from_block_number_and_length(BlockNumber(10), BlockNumber(0))
474 .expect_err("BlockRange should not be computed with a length of 0");
475 }
476
477 #[test]
478 #[allow(clippy::reversed_empty_ranges)]
480 fn test_building_sequence_with_start_greater_than_end_yield_empty_iterator() {
481 let sequence = BlockRange::all_block_ranges_in(BlockNumber(30)..=BlockNumber(15));
482 assert_eq!(sequence.clone().into_vec(), vec![]);
483 assert!(sequence.is_empty());
484 }
485}