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)> { None }
661 }
662
663 #[cfg(feature = "encoding")]
665 #[derive(Debug, Clone, PartialEq, Eq)]
666 pub struct BlockHeightDecoderError(pub(super) encoding::UnexpectedEofError);
667
668 #[cfg(feature = "encoding")]
669 impl From<Infallible> for BlockHeightDecoderError {
670 fn from(never: Infallible) -> Self { match never {} }
671 }
672
673 #[cfg(feature = "encoding")]
674 impl fmt::Display for BlockHeightDecoderError {
675 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
676 write_err!(f, "block height decoder error"; self.0)
677 }
678 }
679
680 #[cfg(feature = "encoding")]
681 #[cfg(feature = "std")]
682 impl std::error::Error for BlockHeightDecoderError {
683 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { Some(&self.0) }
684 }
685}
686
687#[cfg(test)]
688mod tests {
689 #[cfg(feature = "alloc")]
690 use alloc::string::ToString;
691 #[cfg(feature = "std")]
692 use std::error::Error;
693
694 #[cfg(feature = "encoding")]
695 use encoding::{Decode as _, Decoder as _, UnexpectedEofError};
696
697 use super::*;
698 use crate::relative::{NumberOf512Seconds, TimeOverflowError};
699
700 #[test]
701 fn sanity_check() {
702 let height: u32 = BlockHeight(100).into();
703 assert_eq!(height, 100);
704
705 let interval: u32 = BlockHeightInterval(100).into();
706 assert_eq!(interval, 100);
707
708 let interval_from_height: BlockHeightInterval =
709 relative::NumberOfBlocks::from(10u16).into();
710 assert_eq!(interval_from_height.to_u32(), 10u32);
711
712 let invalid_height_greater =
713 relative::NumberOfBlocks::try_from(BlockHeightInterval(u32::from(u16::MAX) + 1));
714 assert!(invalid_height_greater.is_err());
715
716 let valid_height =
717 relative::NumberOfBlocks::try_from(BlockHeightInterval(u32::from(u16::MAX)));
718 assert!(valid_height.is_ok());
719 }
720
721 #[test]
723 fn all_available_ops() {
724 assert!(BlockHeight(10) - BlockHeight(7) == BlockHeightInterval(3));
726
727 assert!(BlockHeight(100) + BlockHeightInterval(1) == BlockHeight(101));
729
730 assert!(BlockHeight(100) - BlockHeightInterval(1) == BlockHeight(99));
732
733 assert!(BlockHeightInterval(1) + BlockHeightInterval(2) == BlockHeightInterval(3));
735
736 assert!(BlockHeightInterval(10) - BlockHeightInterval(7) == BlockHeightInterval(3));
738
739 assert!(
741 [BlockHeightInterval(1), BlockHeightInterval(2), BlockHeightInterval(3)]
742 .iter()
743 .sum::<BlockHeightInterval>()
744 == BlockHeightInterval(6)
745 );
746 assert!(
747 [BlockHeightInterval(4), BlockHeightInterval(5), BlockHeightInterval(6)]
748 .into_iter()
749 .sum::<BlockHeightInterval>()
750 == BlockHeightInterval(15)
751 );
752
753 assert!(
755 [BlockMtpInterval(1), BlockMtpInterval(2), BlockMtpInterval(3)]
756 .iter()
757 .sum::<BlockMtpInterval>()
758 == BlockMtpInterval(6)
759 );
760 assert!(
761 [BlockMtpInterval(4), BlockMtpInterval(5), BlockMtpInterval(6)]
762 .into_iter()
763 .sum::<BlockMtpInterval>()
764 == BlockMtpInterval(15)
765 );
766
767 let mut int = BlockHeightInterval(1);
769 int += BlockHeightInterval(2);
770 assert_eq!(int, BlockHeightInterval(3));
771
772 let mut int = BlockHeightInterval(10);
774 int -= BlockHeightInterval(7);
775 assert_eq!(int, BlockHeightInterval(3));
776 }
777
778 #[test]
779 fn block_height_checked() {
780 let a = BlockHeight(10);
781 let b = BlockHeight(5);
782 assert_eq!(a.checked_sub(b), Some(BlockHeightInterval(5)));
783 assert_eq!(a.checked_add(BlockHeightInterval(5)), Some(BlockHeight(15)));
784 assert_eq!(a.checked_sub(BlockHeight(11)), None);
785 assert_eq!(a.checked_add(BlockHeightInterval(u32::MAX - 5)), None);
786 }
787
788 #[test]
789 fn block_height_interval_checked() {
790 let a = BlockHeightInterval(10);
791 let b = BlockHeightInterval(5);
792 assert_eq!(a.checked_sub(b), Some(BlockHeightInterval(5)));
793 assert_eq!(a.checked_add(b), Some(BlockHeightInterval(15)));
794 assert_eq!(a.checked_sub(BlockHeightInterval(11)), None);
795 assert_eq!(a.checked_add(BlockHeightInterval(u32::MAX - 5)), None);
796 }
797
798 #[test]
799 fn block_mtp_interval_checked() {
800 let a = BlockMtpInterval(10);
801 let b = BlockMtpInterval(5);
802 assert_eq!(a.checked_sub(b), Some(BlockMtpInterval(5)));
803 assert_eq!(a.checked_add(b), Some(BlockMtpInterval(15)));
804 assert_eq!(a.checked_sub(BlockMtpInterval(11)), None);
805 assert_eq!(a.checked_add(BlockMtpInterval(u32::MAX - 5)), None);
806 }
807
808 #[test]
809 fn block_mtp_checked() {
810 let a = BlockMtp(10);
811 let b = BlockMtp(5);
812 assert_eq!(a.checked_sub(b), Some(BlockMtpInterval(5)));
813 assert_eq!(a.checked_add(BlockMtpInterval(5)), Some(BlockMtp(15)));
814 assert_eq!(a.checked_sub(BlockMtp(11)), None);
815 assert_eq!(a.checked_add(BlockMtpInterval(u32::MAX - 5)), None);
816 }
817
818 #[test]
819 fn block_mtp_interval_from_number_of_512seconds() {
820 let n = NumberOf512Seconds::from_seconds_floor(0).unwrap();
821 let interval = BlockMtpInterval::from(n);
822 assert_eq!(interval, BlockMtpInterval(0));
823 let n = NumberOf512Seconds::from_seconds_floor(1024).unwrap();
824 let interval = BlockMtpInterval::from(n);
825 assert_eq!(interval, BlockMtpInterval(1024));
826 }
827
828 #[test]
829 fn block_mtp_interval_to_relative_mtp_floor() {
830 let time = NumberOf512Seconds::from_512_second_intervals(0);
831 let interval = BlockMtpInterval::from_u32(0);
832 assert_eq!(interval.to_relative_mtp_interval_floor().unwrap(), time);
833
834 let time = NumberOf512Seconds::from_512_second_intervals(1);
835 let interval = BlockMtpInterval::from_u32(1023);
836 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);
841 let max_seconds = u32::from(u16::MAX) * 512 + 511;
842
843 let interval = BlockMtpInterval::from_u32(max_seconds);
844 assert_eq!(interval.to_relative_mtp_interval_floor().unwrap(), max_time);
845 let interval = BlockMtpInterval::from_u32(max_seconds + 1);
846 assert_eq!(
847 interval.to_relative_mtp_interval_floor().unwrap_err(),
848 TimeOverflowError { seconds: max_seconds + 1 }
849 );
850 }
851
852 #[test]
853 fn block_mtp_interval_to_relative_mtp_ceil() {
854 let time = NumberOf512Seconds::from_512_second_intervals(0);
855 let interval = BlockMtpInterval::from_u32(0);
856 assert_eq!(interval.to_relative_mtp_interval_ceil().unwrap(), time);
857
858 let time = NumberOf512Seconds::from_512_second_intervals(2);
859 let interval = BlockMtpInterval::from_u32(1023);
860 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);
865 let max_seconds = u32::from(u16::MAX) * 512;
866
867 let interval = BlockMtpInterval::from_u32(max_seconds);
868 assert_eq!(interval.to_relative_mtp_interval_ceil().unwrap(), max_time);
869 let interval = BlockMtpInterval::from_u32(max_seconds + 1);
870 assert_eq!(
871 interval.to_relative_mtp_interval_ceil().unwrap_err(),
872 TimeOverflowError { seconds: max_seconds + 1 }
873 );
874 }
875
876 #[test]
877 #[cfg(feature = "encoding")]
878 fn block_height_decoding_error() {
879 let bytes = [0xff, 0xff, 0xff]; let mut decoder = BlockHeightDecoder::default();
882 assert!(decoder.push_bytes(&mut bytes.as_slice()).unwrap().needs_more());
883
884 let error = decoder.end().unwrap_err();
885 assert!(matches!(error, BlockHeightDecoderError(UnexpectedEofError { .. })));
886 }
887
888 macro_rules! serde_roundtrip_test {
890 { $test_name:tt, $typ:ident } => {
891 #[test]
892 #[cfg(feature = "serde")]
893 fn $test_name() {
894 let t = $typ(1_654_321);
895
896 let json = serde_json::to_string(&t).unwrap();
897 assert_eq!(json, "1654321"); let roundtrip = serde_json::from_str::<$typ>(&json).unwrap();
900 assert_eq!(t, roundtrip);
901 }
902 }
903 }
904
905 serde_roundtrip_test!(block_height_serde_round_trip, BlockHeight);
906 serde_roundtrip_test!(block_height_interval_serde_round_trip, BlockHeightInterval);
907 serde_roundtrip_test!(block_mtp_serde_round_trip, BlockMtp);
908 serde_roundtrip_test!(block_mtp_interval_serde_round_trip, BlockMtpInterval);
909
910 #[test]
911 fn block_height_saturating_add() {
912 assert_eq!(BlockHeight(100).saturating_add(BlockHeightInterval(50)), BlockHeight(150),);
914 assert_eq!(BlockHeight::ZERO.saturating_add(BlockHeightInterval(1)), BlockHeight(1),);
915
916 assert_eq!(BlockHeight::MAX.saturating_add(BlockHeightInterval(1)), BlockHeight::MAX,);
918 assert_eq!(BlockHeight::MAX.saturating_add(BlockHeightInterval(100)), BlockHeight::MAX,);
919 assert_eq!(
920 BlockHeight(u32::MAX - 10).saturating_add(BlockHeightInterval(20)),
921 BlockHeight::MAX,
922 );
923
924 assert_eq!(BlockHeight(500).saturating_add(BlockHeightInterval::ZERO), BlockHeight(500),);
926 }
927
928 #[test]
929 fn block_height_saturating_sub() {
930 assert_eq!(BlockHeight(100).saturating_sub(BlockHeightInterval(50)), BlockHeight(50),);
932 assert_eq!(BlockHeight(100).saturating_sub(BlockHeightInterval(100)), BlockHeight(0),);
933
934 assert_eq!(BlockHeight::MIN.saturating_sub(BlockHeightInterval(1)), BlockHeight::MIN,);
936 assert_eq!(BlockHeight::ZERO.saturating_sub(BlockHeightInterval(100)), BlockHeight::ZERO,);
937 assert_eq!(BlockHeight(10).saturating_sub(BlockHeightInterval(20)), BlockHeight::ZERO,);
938
939 assert_eq!(BlockHeight(500).saturating_sub(BlockHeightInterval::ZERO), BlockHeight(500),);
941 }
942
943 #[test]
944 #[cfg(feature = "alloc")]
945 fn error_display_is_non_empty() {
946 let big_interval = BlockHeightInterval::from_u32(u32::MAX);
948 let e = relative::NumberOfBlocks::try_from(big_interval).unwrap_err();
949 assert!(!e.to_string().is_empty());
950 #[cfg(feature = "std")]
951 assert!(e.source().is_none());
952
953 #[cfg(feature = "encoding")]
954 {
955 let mut decoder = BlockHeight::decoder();
957 let _ = decoder.push_bytes(&mut [0u8; 3].as_slice());
958 let e = decoder.end().unwrap_err();
959 assert!(!e.to_string().is_empty());
960 #[cfg(feature = "std")]
961 assert!(e.source().is_some());
962 }
963 }
964}