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<BlockRange> for Range<BlockNumber> {
100 fn from(value: BlockRange) -> Self {
101 value.inner_range
102 }
103}
104
105impl From<BlockRange> for Range<u64> {
106 fn from(value: BlockRange) -> Self {
107 *value.inner_range.start..*value.inner_range.end
108 }
109}
110
111impl From<Range<u64>> for BlockRange {
112 fn from(other: Range<u64>) -> Self {
113 BlockRange {
114 inner_range: BlockNumber(other.start)..BlockNumber(other.end),
115 }
116 }
117}
118
119impl From<BlockRange> for MKTreeNode {
120 fn from(other: BlockRange) -> Self {
121 let start = other.start.to_string();
122 let end = other.end.to_string();
123 let mut bytes = vec![];
124 bytes.extend_from_slice(start.as_bytes());
125 bytes.extend_from_slice("-".as_bytes());
126 bytes.extend_from_slice(end.as_bytes());
127 MKTreeNode::new(bytes)
128 }
129}
130
131impl MKMapKey for BlockRange {}
132
133#[derive(Debug, Clone, Eq, PartialEq)]
138pub struct BlockRangesSequence {
139 start: BlockNumber,
140 end: BlockNumber,
141}
142
143impl BlockRangesSequence {
144 pub fn new(interval: RangeInclusive<BlockNumber>) -> Self {
148 let start = if (*interval.start() % BlockRange::LENGTH) == 0 {
149 *interval.start()
150 } else {
151 BlockRange::start(*interval.start()) + BlockRange::LENGTH
152 };
153 let end = BlockRange::start(*interval.end() + 1);
155
156 if start >= end {
157 Self {
158 start: BlockNumber(0),
159 end: BlockNumber(0),
160 }
161 } else {
162 Self { start, end }
163 }
164 }
165
166 pub fn start(&self) -> BlockNumber {
168 self.start
169 }
170
171 pub fn end(&self) -> BlockNumber {
173 self.end
174 }
175
176 pub fn contains(&self, range: &Range<BlockNumber>) -> bool {
178 self.start <= range.start && range.end <= self.end
179 }
180
181 pub fn is_empty(&self) -> bool {
183 self.start >= self.end
184 }
185
186 pub fn into_vec(self) -> Vec<BlockRange> {
188 self.into_iter().collect()
189 }
190}
191
192impl Iterator for BlockRangesSequence {
193 type Item = BlockRange;
194
195 fn next(&mut self) -> Option<Self::Item> {
196 if BlockRangesSequence::is_empty(self) {
197 return None;
198 }
199
200 let block_range = BlockRange::from_block_number(self.start);
201 self.start = block_range.end;
202 Some(block_range)
203 }
204
205 fn size_hint(&self) -> (usize, Option<usize>) {
206 (*self.start as usize, Some(*self.end as usize))
207 }
208}
209
210impl ExactSizeIterator for BlockRangesSequence {
211 fn len(&self) -> usize {
212 *((self.end - self.start) / BlockRange::LENGTH) as usize
213 }
214}
215
216mod test_extensions {
217 use crate::test::entities_extensions::BlockRangeTestExtension;
218
219 use super::*;
220
221 impl BlockRangeTestExtension for BlockRange {
222 fn new(start: u64, end: u64) -> Self {
223 Self {
224 inner_range: BlockNumber(start)..BlockNumber(end),
225 }
226 }
227
228 fn try_add(&self, other: &BlockRange) -> StdResult<BlockRange> {
229 if self.inner_range.end.max(other.inner_range.end)
230 < self.inner_range.start.min(other.inner_range.start)
231 {
232 return Err(anyhow!(
233 "BlockRange cannot be added as they don't strictly overlap"
234 ));
235 }
236
237 Ok(Self {
238 inner_range: Range {
239 start: self.inner_range.start.min(other.inner_range.start),
240 end: self.inner_range.end.max(other.inner_range.end),
241 },
242 })
243 }
244 }
245}
246
247#[cfg(test)]
248mod tests {
249 use std::ops::Not;
250
251 use crate::test::entities_extensions::BlockRangeTestExtension;
252
253 use super::*;
254
255 #[test]
256 fn test_block_range_contains() {
257 let block_range = BlockRange::new(1, 10);
258
259 assert!(block_range.contains(&BlockNumber(1)));
260 assert!(block_range.contains(&BlockNumber(6)));
261 assert!(block_range.contains(&BlockNumber(9)));
262
263 assert!(block_range.contains(&BlockNumber(0)).not());
264 assert!(block_range.contains(&BlockNumber(10)).not());
266 }
267
268 #[test]
269 fn test_block_range_cmp() {
270 assert_eq!(BlockRange::new(1, 10), BlockRange::new(1, 10));
271 assert_ne!(BlockRange::new(1, 10), BlockRange::new(1, 11));
272 assert_ne!(BlockRange::new(1, 10), BlockRange::new(2, 10));
273 assert_ne!(BlockRange::new(1, 11), BlockRange::new(2, 10));
274
275 assert!(BlockRange::new(1, 10) < BlockRange::new(1, 11));
276 assert!(BlockRange::new(1, 10) < BlockRange::new(2, 10));
277 assert!(BlockRange::new(1, 11) < BlockRange::new(2, 10));
278 }
279
280 #[test]
281 fn test_block_range_try_add() {
282 assert_eq!(
283 BlockRange::new(1, 10).try_add(&BlockRange::new(1, 10)).unwrap(),
284 BlockRange::new(1, 10)
285 );
286 assert_eq!(
287 BlockRange::new(1, 10).try_add(&BlockRange::new(1, 11)).unwrap(),
288 BlockRange::new(1, 11)
289 );
290 assert_eq!(
291 BlockRange::new(1, 10).try_add(&BlockRange::new(2, 10)).unwrap(),
292 BlockRange::new(1, 10)
293 );
294 }
295
296 #[test]
297 fn test_block_range_start() {
298 assert_eq!(BlockRange::start(BlockNumber(0)), 0);
299 assert_eq!(BlockRange::start(BlockNumber(1)), 0);
300 assert_eq!(BlockRange::start(BlockNumber(14)), 0);
301 assert_eq!(BlockRange::start(BlockNumber(15)), 15);
302 assert_eq!(BlockRange::start(BlockNumber(16)), 15);
303 assert_eq!(BlockRange::start(BlockNumber(29)), 15);
304 }
305
306 #[test]
307 fn test_block_range_all_block_ranges_in() {
308 assert_eq!(
309 BlockRange::all_block_ranges_in(BlockNumber(0)..=BlockNumber(0)).into_vec(),
310 vec![]
311 );
312 assert_eq!(
313 BlockRange::all_block_ranges_in(BlockNumber(0)..=BlockNumber(1)).into_vec(),
314 vec![]
315 );
316 assert_eq!(
317 BlockRange::all_block_ranges_in(BlockNumber(0)..=BlockNumber(13)).into_vec(),
318 vec![]
319 );
320 assert_eq!(
321 BlockRange::all_block_ranges_in(BlockNumber(1)..=BlockNumber(14)).into_vec(),
322 vec![]
323 );
324 assert_eq!(
325 BlockRange::all_block_ranges_in(BlockNumber(0)..=BlockNumber(14)).into_vec(),
326 vec![BlockRange::new(0, 15)]
327 );
328 assert_eq!(
329 BlockRange::all_block_ranges_in(BlockNumber(0)..=BlockNumber(15)).into_vec(),
330 vec![BlockRange::new(0, 15)]
331 );
332 assert_eq!(
333 BlockRange::all_block_ranges_in(BlockNumber(14)..=BlockNumber(29)).into_vec(),
334 vec![BlockRange::new(15, 30)]
335 );
336 assert_eq!(
337 BlockRange::all_block_ranges_in(BlockNumber(14)..=BlockNumber(30)).into_vec(),
338 vec![BlockRange::new(15, 30)]
339 );
340 assert_eq!(
341 BlockRange::all_block_ranges_in(BlockNumber(14)..=BlockNumber(60)).into_vec(),
342 vec![
343 BlockRange::new(15, 30),
344 BlockRange::new(30, 45),
345 BlockRange::new(45, 60)
346 ]
347 );
348 }
349
350 #[test]
351 fn test_block_ranges_sequence_is_empty() {
352 assert!(BlockRange::all_block_ranges_in(BlockNumber(0)..=BlockNumber(0)).is_empty());
353 assert!(BlockRange::all_block_ranges_in(BlockNumber(0)..=BlockNumber(1)).is_empty());
354 assert!(BlockRange::all_block_ranges_in(BlockNumber(0)..=BlockNumber(13)).is_empty());
355 assert!(BlockRange::all_block_ranges_in(BlockNumber(1)..=BlockNumber(14)).is_empty());
356 assert!(
357 BlockRange::all_block_ranges_in(BlockNumber(0)..=BlockNumber(14))
358 .is_empty()
359 .not()
360 );
361 assert!(
362 BlockRange::all_block_ranges_in(BlockNumber(0)..=BlockNumber(15))
363 .is_empty()
364 .not()
365 );
366 assert!(
367 BlockRange::all_block_ranges_in(BlockNumber(14)..=BlockNumber(29))
368 .is_empty()
369 .not()
370 );
371 assert!(
372 BlockRange::all_block_ranges_in(BlockNumber(14)..=BlockNumber(30))
373 .is_empty()
374 .not()
375 );
376 assert!(
377 BlockRange::all_block_ranges_in(BlockNumber(14)..=BlockNumber(60))
378 .is_empty()
379 .not()
380 );
381 }
382
383 #[test]
384 fn test_block_ranges_sequence_len() {
385 assert_eq!(
386 BlockRange::all_block_ranges_in(BlockNumber(0)..=(BlockRange::LENGTH - 2)).len(),
387 0
388 );
389 assert_eq!(
390 BlockRange::all_block_ranges_in(BlockNumber(0)..=(BlockRange::LENGTH - 1)).len(),
391 1
392 );
393 assert_eq!(
394 BlockRange::all_block_ranges_in(BlockNumber(0)..=(BlockRange::LENGTH * 15)).len(),
395 15
396 );
397 }
398
399 #[test]
400 fn test_block_ranges_sequence_contains() {
401 let block_range = BlockRange::new(15, 30);
402 assert!(
403 BlockRange::all_block_ranges_in(BlockNumber(0)..=BlockNumber(14))
404 .contains(&block_range)
405 .not()
406 );
407 assert!(
408 BlockRange::all_block_ranges_in(BlockNumber(30)..=BlockNumber(59))
409 .contains(&block_range)
410 .not()
411 );
412 assert!(
413 BlockRange::all_block_ranges_in(BlockNumber(0)..=BlockNumber(29))
414 .contains(&block_range)
415 );
416 assert!(
417 BlockRange::all_block_ranges_in(BlockNumber(15)..=BlockNumber(29))
418 .contains(&block_range)
419 );
420 assert!(
421 BlockRange::all_block_ranges_in(BlockNumber(15)..=BlockNumber(44))
422 .contains(&block_range)
423 );
424 }
425
426 #[test]
427 fn test_block_range_from_number() {
428 assert_eq!(
429 BlockRange::from_block_number(BlockNumber(0)),
430 BlockRange::new(0, 15)
431 );
432 assert_eq!(
433 BlockRange::from_block_number(BlockNumber(1)),
434 BlockRange::new(0, 15)
435 );
436 assert_eq!(
437 BlockRange::from_block_number(BlockNumber(14)),
438 BlockRange::new(0, 15)
439 );
440 assert_eq!(
441 BlockRange::from_block_number(BlockNumber(15)),
442 BlockRange::new(15, 30)
443 );
444 assert_eq!(
445 BlockRange::from_block_number(BlockNumber(16)),
446 BlockRange::new(15, 30)
447 );
448 assert_eq!(
449 BlockRange::from_block_number(BlockNumber(29)),
450 BlockRange::new(15, 30)
451 );
452 }
453
454 #[test]
455 fn test_block_range_from_number_and_length_with_valid_input() {
456 assert_eq!(
457 BlockRange::from_block_number_and_length(BlockNumber(0), BlockNumber(10)).unwrap(),
458 BlockRange::new(0, 10)
459 );
460 assert_eq!(
461 BlockRange::from_block_number_and_length(BlockNumber(1), BlockNumber(10)).unwrap(),
462 BlockRange::new(0, 10)
463 );
464 assert_eq!(
465 BlockRange::from_block_number_and_length(BlockNumber(9), BlockNumber(10)).unwrap(),
466 BlockRange::new(0, 10)
467 );
468 assert_eq!(
469 BlockRange::from_block_number_and_length(BlockNumber(10), BlockNumber(10)).unwrap(),
470 BlockRange::new(10, 20)
471 );
472 assert_eq!(
473 BlockRange::from_block_number_and_length(BlockNumber(11), BlockNumber(10)).unwrap(),
474 BlockRange::new(10, 20)
475 );
476 assert_eq!(
477 BlockRange::from_block_number_and_length(BlockNumber(19), BlockNumber(10)).unwrap(),
478 BlockRange::new(10, 20)
479 );
480 }
481
482 #[test]
483 fn test_block_range_from_number_and_length_with_invalid_input() {
484 BlockRange::from_block_number_and_length(BlockNumber(10), BlockNumber(0))
485 .expect_err("BlockRange should not be computed with a length of 0");
486 }
487
488 #[test]
489 #[allow(clippy::reversed_empty_ranges)]
491 fn test_building_sequence_with_start_greater_than_end_yield_empty_iterator() {
492 let sequence = BlockRange::all_block_ranges_in(BlockNumber(30)..=BlockNumber(15));
493 assert_eq!(sequence.clone().into_vec(), vec![]);
494 assert!(sequence.is_empty());
495 }
496}