Skip to main content

bitcoin_units/
block.rs

1// SPDX-License-Identifier: CC0-1.0
2
3//! Block height and interval types.
4//!
5//! These types are thin wrappers around `u32`, no invariants implemented or implied.
6//!
7//! These are general types for abstracting over block heights, they are not designed for use with
8//! lock times. If you are creating lock times you should be using the
9//! [`locktime::absolute::Height`] and [`locktime::relative::NumberOfBlocks`] types.
10//!
11//! The difference between these types and the locktime types is that these types are thin wrappers
12//! whereas the locktime types contain more complex locktime specific abstractions.
13
14use 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]                // Keep public re-exports separate.
27#[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    /// A block height. Zero denotes the genesis block.
126    ///
127    /// This type is not meant for constructing height based timelocks. It is a general purpose
128    /// blockheight abstraction. For locktimes please see [`locktime::absolute::Height`].
129    ///
130    /// This is a thin wrapper around a `u32` that may take on all values of a `u32`.
131    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
132    pub struct BlockHeight(u32);
133}
134
135impl BlockHeight {
136    /// Block height 0, the genesis block.
137    pub const ZERO: Self = Self(0);
138
139    /// The minimum block height (0), the genesis block.
140    pub const MIN: Self = Self::ZERO;
141
142    /// The maximum block height.
143    pub const MAX: Self = Self(u32::MAX);
144
145    /// Constructs a new block height from a `u32`.
146    #[inline]
147    pub const fn from_u32(inner: u32) -> Self { Self(inner) }
148
149    /// Returns block height as a `u32`.
150    #[inline]
151    pub const fn to_u32(self) -> u32 { self.0 }
152
153    /// Attempts to subtract two [`BlockHeight`]s, returning [`None`] if overflow occurred.
154    #[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    /// Attempts to add an interval to this [`BlockHeight`], returning [`None`] if overflow
161    /// occurred.
162    #[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    /// Saturating integer addition.
169    ///
170    /// Computes self + rhs, saturating at [`BlockHeight::MAX`] instead of overflowing.
171    #[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    /// Saturating integer subtraction.
178    ///
179    /// Computes self - rhs, saturating at [`BlockHeight::MIN`] instead of overflowing.
180    #[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    /// Converts a [`locktime::absolute::Height`] to a [`BlockHeight`].
191    ///
192    /// An absolute locktime block height has a maximum value of [`absolute::LOCK_TIME_THRESHOLD`]
193    /// minus one, while [`BlockHeight`] may take the full range of `u32`.
194    #[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    /// Converts a [`BlockHeight`] to a [`locktime::absolute::Height`].
202    ///
203    /// An absolute locktime block height has a maximum value of [`absolute::LOCK_TIME_THRESHOLD`]
204    /// minus one, while [`BlockHeight`] may take the full range of `u32`.
205    #[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    /// The encoder for the [`BlockHeight`] type.
228    #[derive(Debug, Clone)]
229    pub struct BlockHeightEncoder<'e>(encoding::ArrayEncoder<4>);
230}
231
232#[cfg(feature = "encoding")]
233crate::decoder_newtype! {
234    /// The decoder for the [`BlockHeight`] type.
235    #[derive(Debug, Clone)]
236    pub struct BlockHeightDecoder(encoding::ArrayDecoder<4>);
237
238    /// Constructs a new [`BlockHeight`] decoder.
239    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    /// An unsigned block interval.
250    ///
251    /// Block interval is an integer type representing a difference between the heights of two blocks.
252    ///
253    /// This type is not meant for constructing relative height based timelocks. It is a general
254    /// purpose block interval abstraction. For locktimes please see [`locktime::relative::NumberOfBlocks`].
255    #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
256    pub struct BlockHeightInterval(u32);
257}
258
259impl BlockHeightInterval {
260    /// Block interval 0.
261    pub const ZERO: Self = Self(0);
262
263    /// The minimum block interval, equivalent to [`Self::ZERO`].
264    pub const MIN: Self = Self::ZERO;
265
266    /// The maximum block interval.
267    pub const MAX: Self = Self(u32::MAX);
268
269    /// Constructs a new block interval from a `u32`.
270    #[inline]
271    pub const fn from_u32(inner: u32) -> Self { Self(inner) }
272
273    /// Returns block interval as a `u32`.
274    #[inline]
275    pub const fn to_u32(self) -> u32 { self.0 }
276
277    /// Attempts to subtract two [`BlockHeightInterval`]s, returning [`None`] if overflow occurred.
278    #[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    /// Attempts to add two [`BlockHeightInterval`]s, returning [`None`] if overflow occurred.
285    #[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    /// Converts a [`locktime::relative::NumberOfBlocks`] to a [`BlockHeightInterval`].
296    ///
297    /// A relative locktime block height has a maximum value of `u16::MAX` where as a
298    /// [`BlockHeightInterval`] is a thin wrapper around a `u32`, the two types are not interchangeable.
299    #[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    /// Converts a [`BlockHeightInterval`] to a [`locktime::relative::NumberOfBlocks`].
307    ///
308    /// A relative locktime block height has a maximum value of `u16::MAX` where as a
309    /// [`BlockHeightInterval`] is a thin wrapper around a `u32`, the two types are not interchangeable.
310    #[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    /// The median timestamp of 11 consecutive blocks.
320    ///
321    /// This type is not meant for constructing time-based timelocks. It is a general purpose
322    /// MTP abstraction. For locktimes please see [`locktime::absolute::MedianTimePast`].
323    ///
324    /// This is a thin wrapper around a `u32` that may take on all values of a `u32`.
325    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
326    pub struct BlockMtp(u32);
327}
328
329impl BlockMtp {
330    /// Block MTP 0.
331    ///
332    /// Since MTP is a timestamp, 0 is before Bitcoin was invented. This const may still be useful
333    /// for some use cases e.g., folding a sum of intervals.
334    pub const ZERO: Self = Self(0);
335
336    /// The minimum block MTP, equivalent to [`Self::ZERO`].
337    pub const MIN: Self = Self::ZERO;
338
339    /// The maximum block MTP.
340    pub const MAX: Self = Self(u32::MAX);
341
342    /// Constructs a new block MTP from a `u32`.
343    #[inline]
344    pub const fn from_u32(inner: u32) -> Self { Self(inner) }
345
346    /// Returns block MTP as a `u32`.
347    #[inline]
348    pub const fn to_u32(self) -> u32 { self.0 }
349
350    /// Constructs a [`BlockMtp`] by computing the median-time-past from the last 11 block timestamps.
351    ///
352    /// Because block timestamps are not monotonic, this function internally sorts them;
353    /// it is therefore not important what order they appear in the array; use whatever
354    /// is most convenient.
355    #[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    /// Attempts to subtract two [`BlockMtp`]s, returning [`None`] if overflow occurred.
362    #[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    /// Attempts to add an interval to this [`BlockMtp`], returning [`None`] if overflow occurred.
369    #[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    /// Converts a [`locktime::absolute::MedianTimePast`] to a [`BlockMtp`].
380    ///
381    /// An absolute locktime MTP has a minimum value of [`absolute::LOCK_TIME_THRESHOLD`],
382    /// while [`BlockMtp`] may take the full range of `u32`.
383    #[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    /// Converts a [`BlockMtp`] to a [`locktime::absolute::MedianTimePast`].
391    ///
392    /// An absolute locktime MTP has a minimum value of [`absolute::LOCK_TIME_THRESHOLD`],
393    /// while [`BlockMtp`] may take the full range of `u32`.
394    #[inline]
395    fn try_from(h: BlockMtp) -> Result<Self, Self::Error> { Self::from_u32(h.to_u32()) }
396}
397
398impl_u32_wrapper! {
399    /// An unsigned difference between two [`BlockMtp`]s.
400    ///
401    /// This type is not meant for constructing time-based timelocks. It is a general purpose
402    /// MTP abstraction. For locktimes please see [`locktime::relative::NumberOf512Seconds`].
403    ///
404    /// This is a thin wrapper around a `u32` that may take on all values of a `u32`.
405    #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
406    pub struct BlockMtpInterval(u32);
407}
408
409impl BlockMtpInterval {
410    /// Block MTP interval 0.
411    pub const ZERO: Self = Self(0);
412
413    /// The minimum block MTP interval, equivalent to [`Self::ZERO`].
414    pub const MIN: Self = Self::ZERO;
415
416    /// The maximum block MTP interval.
417    pub const MAX: Self = Self(u32::MAX);
418
419    /// Constructs a new block MTP interval from a `u32`.
420    #[inline]
421    pub const fn from_u32(inner: u32) -> Self { Self(inner) }
422
423    /// Returns block MTP interval as a `u32`.
424    #[inline]
425    pub const fn to_u32(self) -> u32 { self.0 }
426
427    /// Converts a [`BlockMtpInterval`] to a [`locktime::relative::NumberOf512Seconds`], rounding down.
428    ///
429    /// Relative timelock MTP intervals have a resolution of 512 seconds, while
430    /// [`BlockMtpInterval`], like all block timestamp types, has a one-second resolution.
431    ///
432    /// # Errors
433    ///
434    /// Errors if the MTP is out-of-range (in excess of 512 times `u16::MAX` seconds, or about
435    /// 388 days) for a time-based relative locktime.
436    #[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    /// Converts a [`BlockMtpInterval`] to a [`locktime::relative::NumberOf512Seconds`], rounding up.
444    ///
445    /// Relative timelock MTP intervals have a resolution of 512 seconds, while
446    /// [`BlockMtpInterval`], like all block timestamp types, has a one-second resolution.
447    ///
448    /// # Errors
449    ///
450    /// Errors if the MTP is out-of-range (in excess of 512 times `u16::MAX` seconds, or about
451    /// 388 days) for a time-based relative locktime.
452    #[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    /// Attempts to subtract two [`BlockMtpInterval`]s, returning [`None`] if overflow occurred.
460    #[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    /// Attempts to add two [`BlockMtpInterval`]s, returning [`None`] if overflow occurred.
467    #[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    /// Converts a [`locktime::relative::NumberOf512Seconds`] to a [`BlockMtpInterval`].
478    ///
479    /// A relative locktime MTP interval has a resolution of 512 seconds, and a maximum value
480    /// of `u16::MAX` 512-second intervals. [`BlockMtpInterval`] may take the full range of
481    /// `u32`.
482    #[inline]
483    fn from(h: relative::NumberOf512Seconds) -> Self { Self::from_u32(h.to_seconds()) }
484}
485
486crate::internal_macros::impl_op_for_references! {
487    // height - height = interval
488    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    // height + interval = height
499    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    // height - interval = height
510    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    // interval + interval = interval
521    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    // interval - interval = interval
532    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    // height - height = interval
543    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    // height + interval = height
554    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    // height - interval = height
565    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    // interval + interval = interval
576    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    // interval - interval = interval
587    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
641/// Error types for block height and interval types.
642pub 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    /// Error returned when the block interval is too big to be used as a relative lock time.
652    #[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    /// An error consensus decoding a [`BlockHeight`].
682    ///
683    /// [`BlockHeight`]: super::BlockHeight
684    #[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    // These tests are supposed to comprise an exhaustive list of available operations.
745    #[test]
746    fn all_available_ops() {
747        // height - height = interval
748        assert!(BlockHeight(10) - BlockHeight(7) == BlockHeightInterval(3));
749
750        // height + interval = height
751        assert!(BlockHeight(100) + BlockHeightInterval(1) == BlockHeight(101));
752
753        // height - interval == height
754        assert!(BlockHeight(100) - BlockHeightInterval(1) == BlockHeight(99));
755
756        // interval + interval = interval
757        assert!(BlockHeightInterval(1) + BlockHeightInterval(2) == BlockHeightInterval(3));
758
759        // interval - interval = interval
760        assert!(BlockHeightInterval(10) - BlockHeightInterval(7) == BlockHeightInterval(3));
761
762        // Sum for BlockHeightInterval by reference and by value
763        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        // Sum for BlockMtpInterval by reference and by value
777        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        // interval += interval
791        let mut int = BlockHeightInterval(1);
792        int += BlockHeightInterval(2);
793        assert_eq!(int, BlockHeightInterval(3));
794
795        // interval -= interval
796        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); // Should floor down to 1
860        assert_ne!(interval.to_relative_mtp_interval_ceil().unwrap(), time); // Should ceil up to 2
861
862        // Check overflow limit
863        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); // Should ceil up to 2
884        assert_ne!(interval.to_relative_mtp_interval_floor().unwrap(), time); // Should floor down to 1
885
886        // Check overflow limit
887        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]; // 3 bytes is an EOF error
903
904        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    // Test a impl_u32_wrapper! type serde serialisation roundtrip.
912    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"); // ASCII number representation
921
922                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        // Normal addition
936        assert_eq!(BlockHeight(100).saturating_add(BlockHeightInterval(50)), BlockHeight(150),);
937        assert_eq!(BlockHeight::ZERO.saturating_add(BlockHeightInterval(1)), BlockHeight(1),);
938
939        // Saturates at MAX instead of overflowing
940        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        // Adding zero
948        assert_eq!(BlockHeight(500).saturating_add(BlockHeightInterval::ZERO), BlockHeight(500),);
949    }
950
951    #[test]
952    fn block_height_saturating_sub() {
953        // Normal subtraction
954        assert_eq!(BlockHeight(100).saturating_sub(BlockHeightInterval(50)), BlockHeight(50),);
955        assert_eq!(BlockHeight(100).saturating_sub(BlockHeightInterval(100)), BlockHeight(0),);
956
957        // Saturates at MIN instead of underflowing
958        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        // Subtracting zero
963        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        // TooBigForRelativeHeightError - block interval too big for relative height
970        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            // BlockHeightDecoderError
979            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}