1use core::{fmt, ops};
15
16#[cfg(feature = "arbitrary")]
17use arbitrary::{Arbitrary, Unstructured};
18#[cfg(feature = "serde")]
19use serde::{Deserialize, Deserializer, Serialize, Serializer};
20
21#[cfg(doc)]
22use crate::locktime;
23use crate::locktime::{absolute, relative};
24use crate::parse_int::{self, PrefixedHexError, UnprefixedHexError};
25
26#[rustfmt::skip] #[cfg(feature = "encoding")]
28#[doc(no_inline)]
29pub use self::error::BlockHeightDecoderError;
30#[doc(no_inline)]
31pub use self::error::TooBigForRelativeHeightError;
32
33macro_rules! impl_u32_wrapper {
34 {
35 $(#[$($type_attrs:tt)*])*
36 $type_vis:vis struct $newtype:ident($inner_vis:vis u32);
37 } => {
38 $(#[$($type_attrs)*])*
39 $type_vis struct $newtype($inner_vis u32);
40
41 impl $newtype {
42 #[doc = "Constructs a new `"]
43 #[doc = stringify!($newtype)]
44 #[doc = "` from an unprefixed hex string.\n\n"]
45 #[doc = "# Errors\n\n"]
46 #[doc = "If the input string is not a valid hex representation of a `"]
47 #[doc = stringify!($newtype)]
48 #[doc = "` or it does not include the `0x` prefix."]
49 #[inline]
50 pub fn from_hex(s: &str) -> Result<Self, PrefixedHexError> {
51 let block_height = parse_int::hex_u32_prefixed(s)?;
52 Ok(Self(block_height))
53 }
54
55 #[doc = "Constructs a new `"]
56 #[doc = stringify!($newtype)]
57 #[doc = "` from a prefixed hex string.\n\n"]
58 #[doc = "# Errors\n\n"]
59 #[doc = "If the input string is not a valid hex representation of a `"]
60 #[doc = stringify!($newtype)]
61 #[doc = "` or if it includes the `0x` prefix."]
62 #[inline]
63 pub fn from_unprefixed_hex(s: &str) -> Result<Self, UnprefixedHexError> {
64 let block_height = parse_int::hex_u32_unprefixed(s)?;
65 Ok(Self(block_height))
66 }
67 }
68
69 impl fmt::Display for $newtype {
70 #[inline]
71 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
72 }
73
74 crate::parse_int::impl_parse_str_from_int_infallible!($newtype, u32, from);
75
76 impl From<u32> for $newtype {
77 #[inline]
78 fn from(inner: u32) -> Self { Self::from_u32(inner) }
79 }
80
81 impl From<$newtype> for u32 {
82 #[inline]
83 fn from(height: $newtype) -> Self { height.to_u32() }
84 }
85
86 #[cfg(feature = "serde")]
87 impl Serialize for $newtype {
88 #[inline]
89 fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
90 where
91 S: Serializer,
92 {
93 u32::serialize(&self.to_u32(), s)
94 }
95 }
96
97 #[cfg(feature = "serde")]
98 impl<'de> Deserialize<'de> for $newtype {
99 #[inline]
100 fn deserialize<D>(d: D) -> Result<Self, D::Error>
101 where
102 D: Deserializer<'de>,
103 {
104 Ok(Self::from_u32(u32::deserialize(d)?))
105 }
106 }
107
108 #[cfg(feature = "arbitrary")]
109 impl<'a> Arbitrary<'a> for $newtype {
110 fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
111 let choice = u.int_in_range(0..=2)?;
112 match choice {
113 0 => Ok(Self::ZERO),
114 1 => Ok(Self::MIN),
115 2 => Ok(Self::MAX),
116 _ => Ok(Self::from_u32(u32::arbitrary(u)?)),
117 }
118 }
119 }
120 }
121}
122
123impl_u32_wrapper! {
124 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
131 pub struct BlockHeight(u32);
132}
133
134impl BlockHeight {
135 pub const ZERO: Self = Self(0);
137
138 pub const MIN: Self = Self::ZERO;
140
141 pub const MAX: Self = Self(u32::MAX);
143
144 #[inline]
146 pub const fn from_u32(inner: u32) -> Self { Self(inner) }
147
148 #[inline]
150 pub const fn to_u32(self) -> u32 { self.0 }
151
152 #[inline]
154 #[must_use]
155 pub fn checked_sub(self, other: Self) -> Option<BlockHeightInterval> {
156 self.to_u32().checked_sub(other.to_u32()).map(BlockHeightInterval)
157 }
158
159 #[inline]
161 #[must_use]
162 pub fn checked_add(self, other: BlockHeightInterval) -> Option<Self> {
163 self.to_u32().checked_add(other.to_u32()).map(Self)
164 }
165
166 #[inline]
170 #[must_use]
171 pub const fn saturating_add(self, rhs: BlockHeightInterval) -> Self {
172 Self::from_u32(self.to_u32().saturating_add(rhs.to_u32()))
173 }
174
175 #[inline]
179 #[must_use]
180 pub const fn saturating_sub(self, rhs: BlockHeightInterval) -> Self {
181 Self::from_u32(self.to_u32().saturating_sub(rhs.to_u32()))
182 }
183}
184
185crate::internal_macros::impl_fmt_traits_for_u32_wrapper!(BlockHeight);
186
187impl From<absolute::Height> for BlockHeight {
188 #[inline]
193 fn from(h: absolute::Height) -> Self { Self::from_u32(h.to_u32()) }
194}
195
196impl TryFrom<BlockHeight> for absolute::Height {
197 type Error = absolute::ConversionError;
198
199 #[inline]
204 fn try_from(h: BlockHeight) -> Result<Self, Self::Error> { Self::from_u32(h.to_u32()) }
205}
206
207#[cfg(feature = "encoding")]
208impl encoding::Encode for BlockHeight {
209 type Encoder<'e> = BlockHeightEncoder<'e>;
210 #[inline]
211 fn encoder(&self) -> Self::Encoder<'_> {
212 BlockHeightEncoder::new(encoding::ArrayEncoder::without_length_prefix(
213 self.to_u32().to_le_bytes(),
214 ))
215 }
216}
217
218#[cfg(feature = "encoding")]
219impl encoding::Decode for BlockHeight {
220 type Decoder = BlockHeightDecoder;
221}
222
223#[cfg(feature = "encoding")]
224encoding::encoder_newtype_exact! {
225 #[derive(Debug, Clone)]
227 pub struct BlockHeightEncoder<'e>(encoding::ArrayEncoder<4>);
228}
229
230#[cfg(feature = "encoding")]
231crate::decoder_newtype! {
232 #[derive(Debug, Clone)]
234 pub struct BlockHeightDecoder(encoding::ArrayDecoder<4>);
235
236 pub const fn new() -> Self { Self(encoding::ArrayDecoder::new()) }
238
239 fn end(result: Result<[u8; 4], encoding::UnexpectedEofError>) -> Result<BlockHeight, BlockHeightDecoderError> {
240 let value = result.map_err(BlockHeightDecoderError)?;
241 let n = u32::from_le_bytes(value);
242 Ok(BlockHeight::from_u32(n))
243 }
244}
245
246impl_u32_wrapper! {
247 #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
254 pub struct BlockHeightInterval(u32);
255}
256
257impl BlockHeightInterval {
258 pub const ZERO: Self = Self(0);
260
261 pub const MIN: Self = Self::ZERO;
263
264 pub const MAX: Self = Self(u32::MAX);
266
267 #[inline]
269 pub const fn from_u32(inner: u32) -> Self { Self(inner) }
270
271 #[inline]
273 pub const fn to_u32(self) -> u32 { self.0 }
274
275 #[inline]
277 #[must_use]
278 pub fn checked_sub(self, other: Self) -> Option<Self> {
279 self.to_u32().checked_sub(other.to_u32()).map(Self)
280 }
281
282 #[inline]
284 #[must_use]
285 pub fn checked_add(self, other: Self) -> Option<Self> {
286 self.to_u32().checked_add(other.to_u32()).map(Self)
287 }
288}
289
290crate::internal_macros::impl_fmt_traits_for_u32_wrapper!(BlockHeightInterval);
291
292impl From<relative::NumberOfBlocks> for BlockHeightInterval {
293 #[inline]
298 fn from(h: relative::NumberOfBlocks) -> Self { Self::from_u32(h.to_height().into()) }
299}
300
301impl TryFrom<BlockHeightInterval> for relative::NumberOfBlocks {
302 type Error = TooBigForRelativeHeightError;
303
304 #[inline]
309 fn try_from(h: BlockHeightInterval) -> Result<Self, Self::Error> {
310 u16::try_from(h.to_u32())
311 .map(Self::from)
312 .map_err(|_| TooBigForRelativeHeightError(h.into()))
313 }
314}
315
316impl_u32_wrapper! {
317 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
324 pub struct BlockMtp(u32);
325}
326
327impl BlockMtp {
328 pub const ZERO: Self = Self(0);
333
334 pub const MIN: Self = Self::ZERO;
336
337 pub const MAX: Self = Self(u32::MAX);
339
340 #[inline]
342 pub const fn from_u32(inner: u32) -> Self { Self(inner) }
343
344 #[inline]
346 pub const fn to_u32(self) -> u32 { self.0 }
347
348 #[inline]
354 pub fn new(mut timestamps: [crate::BlockTime; 11]) -> Self {
355 timestamps.sort_unstable();
356 Self::from_u32(u32::from(timestamps[5]))
357 }
358
359 #[inline]
361 #[must_use]
362 pub fn checked_sub(self, other: Self) -> Option<BlockMtpInterval> {
363 self.to_u32().checked_sub(other.to_u32()).map(BlockMtpInterval)
364 }
365
366 #[inline]
368 #[must_use]
369 pub fn checked_add(self, other: BlockMtpInterval) -> Option<Self> {
370 self.to_u32().checked_add(other.to_u32()).map(Self)
371 }
372}
373
374crate::internal_macros::impl_fmt_traits_for_u32_wrapper!(BlockMtp);
375
376impl From<absolute::MedianTimePast> for BlockMtp {
377 #[inline]
382 fn from(h: absolute::MedianTimePast) -> Self { Self::from_u32(h.to_u32()) }
383}
384
385impl TryFrom<BlockMtp> for absolute::MedianTimePast {
386 type Error = absolute::ConversionError;
387
388 #[inline]
393 fn try_from(h: BlockMtp) -> Result<Self, Self::Error> { Self::from_u32(h.to_u32()) }
394}
395
396impl_u32_wrapper! {
397 #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
404 pub struct BlockMtpInterval(u32);
405}
406
407impl BlockMtpInterval {
408 pub const ZERO: Self = Self(0);
410
411 pub const MIN: Self = Self::ZERO;
413
414 pub const MAX: Self = Self(u32::MAX);
416
417 #[inline]
419 pub const fn from_u32(inner: u32) -> Self { Self(inner) }
420
421 #[inline]
423 pub const fn to_u32(self) -> u32 { self.0 }
424
425 #[inline]
435 pub const fn to_relative_mtp_interval_floor(
436 self,
437 ) -> Result<relative::NumberOf512Seconds, relative::TimeOverflowError> {
438 relative::NumberOf512Seconds::from_seconds_floor(self.to_u32())
439 }
440
441 #[inline]
451 pub const fn to_relative_mtp_interval_ceil(
452 self,
453 ) -> Result<relative::NumberOf512Seconds, relative::TimeOverflowError> {
454 relative::NumberOf512Seconds::from_seconds_ceil(self.to_u32())
455 }
456
457 #[inline]
459 #[must_use]
460 pub fn checked_sub(self, other: Self) -> Option<Self> {
461 self.to_u32().checked_sub(other.to_u32()).map(Self)
462 }
463
464 #[inline]
466 #[must_use]
467 pub fn checked_add(self, other: Self) -> Option<Self> {
468 self.to_u32().checked_add(other.to_u32()).map(Self)
469 }
470}
471
472crate::internal_macros::impl_fmt_traits_for_u32_wrapper!(BlockMtpInterval);
473
474impl From<relative::NumberOf512Seconds> for BlockMtpInterval {
475 #[inline]
481 fn from(h: relative::NumberOf512Seconds) -> Self { Self::from_u32(h.to_seconds()) }
482}
483
484crate::internal_macros::impl_op_for_references! {
485 impl ops::Sub<BlockHeight> for BlockHeight {
487 type Output = BlockHeightInterval;
488
489 fn sub(self, rhs: BlockHeight) -> Self::Output {
490 let interval = self.to_u32() - rhs.to_u32();
491 BlockHeightInterval::from_u32(interval)
492 }
493 }
494
495 impl ops::Add<BlockHeightInterval> for BlockHeight {
497 type Output = BlockHeight;
498
499 fn add(self, rhs: BlockHeightInterval) -> Self::Output {
500 let height = self.to_u32() + rhs.to_u32();
501 BlockHeight::from_u32(height)
502 }
503 }
504
505 impl ops::Sub<BlockHeightInterval> for BlockHeight {
507 type Output = BlockHeight;
508
509 fn sub(self, rhs: BlockHeightInterval) -> Self::Output {
510 let height = self.to_u32() - rhs.to_u32();
511 BlockHeight::from_u32(height)
512 }
513 }
514
515 impl ops::Add<BlockHeightInterval> for BlockHeightInterval {
517 type Output = BlockHeightInterval;
518
519 fn add(self, rhs: BlockHeightInterval) -> Self::Output {
520 let height = self.to_u32() + rhs.to_u32();
521 BlockHeightInterval::from_u32(height)
522 }
523 }
524
525 impl ops::Sub<BlockHeightInterval> for BlockHeightInterval {
527 type Output = BlockHeightInterval;
528
529 fn sub(self, rhs: BlockHeightInterval) -> Self::Output {
530 let height = self.to_u32() - rhs.to_u32();
531 BlockHeightInterval::from_u32(height)
532 }
533 }
534
535 impl ops::Sub<BlockMtp> for BlockMtp {
537 type Output = BlockMtpInterval;
538
539 fn sub(self, rhs: BlockMtp) -> Self::Output {
540 let interval = self.to_u32() - rhs.to_u32();
541 BlockMtpInterval::from_u32(interval)
542 }
543 }
544
545 impl ops::Add<BlockMtpInterval> for BlockMtp {
547 type Output = BlockMtp;
548
549 fn add(self, rhs: BlockMtpInterval) -> Self::Output {
550 let height = self.to_u32() + rhs.to_u32();
551 BlockMtp::from_u32(height)
552 }
553 }
554
555 impl ops::Sub<BlockMtpInterval> for BlockMtp {
557 type Output = BlockMtp;
558
559 fn sub(self, rhs: BlockMtpInterval) -> Self::Output {
560 let height = self.to_u32() - rhs.to_u32();
561 BlockMtp::from_u32(height)
562 }
563 }
564
565 impl ops::Add<BlockMtpInterval> for BlockMtpInterval {
567 type Output = BlockMtpInterval;
568
569 fn add(self, rhs: BlockMtpInterval) -> Self::Output {
570 let height = self.to_u32() + rhs.to_u32();
571 BlockMtpInterval::from_u32(height)
572 }
573 }
574
575 impl ops::Sub<BlockMtpInterval> for BlockMtpInterval {
577 type Output = BlockMtpInterval;
578
579 fn sub(self, rhs: BlockMtpInterval) -> Self::Output {
580 let height = self.to_u32() - rhs.to_u32();
581 BlockMtpInterval::from_u32(height)
582 }
583 }
584}
585
586crate::internal_macros::impl_add_assign!(BlockHeightInterval);
587crate::internal_macros::impl_sub_assign!(BlockHeightInterval);
588crate::internal_macros::impl_add_assign!(BlockMtpInterval);
589crate::internal_macros::impl_sub_assign!(BlockMtpInterval);
590
591impl core::iter::Sum for BlockHeightInterval {
592 #[inline]
593 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
594 let sum = iter.map(Self::to_u32).sum();
595 Self::from_u32(sum)
596 }
597}
598
599impl<'a> core::iter::Sum<&'a Self> for BlockHeightInterval {
600 #[inline]
601 fn sum<I>(iter: I) -> Self
602 where
603 I: Iterator<Item = &'a Self>,
604 {
605 let sum = iter.map(|interval| interval.to_u32()).sum();
606 Self::from_u32(sum)
607 }
608}
609
610impl core::iter::Sum for BlockMtpInterval {
611 #[inline]
612 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
613 let sum = iter.map(Self::to_u32).sum();
614 Self::from_u32(sum)
615 }
616}
617
618impl<'a> core::iter::Sum<&'a Self> for BlockMtpInterval {
619 #[inline]
620 fn sum<I>(iter: I) -> Self
621 where
622 I: Iterator<Item = &'a Self>,
623 {
624 let sum = iter.map(|interval| interval.to_u32()).sum();
625 Self::from_u32(sum)
626 }
627}
628
629pub mod error {
631 use core::convert::Infallible;
632 use core::fmt;
633
634 #[cfg(feature = "encoding")]
635 use internals::write_err;
636
637 use crate::locktime::relative;
638
639 #[derive(Debug, Clone, PartialEq, Eq)]
641 pub struct TooBigForRelativeHeightError(pub(super) u32);
642
643 impl From<Infallible> for TooBigForRelativeHeightError {
644 fn from(never: Infallible) -> Self { match never {} }
645 }
646
647 impl fmt::Display for TooBigForRelativeHeightError {
648 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
649 write!(
650 f,
651 "block interval is too big to be used as a relative lock time: {} (max: {})",
652 self.0,
653 relative::NumberOfBlocks::MAX
654 )
655 }
656 }
657
658 #[cfg(feature = "std")]
659 impl std::error::Error for TooBigForRelativeHeightError {
660 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
661 let Self(_) = self;
662 None
663 }
664 }
665
666 #[cfg(feature = "encoding")]
668 #[derive(Debug, Clone, PartialEq, Eq)]
669 pub struct BlockHeightDecoderError(pub(super) encoding::UnexpectedEofError);
670
671 #[cfg(feature = "encoding")]
672 impl From<Infallible> for BlockHeightDecoderError {
673 fn from(never: Infallible) -> Self { match never {} }
674 }
675
676 #[cfg(feature = "encoding")]
677 impl fmt::Display for BlockHeightDecoderError {
678 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
679 write_err!(f, "block height decoder error"; self.0)
680 }
681 }
682
683 #[cfg(feature = "encoding")]
684 #[cfg(feature = "std")]
685 impl std::error::Error for BlockHeightDecoderError {
686 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { Some(&self.0) }
687 }
688}
689
690#[cfg(test)]
691mod tests {
692 #[cfg(feature = "alloc")]
693 use alloc::string::ToString;
694 #[cfg(feature = "std")]
695 use std::error::Error;
696
697 #[cfg(feature = "encoding")]
698 use encoding::{Decode as _, Decoder as _, UnexpectedEofError};
699
700 use super::*;
701 use crate::relative::{NumberOf512Seconds, TimeOverflowError};
702
703 #[test]
704 fn sanity_check() {
705 let height: u32 = BlockHeight(100).into();
706 assert_eq!(height, 100);
707
708 let interval: u32 = BlockHeightInterval(100).into();
709 assert_eq!(interval, 100);
710
711 let interval_from_height: BlockHeightInterval =
712 relative::NumberOfBlocks::from(10u16).into();
713 assert_eq!(interval_from_height.to_u32(), 10u32);
714
715 let invalid_height_greater =
716 relative::NumberOfBlocks::try_from(BlockHeightInterval(u32::from(u16::MAX) + 1));
717 assert!(invalid_height_greater.is_err());
718
719 let valid_height =
720 relative::NumberOfBlocks::try_from(BlockHeightInterval(u32::from(u16::MAX)));
721 assert!(valid_height.is_ok());
722 }
723
724 #[test]
726 fn all_available_ops() {
727 assert!(BlockHeight(10) - BlockHeight(7) == BlockHeightInterval(3));
729
730 assert!(BlockHeight(100) + BlockHeightInterval(1) == BlockHeight(101));
732
733 assert!(BlockHeight(100) - BlockHeightInterval(1) == BlockHeight(99));
735
736 assert!(BlockHeightInterval(1) + BlockHeightInterval(2) == BlockHeightInterval(3));
738
739 assert!(BlockHeightInterval(10) - BlockHeightInterval(7) == BlockHeightInterval(3));
741
742 assert!(
744 [BlockHeightInterval(1), BlockHeightInterval(2), BlockHeightInterval(3)]
745 .iter()
746 .sum::<BlockHeightInterval>()
747 == BlockHeightInterval(6)
748 );
749 assert!(
750 [BlockHeightInterval(4), BlockHeightInterval(5), BlockHeightInterval(6)]
751 .into_iter()
752 .sum::<BlockHeightInterval>()
753 == BlockHeightInterval(15)
754 );
755
756 assert!(
758 [BlockMtpInterval(1), BlockMtpInterval(2), BlockMtpInterval(3)]
759 .iter()
760 .sum::<BlockMtpInterval>()
761 == BlockMtpInterval(6)
762 );
763 assert!(
764 [BlockMtpInterval(4), BlockMtpInterval(5), BlockMtpInterval(6)]
765 .into_iter()
766 .sum::<BlockMtpInterval>()
767 == BlockMtpInterval(15)
768 );
769
770 let mut int = BlockHeightInterval(1);
772 int += BlockHeightInterval(2);
773 assert_eq!(int, BlockHeightInterval(3));
774
775 let mut int = BlockHeightInterval(10);
777 int -= BlockHeightInterval(7);
778 assert_eq!(int, BlockHeightInterval(3));
779 }
780
781 #[test]
782 fn block_height_checked() {
783 let a = BlockHeight(10);
784 let b = BlockHeight(5);
785 assert_eq!(a.checked_sub(b), Some(BlockHeightInterval(5)));
786 assert_eq!(a.checked_add(BlockHeightInterval(5)), Some(BlockHeight(15)));
787 assert_eq!(a.checked_sub(BlockHeight(11)), None);
788 assert_eq!(a.checked_add(BlockHeightInterval(u32::MAX - 5)), None);
789 }
790
791 #[test]
792 fn block_height_interval_checked() {
793 let a = BlockHeightInterval(10);
794 let b = BlockHeightInterval(5);
795 assert_eq!(a.checked_sub(b), Some(BlockHeightInterval(5)));
796 assert_eq!(a.checked_add(b), Some(BlockHeightInterval(15)));
797 assert_eq!(a.checked_sub(BlockHeightInterval(11)), None);
798 assert_eq!(a.checked_add(BlockHeightInterval(u32::MAX - 5)), None);
799 }
800
801 #[test]
802 fn block_mtp_interval_checked() {
803 let a = BlockMtpInterval(10);
804 let b = BlockMtpInterval(5);
805 assert_eq!(a.checked_sub(b), Some(BlockMtpInterval(5)));
806 assert_eq!(a.checked_add(b), Some(BlockMtpInterval(15)));
807 assert_eq!(a.checked_sub(BlockMtpInterval(11)), None);
808 assert_eq!(a.checked_add(BlockMtpInterval(u32::MAX - 5)), None);
809 }
810
811 #[test]
812 fn block_mtp_checked() {
813 let a = BlockMtp(10);
814 let b = BlockMtp(5);
815 assert_eq!(a.checked_sub(b), Some(BlockMtpInterval(5)));
816 assert_eq!(a.checked_add(BlockMtpInterval(5)), Some(BlockMtp(15)));
817 assert_eq!(a.checked_sub(BlockMtp(11)), None);
818 assert_eq!(a.checked_add(BlockMtpInterval(u32::MAX - 5)), None);
819 }
820
821 #[test]
822 fn block_mtp_interval_from_number_of_512seconds() {
823 let n = NumberOf512Seconds::from_seconds_floor(0).unwrap();
824 let interval = BlockMtpInterval::from(n);
825 assert_eq!(interval, BlockMtpInterval(0));
826 let n = NumberOf512Seconds::from_seconds_floor(1024).unwrap();
827 let interval = BlockMtpInterval::from(n);
828 assert_eq!(interval, BlockMtpInterval(1024));
829 }
830
831 #[test]
832 fn block_mtp_interval_to_relative_mtp_floor() {
833 let time = NumberOf512Seconds::from_512_second_intervals(0);
834 let interval = BlockMtpInterval::from_u32(0);
835 assert_eq!(interval.to_relative_mtp_interval_floor().unwrap(), time);
836
837 let time = NumberOf512Seconds::from_512_second_intervals(1);
838 let interval = BlockMtpInterval::from_u32(1023);
839 assert_eq!(interval.to_relative_mtp_interval_floor().unwrap(), time); assert_ne!(interval.to_relative_mtp_interval_ceil().unwrap(), time); let max_time = NumberOf512Seconds::from_512_second_intervals(u16::MAX);
844 let max_seconds = u32::from(u16::MAX) * 512 + 511;
845
846 let interval = BlockMtpInterval::from_u32(max_seconds);
847 assert_eq!(interval.to_relative_mtp_interval_floor().unwrap(), max_time);
848 let interval = BlockMtpInterval::from_u32(max_seconds + 1);
849 assert_eq!(
850 interval.to_relative_mtp_interval_floor().unwrap_err(),
851 TimeOverflowError { seconds: max_seconds + 1 }
852 );
853 }
854
855 #[test]
856 fn block_mtp_interval_to_relative_mtp_ceil() {
857 let time = NumberOf512Seconds::from_512_second_intervals(0);
858 let interval = BlockMtpInterval::from_u32(0);
859 assert_eq!(interval.to_relative_mtp_interval_ceil().unwrap(), time);
860
861 let time = NumberOf512Seconds::from_512_second_intervals(2);
862 let interval = BlockMtpInterval::from_u32(1023);
863 assert_eq!(interval.to_relative_mtp_interval_ceil().unwrap(), time); assert_ne!(interval.to_relative_mtp_interval_floor().unwrap(), time); let max_time = NumberOf512Seconds::from_512_second_intervals(u16::MAX);
868 let max_seconds = u32::from(u16::MAX) * 512;
869
870 let interval = BlockMtpInterval::from_u32(max_seconds);
871 assert_eq!(interval.to_relative_mtp_interval_ceil().unwrap(), max_time);
872 let interval = BlockMtpInterval::from_u32(max_seconds + 1);
873 assert_eq!(
874 interval.to_relative_mtp_interval_ceil().unwrap_err(),
875 TimeOverflowError { seconds: max_seconds + 1 }
876 );
877 }
878
879 #[test]
880 #[cfg(feature = "encoding")]
881 fn block_height_decoding_error() {
882 let bytes = [0xff, 0xff, 0xff]; let mut decoder = BlockHeightDecoder::default();
885 assert!(decoder.push_bytes(&mut bytes.as_slice()).unwrap().needs_more());
886
887 let error = decoder.end().unwrap_err();
888 assert!(matches!(error, BlockHeightDecoderError(UnexpectedEofError { .. })));
889 }
890
891 macro_rules! serde_roundtrip_test {
893 { $test_name:tt, $typ:ident } => {
894 #[test]
895 #[cfg(feature = "serde")]
896 fn $test_name() {
897 let t = $typ(1_654_321);
898
899 let json = serde_json::to_string(&t).unwrap();
900 assert_eq!(json, "1654321"); let roundtrip = serde_json::from_str::<$typ>(&json).unwrap();
903 assert_eq!(t, roundtrip);
904 }
905 }
906 }
907
908 serde_roundtrip_test!(block_height_serde_round_trip, BlockHeight);
909 serde_roundtrip_test!(block_height_interval_serde_round_trip, BlockHeightInterval);
910 serde_roundtrip_test!(block_mtp_serde_round_trip, BlockMtp);
911 serde_roundtrip_test!(block_mtp_interval_serde_round_trip, BlockMtpInterval);
912
913 #[test]
914 fn block_height_saturating_add() {
915 assert_eq!(BlockHeight(100).saturating_add(BlockHeightInterval(50)), BlockHeight(150),);
917 assert_eq!(BlockHeight::ZERO.saturating_add(BlockHeightInterval(1)), BlockHeight(1),);
918
919 assert_eq!(BlockHeight::MAX.saturating_add(BlockHeightInterval(1)), BlockHeight::MAX,);
921 assert_eq!(BlockHeight::MAX.saturating_add(BlockHeightInterval(100)), BlockHeight::MAX,);
922 assert_eq!(
923 BlockHeight(u32::MAX - 10).saturating_add(BlockHeightInterval(20)),
924 BlockHeight::MAX,
925 );
926
927 assert_eq!(BlockHeight(500).saturating_add(BlockHeightInterval::ZERO), BlockHeight(500),);
929 }
930
931 #[test]
932 fn block_height_saturating_sub() {
933 assert_eq!(BlockHeight(100).saturating_sub(BlockHeightInterval(50)), BlockHeight(50),);
935 assert_eq!(BlockHeight(100).saturating_sub(BlockHeightInterval(100)), BlockHeight(0),);
936
937 assert_eq!(BlockHeight::MIN.saturating_sub(BlockHeightInterval(1)), BlockHeight::MIN,);
939 assert_eq!(BlockHeight::ZERO.saturating_sub(BlockHeightInterval(100)), BlockHeight::ZERO,);
940 assert_eq!(BlockHeight(10).saturating_sub(BlockHeightInterval(20)), BlockHeight::ZERO,);
941
942 assert_eq!(BlockHeight(500).saturating_sub(BlockHeightInterval::ZERO), BlockHeight(500),);
944 }
945
946 #[test]
947 #[cfg(feature = "alloc")]
948 fn error_display_is_non_empty() {
949 let big_interval = BlockHeightInterval::from_u32(u32::MAX);
951 let e = relative::NumberOfBlocks::try_from(big_interval).unwrap_err();
952 assert!(!e.to_string().is_empty());
953 #[cfg(feature = "std")]
954 assert!(e.source().is_none());
955
956 #[cfg(feature = "encoding")]
957 {
958 let mut decoder = BlockHeight::decoder();
960 let _ = decoder.push_bytes(&mut [0u8; 3].as_slice());
961 let e = decoder.end().unwrap_err();
962 assert!(!e.to_string().is_empty());
963 #[cfg(feature = "std")]
964 assert!(e.source().is_some());
965 }
966 }
967}