1#[cfg(feature = "encoding")]
15use core::convert::Infallible;
16use core::{fmt, ops};
17
18#[cfg(feature = "arbitrary")]
19use arbitrary::{Arbitrary, Unstructured};
20#[cfg(feature = "encoding")]
21use internals::write_err;
22#[cfg(feature = "serde")]
23use serde::{Deserialize, Deserializer, Serialize, Serializer};
24
25#[cfg(doc)]
26use crate::locktime;
27use crate::locktime::{absolute, relative};
28
29macro_rules! impl_u32_wrapper {
30 {
31 $(#[$($type_attrs:tt)*])*
32 $type_vis:vis struct $newtype:ident($inner_vis:vis u32);
33 } => {
34 $(#[$($type_attrs)*])*
35 $type_vis struct $newtype($inner_vis u32);
36
37 impl fmt::Display for $newtype {
38 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
39 }
40
41 crate::parse_int::impl_parse_str_from_int_infallible!($newtype, u32, from);
42
43 impl From<u32> for $newtype {
44 fn from(inner: u32) -> Self { Self::from_u32(inner) }
45 }
46
47 impl From<$newtype> for u32 {
48 fn from(height: $newtype) -> Self { height.to_u32() }
49 }
50
51 #[cfg(feature = "serde")]
52 impl Serialize for $newtype {
53 #[inline]
54 fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
55 where
56 S: Serializer,
57 {
58 u32::serialize(&self.to_u32(), s)
59 }
60 }
61
62 #[cfg(feature = "serde")]
63 impl<'de> Deserialize<'de> for $newtype {
64 #[inline]
65 fn deserialize<D>(d: D) -> Result<Self, D::Error>
66 where
67 D: Deserializer<'de>,
68 {
69 Ok(Self::from_u32(u32::deserialize(d)?))
70 }
71 }
72
73 #[cfg(feature = "arbitrary")]
74 impl<'a> Arbitrary<'a> for $newtype {
75 fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
76 let choice = u.int_in_range(0..=2)?;
77 match choice {
78 0 => Ok(Self::ZERO),
79 1 => Ok(Self::MIN),
80 2 => Ok(Self::MAX),
81 _ => Ok(Self::from_u32(u32::arbitrary(u)?)),
82 }
83 }
84 }
85 }
86}
87
88impl_u32_wrapper! {
89 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
96 pub struct BlockHeight(u32);
97}
98
99impl BlockHeight {
100 pub const ZERO: Self = Self(0);
102
103 pub const MIN: Self = Self::ZERO;
105
106 pub const MAX: Self = Self(u32::MAX);
108
109 pub const fn from_u32(inner: u32) -> Self { Self(inner) }
111
112 pub const fn to_u32(self) -> u32 { self.0 }
114
115 #[must_use]
117 pub fn checked_sub(self, other: Self) -> Option<BlockHeightInterval> {
118 self.to_u32().checked_sub(other.to_u32()).map(BlockHeightInterval)
119 }
120
121 #[must_use]
123 pub fn checked_add(self, other: BlockHeightInterval) -> Option<Self> {
124 self.to_u32().checked_add(other.to_u32()).map(Self)
125 }
126
127 #[inline]
131 #[must_use]
132 pub const fn saturating_add(self, rhs: BlockHeightInterval) -> Self {
133 Self::from_u32(self.to_u32().saturating_add(rhs.to_u32()))
134 }
135
136 #[inline]
140 #[must_use]
141 pub const fn saturating_sub(self, rhs: BlockHeightInterval) -> Self {
142 Self::from_u32(self.to_u32().saturating_sub(rhs.to_u32()))
143 }
144}
145
146crate::internal_macros::impl_fmt_traits_for_u32_wrapper!(BlockHeight);
147
148impl From<absolute::Height> for BlockHeight {
149 fn from(h: absolute::Height) -> Self { Self::from_u32(h.to_u32()) }
154}
155
156impl TryFrom<BlockHeight> for absolute::Height {
157 type Error = absolute::ConversionError;
158
159 fn try_from(h: BlockHeight) -> Result<Self, Self::Error> { Self::from_u32(h.to_u32()) }
164}
165
166#[cfg(feature = "encoding")]
167encoding::encoder_newtype_exact! {
168 pub struct BlockHeightEncoder<'e>(encoding::ArrayEncoder<4>);
170}
171
172#[cfg(feature = "encoding")]
173impl encoding::Encodable for BlockHeight {
174 type Encoder<'e> = BlockHeightEncoder<'e>;
175 fn encoder(&self) -> Self::Encoder<'_> {
176 BlockHeightEncoder::new(encoding::ArrayEncoder::without_length_prefix(
177 self.to_u32().to_le_bytes(),
178 ))
179 }
180}
181
182#[cfg(feature = "encoding")]
184pub struct BlockHeightDecoder(encoding::ArrayDecoder<4>);
185
186#[cfg(feature = "encoding")]
187impl Default for BlockHeightDecoder {
188 fn default() -> Self { Self::new() }
189}
190
191#[cfg(feature = "encoding")]
192impl BlockHeightDecoder {
193 pub const fn new() -> Self { Self(encoding::ArrayDecoder::new()) }
195}
196
197#[cfg(feature = "encoding")]
198impl encoding::Decoder for BlockHeightDecoder {
199 type Output = BlockHeight;
200 type Error = BlockHeightDecoderError;
201
202 #[inline]
203 fn push_bytes(&mut self, bytes: &mut &[u8]) -> Result<bool, Self::Error> {
204 self.0.push_bytes(bytes).map_err(BlockHeightDecoderError)
205 }
206
207 #[inline]
208 fn end(self) -> Result<Self::Output, Self::Error> {
209 let n = u32::from_le_bytes(self.0.end().map_err(BlockHeightDecoderError)?);
210 Ok(BlockHeight::from_u32(n))
211 }
212
213 #[inline]
214 fn read_limit(&self) -> usize { self.0.read_limit() }
215}
216
217#[cfg(feature = "encoding")]
218impl encoding::Decodable for BlockHeight {
219 type Decoder = BlockHeightDecoder;
220 fn decoder() -> Self::Decoder { BlockHeightDecoder(encoding::ArrayDecoder::<4>::new()) }
221}
222
223#[cfg(feature = "encoding")]
225#[derive(Debug, Clone, PartialEq, Eq)]
226pub struct BlockHeightDecoderError(encoding::UnexpectedEofError);
227
228#[cfg(feature = "encoding")]
229impl From<Infallible> for BlockHeightDecoderError {
230 fn from(never: Infallible) -> Self { match never {} }
231}
232
233#[cfg(feature = "encoding")]
234impl fmt::Display for BlockHeightDecoderError {
235 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
236 write_err!(f, "block height decoder error"; self.0)
237 }
238}
239
240#[cfg(all(feature = "std", feature = "encoding"))]
241impl std::error::Error for BlockHeightDecoderError {
242 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { Some(&self.0) }
243}
244
245impl_u32_wrapper! {
246 #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
253 pub struct BlockHeightInterval(u32);
254}
255
256impl BlockHeightInterval {
257 pub const ZERO: Self = Self(0);
259
260 pub const MIN: Self = Self::ZERO;
262
263 pub const MAX: Self = Self(u32::MAX);
265
266 pub const fn from_u32(inner: u32) -> Self { Self(inner) }
268
269 pub const fn to_u32(self) -> u32 { self.0 }
271
272 #[must_use]
274 pub fn checked_sub(self, other: Self) -> Option<Self> {
275 self.to_u32().checked_sub(other.to_u32()).map(Self)
276 }
277
278 #[must_use]
280 pub fn checked_add(self, other: Self) -> Option<Self> {
281 self.to_u32().checked_add(other.to_u32()).map(Self)
282 }
283}
284
285crate::internal_macros::impl_fmt_traits_for_u32_wrapper!(BlockHeightInterval);
286
287impl From<relative::NumberOfBlocks> for BlockHeightInterval {
288 fn from(h: relative::NumberOfBlocks) -> Self { Self::from_u32(h.to_height().into()) }
293}
294
295impl TryFrom<BlockHeightInterval> for relative::NumberOfBlocks {
296 type Error = TooBigForRelativeHeightError;
297
298 fn try_from(h: BlockHeightInterval) -> Result<Self, Self::Error> {
303 u16::try_from(h.to_u32())
304 .map(Self::from)
305 .map_err(|_| TooBigForRelativeHeightError(h.into()))
306 }
307}
308
309impl_u32_wrapper! {
310 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
317 pub struct BlockMtp(u32);
318}
319
320impl BlockMtp {
321 pub const ZERO: Self = Self(0);
326
327 pub const MIN: Self = Self::ZERO;
329
330 pub const MAX: Self = Self(u32::MAX);
332
333 pub const fn from_u32(inner: u32) -> Self { Self(inner) }
335
336 pub const fn to_u32(self) -> u32 { self.0 }
338
339 pub fn new(mut timestamps: [crate::BlockTime; 11]) -> Self {
345 timestamps.sort_unstable();
346 Self::from_u32(u32::from(timestamps[5]))
347 }
348
349 #[must_use]
351 pub fn checked_sub(self, other: Self) -> Option<BlockMtpInterval> {
352 self.to_u32().checked_sub(other.to_u32()).map(BlockMtpInterval)
353 }
354
355 #[must_use]
357 pub fn checked_add(self, other: BlockMtpInterval) -> Option<Self> {
358 self.to_u32().checked_add(other.to_u32()).map(Self)
359 }
360}
361
362crate::internal_macros::impl_fmt_traits_for_u32_wrapper!(BlockMtp);
363
364impl From<absolute::MedianTimePast> for BlockMtp {
365 fn from(h: absolute::MedianTimePast) -> Self { Self::from_u32(h.to_u32()) }
370}
371
372impl TryFrom<BlockMtp> for absolute::MedianTimePast {
373 type Error = absolute::ConversionError;
374
375 fn try_from(h: BlockMtp) -> Result<Self, Self::Error> { Self::from_u32(h.to_u32()) }
380}
381
382impl_u32_wrapper! {
383 #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
390 pub struct BlockMtpInterval(u32);
391}
392
393impl BlockMtpInterval {
394 pub const ZERO: Self = Self(0);
396
397 pub const MIN: Self = Self::ZERO;
399
400 pub const MAX: Self = Self(u32::MAX);
402
403 pub const fn from_u32(inner: u32) -> Self { Self(inner) }
405
406 pub const fn to_u32(self) -> u32 { self.0 }
408
409 #[inline]
419 pub const fn to_relative_mtp_interval_floor(
420 self,
421 ) -> Result<relative::NumberOf512Seconds, relative::TimeOverflowError> {
422 relative::NumberOf512Seconds::from_seconds_floor(self.to_u32())
423 }
424
425 #[inline]
435 pub const fn to_relative_mtp_interval_ceil(
436 self,
437 ) -> Result<relative::NumberOf512Seconds, relative::TimeOverflowError> {
438 relative::NumberOf512Seconds::from_seconds_ceil(self.to_u32())
439 }
440
441 #[must_use]
443 pub fn checked_sub(self, other: Self) -> Option<Self> {
444 self.to_u32().checked_sub(other.to_u32()).map(Self)
445 }
446
447 #[must_use]
449 pub fn checked_add(self, other: Self) -> Option<Self> {
450 self.to_u32().checked_add(other.to_u32()).map(Self)
451 }
452}
453
454crate::internal_macros::impl_fmt_traits_for_u32_wrapper!(BlockMtpInterval);
455
456impl From<relative::NumberOf512Seconds> for BlockMtpInterval {
457 fn from(h: relative::NumberOf512Seconds) -> Self { Self::from_u32(h.to_seconds()) }
463}
464
465#[derive(Debug, Clone, PartialEq, Eq)]
467pub struct TooBigForRelativeHeightError(u32);
468
469impl fmt::Display for TooBigForRelativeHeightError {
470 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
471 write!(
472 f,
473 "block interval is too big to be used as a relative lock time: {} (max: {})",
474 self.0,
475 relative::NumberOfBlocks::MAX
476 )
477 }
478}
479
480#[cfg(feature = "std")]
481impl std::error::Error for TooBigForRelativeHeightError {}
482
483crate::internal_macros::impl_op_for_references! {
484 impl ops::Sub<BlockHeight> for BlockHeight {
486 type Output = BlockHeightInterval;
487
488 fn sub(self, rhs: BlockHeight) -> Self::Output {
489 let interval = self.to_u32() - rhs.to_u32();
490 BlockHeightInterval::from_u32(interval)
491 }
492 }
493
494 impl ops::Add<BlockHeightInterval> for BlockHeight {
496 type Output = BlockHeight;
497
498 fn add(self, rhs: BlockHeightInterval) -> Self::Output {
499 let height = self.to_u32() + rhs.to_u32();
500 BlockHeight::from_u32(height)
501 }
502 }
503
504 impl ops::Sub<BlockHeightInterval> for BlockHeight {
506 type Output = BlockHeight;
507
508 fn sub(self, rhs: BlockHeightInterval) -> Self::Output {
509 let height = self.to_u32() - rhs.to_u32();
510 BlockHeight::from_u32(height)
511 }
512 }
513
514 impl ops::Add<BlockHeightInterval> for BlockHeightInterval {
516 type Output = BlockHeightInterval;
517
518 fn add(self, rhs: BlockHeightInterval) -> Self::Output {
519 let height = self.to_u32() + rhs.to_u32();
520 BlockHeightInterval::from_u32(height)
521 }
522 }
523
524 impl ops::Sub<BlockHeightInterval> for BlockHeightInterval {
526 type Output = BlockHeightInterval;
527
528 fn sub(self, rhs: BlockHeightInterval) -> Self::Output {
529 let height = self.to_u32() - rhs.to_u32();
530 BlockHeightInterval::from_u32(height)
531 }
532 }
533
534 impl ops::Sub<BlockMtp> for BlockMtp {
536 type Output = BlockMtpInterval;
537
538 fn sub(self, rhs: BlockMtp) -> Self::Output {
539 let interval = self.to_u32() - rhs.to_u32();
540 BlockMtpInterval::from_u32(interval)
541 }
542 }
543
544 impl ops::Add<BlockMtpInterval> for BlockMtp {
546 type Output = BlockMtp;
547
548 fn add(self, rhs: BlockMtpInterval) -> Self::Output {
549 let height = self.to_u32() + rhs.to_u32();
550 BlockMtp::from_u32(height)
551 }
552 }
553
554 impl ops::Sub<BlockMtpInterval> for BlockMtp {
556 type Output = BlockMtp;
557
558 fn sub(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::Add<BlockMtpInterval> for BlockMtpInterval {
566 type Output = BlockMtpInterval;
567
568 fn add(self, rhs: BlockMtpInterval) -> Self::Output {
569 let height = self.to_u32() + rhs.to_u32();
570 BlockMtpInterval::from_u32(height)
571 }
572 }
573
574 impl ops::Sub<BlockMtpInterval> for BlockMtpInterval {
576 type Output = BlockMtpInterval;
577
578 fn sub(self, rhs: BlockMtpInterval) -> Self::Output {
579 let height = self.to_u32() - rhs.to_u32();
580 BlockMtpInterval::from_u32(height)
581 }
582 }
583}
584
585crate::internal_macros::impl_add_assign!(BlockHeightInterval);
586crate::internal_macros::impl_sub_assign!(BlockHeightInterval);
587crate::internal_macros::impl_add_assign!(BlockMtpInterval);
588crate::internal_macros::impl_sub_assign!(BlockMtpInterval);
589
590impl core::iter::Sum for BlockHeightInterval {
591 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
592 let sum = iter.map(Self::to_u32).sum();
593 Self::from_u32(sum)
594 }
595}
596
597impl<'a> core::iter::Sum<&'a Self> for BlockHeightInterval {
598 fn sum<I>(iter: I) -> Self
599 where
600 I: Iterator<Item = &'a Self>,
601 {
602 let sum = iter.map(|interval| interval.to_u32()).sum();
603 Self::from_u32(sum)
604 }
605}
606
607impl core::iter::Sum for BlockMtpInterval {
608 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
609 let sum = iter.map(Self::to_u32).sum();
610 Self::from_u32(sum)
611 }
612}
613
614impl<'a> core::iter::Sum<&'a Self> for BlockMtpInterval {
615 fn sum<I>(iter: I) -> Self
616 where
617 I: Iterator<Item = &'a Self>,
618 {
619 let sum = iter.map(|interval| interval.to_u32()).sum();
620 Self::from_u32(sum)
621 }
622}
623
624#[cfg(test)]
625mod tests {
626 #[cfg(feature = "encoding")]
627 use encoding::{Decoder as _, UnexpectedEofError};
628
629 use super::*;
630 use crate::relative::{NumberOf512Seconds, TimeOverflowError};
631
632 #[test]
633 fn sanity_check() {
634 let height: u32 = BlockHeight(100).into();
635 assert_eq!(height, 100);
636
637 let interval: u32 = BlockHeightInterval(100).into();
638 assert_eq!(interval, 100);
639
640 let interval_from_height: BlockHeightInterval =
641 relative::NumberOfBlocks::from(10u16).into();
642 assert_eq!(interval_from_height.to_u32(), 10u32);
643
644 let invalid_height_greater =
645 relative::NumberOfBlocks::try_from(BlockHeightInterval(u32::from(u16::MAX) + 1));
646 assert!(invalid_height_greater.is_err());
647
648 let valid_height =
649 relative::NumberOfBlocks::try_from(BlockHeightInterval(u32::from(u16::MAX)));
650 assert!(valid_height.is_ok());
651 }
652
653 #[test]
655 fn all_available_ops() {
656 assert!(BlockHeight(10) - BlockHeight(7) == BlockHeightInterval(3));
658
659 assert!(BlockHeight(100) + BlockHeightInterval(1) == BlockHeight(101));
661
662 assert!(BlockHeight(100) - BlockHeightInterval(1) == BlockHeight(99));
664
665 assert!(BlockHeightInterval(1) + BlockHeightInterval(2) == BlockHeightInterval(3));
667
668 assert!(BlockHeightInterval(10) - BlockHeightInterval(7) == BlockHeightInterval(3));
670
671 assert!(
673 [BlockHeightInterval(1), BlockHeightInterval(2), BlockHeightInterval(3)]
674 .iter()
675 .sum::<BlockHeightInterval>()
676 == BlockHeightInterval(6)
677 );
678 assert!(
679 [BlockHeightInterval(4), BlockHeightInterval(5), BlockHeightInterval(6)]
680 .into_iter()
681 .sum::<BlockHeightInterval>()
682 == BlockHeightInterval(15)
683 );
684
685 assert!(
687 [BlockMtpInterval(1), BlockMtpInterval(2), BlockMtpInterval(3)]
688 .iter()
689 .sum::<BlockMtpInterval>()
690 == BlockMtpInterval(6)
691 );
692 assert!(
693 [BlockMtpInterval(4), BlockMtpInterval(5), BlockMtpInterval(6)]
694 .into_iter()
695 .sum::<BlockMtpInterval>()
696 == BlockMtpInterval(15)
697 );
698
699 let mut int = BlockHeightInterval(1);
701 int += BlockHeightInterval(2);
702 assert_eq!(int, BlockHeightInterval(3));
703
704 let mut int = BlockHeightInterval(10);
706 int -= BlockHeightInterval(7);
707 assert_eq!(int, BlockHeightInterval(3));
708 }
709
710 #[test]
711 fn block_height_checked() {
712 let a = BlockHeight(10);
713 let b = BlockHeight(5);
714 assert_eq!(a.checked_sub(b), Some(BlockHeightInterval(5)));
715 assert_eq!(a.checked_add(BlockHeightInterval(5)), Some(BlockHeight(15)));
716 assert_eq!(a.checked_sub(BlockHeight(11)), None);
717 assert_eq!(a.checked_add(BlockHeightInterval(u32::MAX - 5)), None);
718 }
719
720 #[test]
721 fn block_height_interval_checked() {
722 let a = BlockHeightInterval(10);
723 let b = BlockHeightInterval(5);
724 assert_eq!(a.checked_sub(b), Some(BlockHeightInterval(5)));
725 assert_eq!(a.checked_add(b), Some(BlockHeightInterval(15)));
726 assert_eq!(a.checked_sub(BlockHeightInterval(11)), None);
727 assert_eq!(a.checked_add(BlockHeightInterval(u32::MAX - 5)), None);
728 }
729
730 #[test]
731 fn block_mtp_interval_checked() {
732 let a = BlockMtpInterval(10);
733 let b = BlockMtpInterval(5);
734 assert_eq!(a.checked_sub(b), Some(BlockMtpInterval(5)));
735 assert_eq!(a.checked_add(b), Some(BlockMtpInterval(15)));
736 assert_eq!(a.checked_sub(BlockMtpInterval(11)), None);
737 assert_eq!(a.checked_add(BlockMtpInterval(u32::MAX - 5)), None);
738 }
739
740 #[test]
741 fn block_mtp_checked() {
742 let a = BlockMtp(10);
743 let b = BlockMtp(5);
744 assert_eq!(a.checked_sub(b), Some(BlockMtpInterval(5)));
745 assert_eq!(a.checked_add(BlockMtpInterval(5)), Some(BlockMtp(15)));
746 assert_eq!(a.checked_sub(BlockMtp(11)), None);
747 assert_eq!(a.checked_add(BlockMtpInterval(u32::MAX - 5)), None);
748 }
749
750 #[test]
751 fn block_mtp_interval_from_number_of_512seconds() {
752 let n = NumberOf512Seconds::from_seconds_floor(0).unwrap();
753 let interval = BlockMtpInterval::from(n);
754 assert_eq!(interval, BlockMtpInterval(0));
755 let n = NumberOf512Seconds::from_seconds_floor(1024).unwrap();
756 let interval = BlockMtpInterval::from(n);
757 assert_eq!(interval, BlockMtpInterval(1024));
758 }
759
760 #[test]
761 fn block_mtp_interval_to_relative_mtp_floor() {
762 let time = NumberOf512Seconds::from_512_second_intervals(0);
763 let interval = BlockMtpInterval::from_u32(0);
764 assert_eq!(interval.to_relative_mtp_interval_floor().unwrap(), time);
765
766 let time = NumberOf512Seconds::from_512_second_intervals(1);
767 let interval = BlockMtpInterval::from_u32(1023);
768 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);
773 let max_seconds = u32::from(u16::MAX) * 512 + 511;
774
775 let interval = BlockMtpInterval::from_u32(max_seconds);
776 assert_eq!(interval.to_relative_mtp_interval_floor().unwrap(), max_time);
777 let interval = BlockMtpInterval::from_u32(max_seconds + 1);
778 assert_eq!(
779 interval.to_relative_mtp_interval_floor().unwrap_err(),
780 TimeOverflowError { seconds: max_seconds + 1 }
781 );
782 }
783
784 #[test]
785 fn block_mtp_interval_to_relative_mtp_ceil() {
786 let time = NumberOf512Seconds::from_512_second_intervals(0);
787 let interval = BlockMtpInterval::from_u32(0);
788 assert_eq!(interval.to_relative_mtp_interval_ceil().unwrap(), time);
789
790 let time = NumberOf512Seconds::from_512_second_intervals(2);
791 let interval = BlockMtpInterval::from_u32(1023);
792 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);
797 let max_seconds = u32::from(u16::MAX) * 512;
798
799 let interval = BlockMtpInterval::from_u32(max_seconds);
800 assert_eq!(interval.to_relative_mtp_interval_ceil().unwrap(), max_time);
801 let interval = BlockMtpInterval::from_u32(max_seconds + 1);
802 assert_eq!(
803 interval.to_relative_mtp_interval_ceil().unwrap_err(),
804 TimeOverflowError { seconds: max_seconds + 1 }
805 );
806 }
807
808 #[test]
809 #[cfg(feature = "encoding")]
810 fn block_height_decoding_error() {
811 let bytes = [0xff, 0xff, 0xff]; let mut decoder = BlockHeightDecoder::default();
814 assert!(decoder.push_bytes(&mut bytes.as_slice()).unwrap());
815
816 let error = decoder.end().unwrap_err();
817 assert!(matches!(error, BlockHeightDecoderError(UnexpectedEofError { .. })));
818 }
819
820 macro_rules! serde_roundtrip_test {
822 { $test_name:tt, $typ:ident } => {
823 #[test]
824 #[cfg(feature = "serde")]
825 fn $test_name() {
826 let t = $typ(1_654_321);
827
828 let json = serde_json::to_string(&t).unwrap();
829 assert_eq!(json, "1654321"); let roundtrip = serde_json::from_str::<$typ>(&json).unwrap();
832 assert_eq!(t, roundtrip);
833 }
834 }
835 }
836
837 serde_roundtrip_test!(block_height_serde_round_trip, BlockHeight);
838 serde_roundtrip_test!(block_height_interval_serde_round_trip, BlockHeightInterval);
839 serde_roundtrip_test!(block_mtp_serde_round_trip, BlockMtp);
840 serde_roundtrip_test!(block_mtp_interval_serde_round_trip, BlockMtpInterval);
841
842 #[test]
843 fn block_height_saturating_add() {
844 assert_eq!(BlockHeight(100).saturating_add(BlockHeightInterval(50)), BlockHeight(150),);
846 assert_eq!(BlockHeight::ZERO.saturating_add(BlockHeightInterval(1)), BlockHeight(1),);
847
848 assert_eq!(BlockHeight::MAX.saturating_add(BlockHeightInterval(1)), BlockHeight::MAX,);
850 assert_eq!(BlockHeight::MAX.saturating_add(BlockHeightInterval(100)), BlockHeight::MAX,);
851 assert_eq!(
852 BlockHeight(u32::MAX - 10).saturating_add(BlockHeightInterval(20)),
853 BlockHeight::MAX,
854 );
855
856 assert_eq!(BlockHeight(500).saturating_add(BlockHeightInterval::ZERO), BlockHeight(500),);
858 }
859
860 #[test]
861 fn block_height_saturating_sub() {
862 assert_eq!(BlockHeight(100).saturating_sub(BlockHeightInterval(50)), BlockHeight(50),);
864 assert_eq!(BlockHeight(100).saturating_sub(BlockHeightInterval(100)), BlockHeight(0),);
865
866 assert_eq!(BlockHeight::MIN.saturating_sub(BlockHeightInterval(1)), BlockHeight::MIN,);
868 assert_eq!(BlockHeight::ZERO.saturating_sub(BlockHeightInterval(100)), BlockHeight::ZERO,);
869 assert_eq!(BlockHeight(10).saturating_sub(BlockHeightInterval(20)), BlockHeight::ZERO,);
870
871 assert_eq!(BlockHeight(500).saturating_sub(BlockHeightInterval::ZERO), BlockHeight(500),);
873 }
874}