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 a prefixed 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 an unprefixed 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 #[inline]
111 fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
112 let choice = u.int_in_range(0..=3)?;
113 match choice {
114 0 => Ok(Self::ZERO),
115 1 => Ok(Self::MIN),
116 2 => Ok(Self::MAX),
117 _ => Ok(Self::from_u32(u32::arbitrary(u)?)),
118 }
119 }
120 }
121 }
122}
123
124impl_u32_wrapper! {
125 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
132 pub struct BlockHeight(u32);
133}
134
135impl BlockHeight {
136 pub const ZERO: Self = Self(0);
138
139 pub const MIN: Self = Self::ZERO;
141
142 pub const MAX: Self = Self(u32::MAX);
144
145 #[inline]
147 pub const fn from_u32(inner: u32) -> Self { Self(inner) }
148
149 #[inline]
151 pub const fn to_u32(self) -> u32 { self.0 }
152
153 #[inline]
155 #[must_use]
156 pub fn checked_sub(self, other: Self) -> Option<BlockHeightInterval> {
157 self.to_u32().checked_sub(other.to_u32()).map(BlockHeightInterval)
158 }
159
160 #[inline]
163 #[must_use]
164 pub fn checked_add(self, other: BlockHeightInterval) -> Option<Self> {
165 self.to_u32().checked_add(other.to_u32()).map(Self)
166 }
167
168 #[inline]
172 #[must_use]
173 pub const fn saturating_add(self, rhs: BlockHeightInterval) -> Self {
174 Self::from_u32(self.to_u32().saturating_add(rhs.to_u32()))
175 }
176
177 #[inline]
181 #[must_use]
182 pub const fn saturating_sub(self, rhs: BlockHeightInterval) -> Self {
183 Self::from_u32(self.to_u32().saturating_sub(rhs.to_u32()))
184 }
185}
186
187crate::internal_macros::impl_fmt_traits_for_u32_wrapper!(BlockHeight);
188
189impl From<absolute::Height> for BlockHeight {
190 #[inline]
195 fn from(h: absolute::Height) -> Self { Self::from_u32(h.to_u32()) }
196}
197
198impl TryFrom<BlockHeight> for absolute::Height {
199 type Error = absolute::ConversionError;
200
201 #[inline]
206 fn try_from(h: BlockHeight) -> Result<Self, Self::Error> { Self::from_u32(h.to_u32()) }
207}
208
209#[cfg(feature = "encoding")]
210impl encoding::Encode for BlockHeight {
211 type Encoder<'e> = BlockHeightEncoder<'e>;
212 #[inline]
213 fn encoder(&self) -> Self::Encoder<'_> {
214 BlockHeightEncoder::new(encoding::ArrayEncoder::without_length_prefix(
215 self.to_u32().to_le_bytes(),
216 ))
217 }
218}
219
220#[cfg(feature = "encoding")]
221impl encoding::Decode for BlockHeight {
222 type Decoder = BlockHeightDecoder;
223}
224
225#[cfg(feature = "encoding")]
226encoding::encoder_newtype_exact! {
227 #[derive(Debug, Clone)]
229 pub struct BlockHeightEncoder<'e>(encoding::ArrayEncoder<4>);
230}
231
232#[cfg(feature = "encoding")]
233crate::decoder_newtype! {
234 #[derive(Debug, Clone)]
236 pub struct BlockHeightDecoder(encoding::ArrayDecoder<4>);
237
238 pub const fn new() -> Self { Self(encoding::ArrayDecoder::new()) }
240
241 fn end(result: Result<[u8; 4], encoding::UnexpectedEofError>) -> Result<BlockHeight, BlockHeightDecoderError> {
242 let value = result.map_err(BlockHeightDecoderError)?;
243 let n = u32::from_le_bytes(value);
244 Ok(BlockHeight::from_u32(n))
245 }
246}
247
248impl_u32_wrapper! {
249 #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
256 pub struct BlockHeightInterval(u32);
257}
258
259impl BlockHeightInterval {
260 pub const ZERO: Self = Self(0);
262
263 pub const MIN: Self = Self::ZERO;
265
266 pub const MAX: Self = Self(u32::MAX);
268
269 #[inline]
271 pub const fn from_u32(inner: u32) -> Self { Self(inner) }
272
273 #[inline]
275 pub const fn to_u32(self) -> u32 { self.0 }
276
277 #[inline]
279 #[must_use]
280 pub fn checked_sub(self, other: Self) -> Option<Self> {
281 self.to_u32().checked_sub(other.to_u32()).map(Self)
282 }
283
284 #[inline]
286 #[must_use]
287 pub fn checked_add(self, other: Self) -> Option<Self> {
288 self.to_u32().checked_add(other.to_u32()).map(Self)
289 }
290}
291
292crate::internal_macros::impl_fmt_traits_for_u32_wrapper!(BlockHeightInterval);
293
294impl From<relative::NumberOfBlocks> for BlockHeightInterval {
295 #[inline]
300 fn from(h: relative::NumberOfBlocks) -> Self { Self::from_u32(h.to_count().into()) }
301}
302
303impl TryFrom<BlockHeightInterval> for relative::NumberOfBlocks {
304 type Error = TooBigForRelativeHeightError;
305
306 #[inline]
311 fn try_from(h: BlockHeightInterval) -> Result<Self, Self::Error> {
312 u16::try_from(h.to_u32())
313 .map(Self::from_count)
314 .map_err(|_| TooBigForRelativeHeightError(h.into()))
315 }
316}
317
318impl_u32_wrapper! {
319 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
326 pub struct BlockMtp(u32);
327}
328
329impl BlockMtp {
330 pub const ZERO: Self = Self(0);
335
336 pub const MIN: Self = Self::ZERO;
338
339 pub const MAX: Self = Self(u32::MAX);
341
342 #[inline]
344 pub const fn from_u32(inner: u32) -> Self { Self(inner) }
345
346 #[inline]
348 pub const fn to_u32(self) -> u32 { self.0 }
349
350 #[inline]
356 pub fn new(mut timestamps: [crate::BlockTime; 11]) -> Self {
357 timestamps.sort_unstable();
358 Self::from_u32(u32::from(timestamps[5]))
359 }
360
361 #[inline]
363 #[must_use]
364 pub fn checked_sub(self, other: Self) -> Option<BlockMtpInterval> {
365 self.to_u32().checked_sub(other.to_u32()).map(BlockMtpInterval)
366 }
367
368 #[inline]
370 #[must_use]
371 pub fn checked_add(self, other: BlockMtpInterval) -> Option<Self> {
372 self.to_u32().checked_add(other.to_u32()).map(Self)
373 }
374}
375
376crate::internal_macros::impl_fmt_traits_for_u32_wrapper!(BlockMtp);
377
378impl From<absolute::MedianTimePast> for BlockMtp {
379 #[inline]
384 fn from(h: absolute::MedianTimePast) -> Self { Self::from_u32(h.to_u32()) }
385}
386
387impl TryFrom<BlockMtp> for absolute::MedianTimePast {
388 type Error = absolute::ConversionError;
389
390 #[inline]
395 fn try_from(h: BlockMtp) -> Result<Self, Self::Error> { Self::from_u32(h.to_u32()) }
396}
397
398impl_u32_wrapper! {
399 #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
406 pub struct BlockMtpInterval(u32);
407}
408
409impl BlockMtpInterval {
410 pub const ZERO: Self = Self(0);
412
413 pub const MIN: Self = Self::ZERO;
415
416 pub const MAX: Self = Self(u32::MAX);
418
419 #[inline]
421 pub const fn from_u32(inner: u32) -> Self { Self(inner) }
422
423 #[inline]
425 pub const fn to_u32(self) -> u32 { self.0 }
426
427 #[inline]
437 pub const fn to_relative_mtp_interval_floor(
438 self,
439 ) -> Result<relative::NumberOf512Seconds, relative::TimeOverflowError> {
440 relative::NumberOf512Seconds::from_seconds_floor(self.to_u32())
441 }
442
443 #[inline]
453 pub const fn to_relative_mtp_interval_ceil(
454 self,
455 ) -> Result<relative::NumberOf512Seconds, relative::TimeOverflowError> {
456 relative::NumberOf512Seconds::from_seconds_ceil(self.to_u32())
457 }
458
459 #[inline]
461 #[must_use]
462 pub fn checked_sub(self, other: Self) -> Option<Self> {
463 self.to_u32().checked_sub(other.to_u32()).map(Self)
464 }
465
466 #[inline]
468 #[must_use]
469 pub fn checked_add(self, other: Self) -> Option<Self> {
470 self.to_u32().checked_add(other.to_u32()).map(Self)
471 }
472}
473
474crate::internal_macros::impl_fmt_traits_for_u32_wrapper!(BlockMtpInterval);
475
476impl From<relative::NumberOf512Seconds> for BlockMtpInterval {
477 #[inline]
483 fn from(h: relative::NumberOf512Seconds) -> Self { Self::from_u32(h.to_seconds()) }
484}
485
486crate::internal_macros::impl_op_for_references! {
487 impl ops::Sub<BlockHeight> for BlockHeight {
489 type Output = BlockHeightInterval;
490
491 #[track_caller]
492 fn sub(self, rhs: BlockHeight) -> Self::Output {
493 let interval = self.to_u32() - rhs.to_u32();
494 BlockHeightInterval::from_u32(interval)
495 }
496 }
497
498 impl ops::Add<BlockHeightInterval> for BlockHeight {
500 type Output = BlockHeight;
501
502 #[track_caller]
503 fn add(self, rhs: BlockHeightInterval) -> Self::Output {
504 let height = self.to_u32() + rhs.to_u32();
505 BlockHeight::from_u32(height)
506 }
507 }
508
509 impl ops::Sub<BlockHeightInterval> for BlockHeight {
511 type Output = BlockHeight;
512
513 #[track_caller]
514 fn sub(self, rhs: BlockHeightInterval) -> Self::Output {
515 let height = self.to_u32() - rhs.to_u32();
516 BlockHeight::from_u32(height)
517 }
518 }
519
520 impl ops::Add<BlockHeightInterval> for BlockHeightInterval {
522 type Output = BlockHeightInterval;
523
524 #[track_caller]
525 fn add(self, rhs: BlockHeightInterval) -> Self::Output {
526 let height = self.to_u32() + rhs.to_u32();
527 BlockHeightInterval::from_u32(height)
528 }
529 }
530
531 impl ops::Sub<BlockHeightInterval> for BlockHeightInterval {
533 type Output = BlockHeightInterval;
534
535 #[track_caller]
536 fn sub(self, rhs: BlockHeightInterval) -> Self::Output {
537 let height = self.to_u32() - rhs.to_u32();
538 BlockHeightInterval::from_u32(height)
539 }
540 }
541
542 impl ops::Sub<BlockMtp> for BlockMtp {
544 type Output = BlockMtpInterval;
545
546 #[track_caller]
547 fn sub(self, rhs: BlockMtp) -> Self::Output {
548 let interval = self.to_u32() - rhs.to_u32();
549 BlockMtpInterval::from_u32(interval)
550 }
551 }
552
553 impl ops::Add<BlockMtpInterval> for BlockMtp {
555 type Output = BlockMtp;
556
557 #[track_caller]
558 fn add(self, rhs: BlockMtpInterval) -> Self::Output {
559 let height = self.to_u32() + rhs.to_u32();
560 BlockMtp::from_u32(height)
561 }
562 }
563
564 impl ops::Sub<BlockMtpInterval> for BlockMtp {
566 type Output = BlockMtp;
567
568 #[track_caller]
569 fn sub(self, rhs: BlockMtpInterval) -> Self::Output {
570 let height = self.to_u32() - rhs.to_u32();
571 BlockMtp::from_u32(height)
572 }
573 }
574
575 impl ops::Add<BlockMtpInterval> for BlockMtpInterval {
577 type Output = BlockMtpInterval;
578
579 #[track_caller]
580 fn add(self, rhs: BlockMtpInterval) -> Self::Output {
581 let height = self.to_u32() + rhs.to_u32();
582 BlockMtpInterval::from_u32(height)
583 }
584 }
585
586 impl ops::Sub<BlockMtpInterval> for BlockMtpInterval {
588 type Output = BlockMtpInterval;
589
590 #[track_caller]
591 fn sub(self, rhs: BlockMtpInterval) -> Self::Output {
592 let height = self.to_u32() - rhs.to_u32();
593 BlockMtpInterval::from_u32(height)
594 }
595 }
596}
597
598crate::internal_macros::impl_add_assign!(BlockHeightInterval);
599crate::internal_macros::impl_sub_assign!(BlockHeightInterval);
600crate::internal_macros::impl_add_assign!(BlockMtpInterval);
601crate::internal_macros::impl_sub_assign!(BlockMtpInterval);
602
603impl core::iter::Sum for BlockHeightInterval {
604 #[inline]
605 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
606 let sum = iter.map(Self::to_u32).sum();
607 Self::from_u32(sum)
608 }
609}
610
611impl<'a> core::iter::Sum<&'a Self> for BlockHeightInterval {
612 #[inline]
613 fn sum<I>(iter: I) -> Self
614 where
615 I: Iterator<Item = &'a Self>,
616 {
617 let sum = iter.map(|interval| interval.to_u32()).sum();
618 Self::from_u32(sum)
619 }
620}
621
622impl core::iter::Sum for BlockMtpInterval {
623 #[inline]
624 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
625 let sum = iter.map(Self::to_u32).sum();
626 Self::from_u32(sum)
627 }
628}
629
630impl<'a> core::iter::Sum<&'a Self> for BlockMtpInterval {
631 #[inline]
632 fn sum<I>(iter: I) -> Self
633 where
634 I: Iterator<Item = &'a Self>,
635 {
636 let sum = iter.map(|interval| interval.to_u32()).sum();
637 Self::from_u32(sum)
638 }
639}
640
641pub mod error {
643 use core::convert::Infallible;
644 use core::fmt;
645
646 #[cfg(feature = "encoding")]
647 use internals::write_err;
648
649 use crate::locktime::relative;
650
651 #[derive(Debug, Clone, PartialEq, Eq)]
653 pub struct TooBigForRelativeHeightError(pub(super) u32);
654
655 impl From<Infallible> for TooBigForRelativeHeightError {
656 #[inline]
657 fn from(never: Infallible) -> Self { match never {} }
658 }
659
660 impl fmt::Display for TooBigForRelativeHeightError {
661 #[inline]
662 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
663 write!(
664 f,
665 "block interval is too big to be used as a relative lock time: {} (max: {})",
666 self.0,
667 relative::NumberOfBlocks::MAX
668 )
669 }
670 }
671
672 #[cfg(feature = "std")]
673 impl std::error::Error for TooBigForRelativeHeightError {
674 #[inline]
675 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
676 let Self(_) = self;
677 None
678 }
679 }
680
681 #[cfg(feature = "encoding")]
685 #[derive(Debug, Clone, PartialEq, Eq)]
686 pub struct BlockHeightDecoderError(pub(super) encoding::UnexpectedEofError);
687
688 #[cfg(feature = "encoding")]
689 impl From<Infallible> for BlockHeightDecoderError {
690 #[inline]
691 fn from(never: Infallible) -> Self { match never {} }
692 }
693
694 #[cfg(feature = "encoding")]
695 impl fmt::Display for BlockHeightDecoderError {
696 #[inline]
697 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
698 write_err!(f, "block height decoder error"; self.0)
699 }
700 }
701
702 #[cfg(feature = "encoding")]
703 #[cfg(feature = "std")]
704 impl std::error::Error for BlockHeightDecoderError {
705 #[inline]
706 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { Some(&self.0) }
707 }
708}
709
710#[cfg(test)]
711mod tests {
712 #[cfg(feature = "alloc")]
713 use alloc::string::ToString;
714 #[cfg(feature = "std")]
715 use std::error::Error;
716
717 #[cfg(feature = "encoding")]
718 use encoding::{Decode as _, Decoder as _, UnexpectedEofError};
719
720 use super::*;
721 use crate::relative::{NumberOf512Seconds, TimeOverflowError};
722
723 #[test]
724 fn sanity_check() {
725 let height: u32 = BlockHeight(100).into();
726 assert_eq!(height, 100);
727
728 let interval: u32 = BlockHeightInterval(100).into();
729 assert_eq!(interval, 100);
730
731 let interval_from_height: BlockHeightInterval =
732 relative::NumberOfBlocks::from_count(10).into();
733 assert_eq!(interval_from_height.to_u32(), 10u32);
734
735 let invalid_height_greater =
736 relative::NumberOfBlocks::try_from(BlockHeightInterval(u32::from(u16::MAX) + 1));
737 assert!(invalid_height_greater.is_err());
738
739 let valid_height =
740 relative::NumberOfBlocks::try_from(BlockHeightInterval(u32::from(u16::MAX)));
741 assert!(valid_height.is_ok());
742 }
743
744 #[test]
746 fn all_available_ops() {
747 assert!(BlockHeight(10) - BlockHeight(7) == BlockHeightInterval(3));
749
750 assert!(BlockHeight(100) + BlockHeightInterval(1) == BlockHeight(101));
752
753 assert!(BlockHeight(100) - BlockHeightInterval(1) == BlockHeight(99));
755
756 assert!(BlockHeightInterval(1) + BlockHeightInterval(2) == BlockHeightInterval(3));
758
759 assert!(BlockHeightInterval(10) - BlockHeightInterval(7) == BlockHeightInterval(3));
761
762 assert!(
764 [BlockHeightInterval(1), BlockHeightInterval(2), BlockHeightInterval(3)]
765 .iter()
766 .sum::<BlockHeightInterval>()
767 == BlockHeightInterval(6)
768 );
769 assert!(
770 [BlockHeightInterval(4), BlockHeightInterval(5), BlockHeightInterval(6)]
771 .into_iter()
772 .sum::<BlockHeightInterval>()
773 == BlockHeightInterval(15)
774 );
775
776 assert!(
778 [BlockMtpInterval(1), BlockMtpInterval(2), BlockMtpInterval(3)]
779 .iter()
780 .sum::<BlockMtpInterval>()
781 == BlockMtpInterval(6)
782 );
783 assert!(
784 [BlockMtpInterval(4), BlockMtpInterval(5), BlockMtpInterval(6)]
785 .into_iter()
786 .sum::<BlockMtpInterval>()
787 == BlockMtpInterval(15)
788 );
789
790 let mut int = BlockHeightInterval(1);
792 int += BlockHeightInterval(2);
793 assert_eq!(int, BlockHeightInterval(3));
794
795 let mut int = BlockHeightInterval(10);
797 int -= BlockHeightInterval(7);
798 assert_eq!(int, BlockHeightInterval(3));
799 }
800
801 #[test]
802 fn block_height_checked() {
803 let a = BlockHeight(10);
804 let b = BlockHeight(5);
805 assert_eq!(a.checked_sub(b), Some(BlockHeightInterval(5)));
806 assert_eq!(a.checked_add(BlockHeightInterval(5)), Some(BlockHeight(15)));
807 assert_eq!(a.checked_sub(BlockHeight(11)), None);
808 assert_eq!(a.checked_add(BlockHeightInterval(u32::MAX - 5)), None);
809 }
810
811 #[test]
812 fn block_height_interval_checked() {
813 let a = BlockHeightInterval(10);
814 let b = BlockHeightInterval(5);
815 assert_eq!(a.checked_sub(b), Some(BlockHeightInterval(5)));
816 assert_eq!(a.checked_add(b), Some(BlockHeightInterval(15)));
817 assert_eq!(a.checked_sub(BlockHeightInterval(11)), None);
818 assert_eq!(a.checked_add(BlockHeightInterval(u32::MAX - 5)), None);
819 }
820
821 #[test]
822 fn block_mtp_interval_checked() {
823 let a = BlockMtpInterval(10);
824 let b = BlockMtpInterval(5);
825 assert_eq!(a.checked_sub(b), Some(BlockMtpInterval(5)));
826 assert_eq!(a.checked_add(b), Some(BlockMtpInterval(15)));
827 assert_eq!(a.checked_sub(BlockMtpInterval(11)), None);
828 assert_eq!(a.checked_add(BlockMtpInterval(u32::MAX - 5)), None);
829 }
830
831 #[test]
832 fn block_mtp_checked() {
833 let a = BlockMtp(10);
834 let b = BlockMtp(5);
835 assert_eq!(a.checked_sub(b), Some(BlockMtpInterval(5)));
836 assert_eq!(a.checked_add(BlockMtpInterval(5)), Some(BlockMtp(15)));
837 assert_eq!(a.checked_sub(BlockMtp(11)), None);
838 assert_eq!(a.checked_add(BlockMtpInterval(u32::MAX - 5)), None);
839 }
840
841 #[test]
842 fn block_mtp_interval_from_number_of_512seconds() {
843 let n = NumberOf512Seconds::from_seconds_floor(0).unwrap();
844 let interval = BlockMtpInterval::from(n);
845 assert_eq!(interval, BlockMtpInterval(0));
846 let n = NumberOf512Seconds::from_seconds_floor(1024).unwrap();
847 let interval = BlockMtpInterval::from(n);
848 assert_eq!(interval, BlockMtpInterval(1024));
849 }
850
851 #[test]
852 fn block_mtp_interval_to_relative_mtp_floor() {
853 let time = NumberOf512Seconds::from_512_second_intervals(0);
854 let interval = BlockMtpInterval::from_u32(0);
855 assert_eq!(interval.to_relative_mtp_interval_floor().unwrap(), time);
856
857 let time = NumberOf512Seconds::from_512_second_intervals(1);
858 let interval = BlockMtpInterval::from_u32(1023);
859 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);
864 let max_seconds = u32::from(u16::MAX) * 512 + 511;
865
866 let interval = BlockMtpInterval::from_u32(max_seconds);
867 assert_eq!(interval.to_relative_mtp_interval_floor().unwrap(), max_time);
868 let interval = BlockMtpInterval::from_u32(max_seconds + 1);
869 assert_eq!(
870 interval.to_relative_mtp_interval_floor().unwrap_err(),
871 TimeOverflowError { seconds: max_seconds + 1 }
872 );
873 }
874
875 #[test]
876 fn block_mtp_interval_to_relative_mtp_ceil() {
877 let time = NumberOf512Seconds::from_512_second_intervals(0);
878 let interval = BlockMtpInterval::from_u32(0);
879 assert_eq!(interval.to_relative_mtp_interval_ceil().unwrap(), time);
880
881 let time = NumberOf512Seconds::from_512_second_intervals(2);
882 let interval = BlockMtpInterval::from_u32(1023);
883 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);
888 let max_seconds = u32::from(u16::MAX) * 512;
889
890 let interval = BlockMtpInterval::from_u32(max_seconds);
891 assert_eq!(interval.to_relative_mtp_interval_ceil().unwrap(), max_time);
892 let interval = BlockMtpInterval::from_u32(max_seconds + 1);
893 assert_eq!(
894 interval.to_relative_mtp_interval_ceil().unwrap_err(),
895 TimeOverflowError { seconds: max_seconds + 1 }
896 );
897 }
898
899 #[test]
900 #[cfg(feature = "encoding")]
901 fn block_height_decoding_error() {
902 let bytes = [0xff, 0xff, 0xff]; let mut decoder = BlockHeightDecoder::default();
905 assert!(decoder.push_bytes(&mut bytes.as_slice()).unwrap().needs_more());
906
907 let error = decoder.end().unwrap_err();
908 assert!(matches!(error, BlockHeightDecoderError(UnexpectedEofError { .. })));
909 }
910
911 macro_rules! serde_roundtrip_test {
913 { $test_name:tt, $typ:ident } => {
914 #[test]
915 #[cfg(feature = "serde")]
916 fn $test_name() {
917 let t = $typ(1_654_321);
918
919 let json = serde_json::to_string(&t).unwrap();
920 assert_eq!(json, "1654321"); let roundtrip = serde_json::from_str::<$typ>(&json).unwrap();
923 assert_eq!(t, roundtrip);
924 }
925 }
926 }
927
928 serde_roundtrip_test!(block_height_serde_round_trip, BlockHeight);
929 serde_roundtrip_test!(block_height_interval_serde_round_trip, BlockHeightInterval);
930 serde_roundtrip_test!(block_mtp_serde_round_trip, BlockMtp);
931 serde_roundtrip_test!(block_mtp_interval_serde_round_trip, BlockMtpInterval);
932
933 #[test]
934 fn block_height_saturating_add() {
935 assert_eq!(BlockHeight(100).saturating_add(BlockHeightInterval(50)), BlockHeight(150),);
937 assert_eq!(BlockHeight::ZERO.saturating_add(BlockHeightInterval(1)), BlockHeight(1),);
938
939 assert_eq!(BlockHeight::MAX.saturating_add(BlockHeightInterval(1)), BlockHeight::MAX,);
941 assert_eq!(BlockHeight::MAX.saturating_add(BlockHeightInterval(100)), BlockHeight::MAX,);
942 assert_eq!(
943 BlockHeight(u32::MAX - 10).saturating_add(BlockHeightInterval(20)),
944 BlockHeight::MAX,
945 );
946
947 assert_eq!(BlockHeight(500).saturating_add(BlockHeightInterval::ZERO), BlockHeight(500),);
949 }
950
951 #[test]
952 fn block_height_saturating_sub() {
953 assert_eq!(BlockHeight(100).saturating_sub(BlockHeightInterval(50)), BlockHeight(50),);
955 assert_eq!(BlockHeight(100).saturating_sub(BlockHeightInterval(100)), BlockHeight(0),);
956
957 assert_eq!(BlockHeight::MIN.saturating_sub(BlockHeightInterval(1)), BlockHeight::MIN,);
959 assert_eq!(BlockHeight::ZERO.saturating_sub(BlockHeightInterval(100)), BlockHeight::ZERO,);
960 assert_eq!(BlockHeight(10).saturating_sub(BlockHeightInterval(20)), BlockHeight::ZERO,);
961
962 assert_eq!(BlockHeight(500).saturating_sub(BlockHeightInterval::ZERO), BlockHeight(500),);
964 }
965
966 #[test]
967 #[cfg(feature = "alloc")]
968 fn error_display_is_non_empty() {
969 let big_interval = BlockHeightInterval::from_u32(u32::MAX);
971 let e = relative::NumberOfBlocks::try_from(big_interval).unwrap_err();
972 assert!(!e.to_string().is_empty());
973 #[cfg(feature = "std")]
974 assert!(e.source().is_none());
975
976 #[cfg(feature = "encoding")]
977 {
978 let mut decoder = BlockHeight::decoder();
980 let _ = decoder.push_bytes(&mut [0u8; 3].as_slice());
981 let e = decoder.end().unwrap_err();
982 assert!(!e.to_string().is_empty());
983 #[cfg(feature = "std")]
984 assert!(e.source().is_some());
985 }
986 }
987}