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 to 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 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    /// A block height. Zero denotes the genesis block.
125    ///
126    /// This type is not meant for constructing height based timelocks. It is a general purpose
127    /// blockheight abstraction. For locktimes please see [`locktime::absolute::Height`].
128    ///
129    /// This is a thin wrapper around a `u32` that may take on all values of a `u32`.
130    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
131    pub struct BlockHeight(u32);
132}
133
134impl BlockHeight {
135    /// Block height 0, the genesis block.
136    pub const ZERO: Self = Self(0);
137
138    /// The minimum block height (0), the genesis block.
139    pub const MIN: Self = Self::ZERO;
140
141    /// The maximum block height.
142    pub const MAX: Self = Self(u32::MAX);
143
144    /// Constructs a new block height from a `u32`.
145    #[inline]
146    pub const fn from_u32(inner: u32) -> Self { Self(inner) }
147
148    /// Returns block height as a `u32`.
149    #[inline]
150    pub const fn to_u32(self) -> u32 { self.0 }
151
152    /// Attempt to subtract two [`BlockHeight`]s, returning `None` if overflow occurred.
153    #[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    /// Attempt to add an interval to this [`BlockHeight`], returning `None` if overflow occurred.
160    #[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    /// Saturating integer addition.
167    ///
168    /// Computes self + rhs, saturating at `BlockHeight::MAX` instead of overflowing.
169    #[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    /// Saturating integer subtraction.
176    ///
177    /// Computes self - rhs, saturating at `BlockHeight::MIN` instead of overflowing.
178    #[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    /// Converts a [`locktime::absolute::Height`] to a [`BlockHeight`].
189    ///
190    /// An absolute locktime block height has a maximum value of [`absolute::LOCK_TIME_THRESHOLD`]
191    /// minus one, while [`BlockHeight`] may take the full range of `u32`.
192    #[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    /// Converts a [`BlockHeight`] to a [`locktime::absolute::Height`].
200    ///
201    /// An absolute locktime block height has a maximum value of [`absolute::LOCK_TIME_THRESHOLD`]
202    /// minus one, while [`BlockHeight`] may take the full range of `u32`.
203    #[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    /// The encoder for the [`BlockHeight`] type.
226    #[derive(Debug, Clone)]
227    pub struct BlockHeightEncoder<'e>(encoding::ArrayEncoder<4>);
228}
229
230#[cfg(feature = "encoding")]
231crate::decoder_newtype! {
232    /// The decoder for the [`BlockHeight`] type.
233    #[derive(Debug, Clone)]
234    pub struct BlockHeightDecoder(encoding::ArrayDecoder<4>);
235
236    /// Constructs a new [`BlockHeight`] decoder.
237    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    /// An unsigned block interval.
248    ///
249    /// Block interval is an integer type representing a difference between the heights of two blocks.
250    ///
251    /// This type is not meant for constructing relative height based timelocks. It is a general
252    /// purpose block interval abstraction. For locktimes please see [`locktime::relative::NumberOfBlocks`].
253    #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
254    pub struct BlockHeightInterval(u32);
255}
256
257impl BlockHeightInterval {
258    /// Block interval 0.
259    pub const ZERO: Self = Self(0);
260
261    /// The minimum block interval, equivalent to `Self::ZERO`.
262    pub const MIN: Self = Self::ZERO;
263
264    /// The maximum block interval.
265    pub const MAX: Self = Self(u32::MAX);
266
267    /// Constructs a new block interval from a `u32`.
268    #[inline]
269    pub const fn from_u32(inner: u32) -> Self { Self(inner) }
270
271    /// Returns block interval as a `u32`.
272    #[inline]
273    pub const fn to_u32(self) -> u32 { self.0 }
274
275    /// Attempt to subtract two [`BlockHeightInterval`]s, returning `None` if overflow occurred.
276    #[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    /// Attempt to add two [`BlockHeightInterval`]s, returning `None` if overflow occurred.
283    #[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    /// Converts a [`locktime::relative::NumberOfBlocks`] to a [`BlockHeightInterval`].
294    ///
295    /// A relative locktime block height has a maximum value of `u16::MAX` where as a
296    /// [`BlockHeightInterval`] is a thin wrapper around a `u32`, the two types are not interchangeable.
297    #[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    /// Converts a [`BlockHeightInterval`] to a [`locktime::relative::NumberOfBlocks`].
305    ///
306    /// A relative locktime block height has a maximum value of `u16::MAX` where as a
307    /// [`BlockHeightInterval`] is a thin wrapper around a `u32`, the two types are not interchangeable.
308    #[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    /// The median timestamp of 11 consecutive blocks.
318    ///
319    /// This type is not meant for constructing time-based timelocks. It is a general purpose
320    /// MTP abstraction. For locktimes please see [`locktime::absolute::MedianTimePast`].
321    ///
322    /// This is a thin wrapper around a `u32` that may take on all values of a `u32`.
323    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
324    pub struct BlockMtp(u32);
325}
326
327impl BlockMtp {
328    /// Block MTP 0.
329    ///
330    /// Since MTP is a timestamp, 0 is before Bitcoin was invented. This const may still be useful
331    /// for some use cases e.g., folding a sum of intervals.
332    pub const ZERO: Self = Self(0);
333
334    /// The minimum block MTP, equivalent to `Self::ZERO`.
335    pub const MIN: Self = Self::ZERO;
336
337    /// The maximum block MTP.
338    pub const MAX: Self = Self(u32::MAX);
339
340    /// Constructs a new block MTP from a `u32`.
341    #[inline]
342    pub const fn from_u32(inner: u32) -> Self { Self(inner) }
343
344    /// Returns block MTP as a `u32`.
345    #[inline]
346    pub const fn to_u32(self) -> u32 { self.0 }
347
348    /// Constructs a [`BlockMtp`] by computing the median‐time‐past from the last 11 block timestamps
349    ///
350    /// Because block timestamps are not monotonic, this function internally sorts them;
351    /// it is therefore not important what order they appear in the array; use whatever
352    /// is most convenient.
353    #[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    /// Attempt to subtract two [`BlockMtp`]s, returning `None` if overflow occurred.
360    #[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    /// Attempt to add an interval to this [`BlockMtp`], returning `None` if overflow occurred.
367    #[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    /// Converts a [`locktime::absolute::MedianTimePast`] to a [`BlockMtp`].
378    ///
379    /// An absolute locktime MTP has a minimum value of [`absolute::LOCK_TIME_THRESHOLD`],
380    /// while [`BlockMtp`] may take the full range of `u32`.
381    #[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    /// Converts a [`BlockMtp`] to a [`locktime::absolute::MedianTimePast`].
389    ///
390    /// An absolute locktime MTP has a minimum value of [`absolute::LOCK_TIME_THRESHOLD`],
391    /// while [`BlockMtp`] may take the full range of `u32`.
392    #[inline]
393    fn try_from(h: BlockMtp) -> Result<Self, Self::Error> { Self::from_u32(h.to_u32()) }
394}
395
396impl_u32_wrapper! {
397    /// An unsigned difference between two [`BlockMtp`]s.
398    ///
399    /// This type is not meant for constructing time-based timelocks. It is a general purpose
400    /// MTP abstraction. For locktimes please see [`locktime::relative::NumberOf512Seconds`].
401    ///
402    /// This is a thin wrapper around a `u32` that may take on all values of a `u32`.
403    #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
404    pub struct BlockMtpInterval(u32);
405}
406
407impl BlockMtpInterval {
408    /// Block MTP interval 0.
409    pub const ZERO: Self = Self(0);
410
411    /// The minimum block MTP interval, equivalent to `Self::ZERO`.
412    pub const MIN: Self = Self::ZERO;
413
414    /// The maximum block MTP interval.
415    pub const MAX: Self = Self(u32::MAX);
416
417    /// Constructs a new block MTP interval from a `u32`.
418    #[inline]
419    pub const fn from_u32(inner: u32) -> Self { Self(inner) }
420
421    /// Returns block MTP interval as a `u32`.
422    #[inline]
423    pub const fn to_u32(self) -> u32 { self.0 }
424
425    /// Converts a [`BlockMtpInterval`] to a [`locktime::relative::NumberOf512Seconds`], rounding down.
426    ///
427    /// Relative timelock MTP intervals have a resolution of 512 seconds, while
428    /// [`BlockMtpInterval`], like all block timestamp types, has a one-second resolution.
429    ///
430    /// # Errors
431    ///
432    /// Errors if the MTP is out-of-range (in excess of 512 times `u16::MAX` seconds, or about
433    /// 388 days) for a time-based relative locktime.
434    #[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    /// Converts a [`BlockMtpInterval`] to a [`locktime::relative::NumberOf512Seconds`], rounding up.
442    ///
443    /// Relative timelock MTP intervals have a resolution of 512 seconds, while
444    /// [`BlockMtpInterval`], like all block timestamp types, has a one-second resolution.
445    ///
446    /// # Errors
447    ///
448    /// Errors if the MTP is out-of-range (in excess of 512 times `u16::MAX` seconds, or about
449    /// 388 days) for a time-based relative locktime.
450    #[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    /// Attempt to subtract two [`BlockMtpInterval`]s, returning `None` if overflow occurred.
458    #[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    /// Attempt to add two [`BlockMtpInterval`]s, returning `None` if overflow occurred.
465    #[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    /// Converts a [`locktime::relative::NumberOf512Seconds`] to a [`BlockMtpInterval `].
476    ///
477    /// A relative locktime MTP interval has a resolution of 512 seconds, and a maximum value
478    /// of `u16::MAX` 512-second intervals. [`BlockMtpInterval`] may take the full range of
479    /// `u32`.
480    #[inline]
481    fn from(h: relative::NumberOf512Seconds) -> Self { Self::from_u32(h.to_seconds()) }
482}
483
484crate::internal_macros::impl_op_for_references! {
485    // height - height = interval
486    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    // height + interval = height
496    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    // height - interval = height
506    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    // interval + interval = interval
516    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    // interval - interval = interval
526    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    // height - height = interval
536    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    // height + interval = height
546    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    // height - interval = height
556    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    // interval + interval = interval
566    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    // interval - interval = interval
576    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
629/// Error types for block height and interval types.
630pub 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    /// Error returned when the block interval is too big to be used as a relative lock time.
640    #[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    /// An error consensus decoding an `BlockHeight`.
664    #[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    // These tests are supposed to comprise an exhaustive list of available operations.
722    #[test]
723    fn all_available_ops() {
724        // height - height = interval
725        assert!(BlockHeight(10) - BlockHeight(7) == BlockHeightInterval(3));
726
727        // height + interval = height
728        assert!(BlockHeight(100) + BlockHeightInterval(1) == BlockHeight(101));
729
730        // height - interval == height
731        assert!(BlockHeight(100) - BlockHeightInterval(1) == BlockHeight(99));
732
733        // interval + interval = interval
734        assert!(BlockHeightInterval(1) + BlockHeightInterval(2) == BlockHeightInterval(3));
735
736        // interval - interval = interval
737        assert!(BlockHeightInterval(10) - BlockHeightInterval(7) == BlockHeightInterval(3));
738
739        // Sum for BlockHeightInterval by reference and by value
740        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        // Sum for BlockMtpInterval by reference and by value
754        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        // interval += interval
768        let mut int = BlockHeightInterval(1);
769        int += BlockHeightInterval(2);
770        assert_eq!(int, BlockHeightInterval(3));
771
772        // interval -= interval
773        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); // Should floor down to 1
837        assert_ne!(interval.to_relative_mtp_interval_ceil().unwrap(), time); // Should ceil up to 2
838
839        // Check overflow limit
840        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); // Should ceil up to 2
861        assert_ne!(interval.to_relative_mtp_interval_floor().unwrap(), time); // Should floor down to 1
862
863        // Check overflow limit
864        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]; // 3 bytes is an EOF error
880
881        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    // Test a impl_u32_wrapper! type serde serialisation roundtrip.
889    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"); // ASCII number representation
898
899                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        // Normal addition
913        assert_eq!(BlockHeight(100).saturating_add(BlockHeightInterval(50)), BlockHeight(150),);
914        assert_eq!(BlockHeight::ZERO.saturating_add(BlockHeightInterval(1)), BlockHeight(1),);
915
916        // Saturates at MAX instead of overflowing
917        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        // Adding zero
925        assert_eq!(BlockHeight(500).saturating_add(BlockHeightInterval::ZERO), BlockHeight(500),);
926    }
927
928    #[test]
929    fn block_height_saturating_sub() {
930        // Normal subtraction
931        assert_eq!(BlockHeight(100).saturating_sub(BlockHeightInterval(50)), BlockHeight(50),);
932        assert_eq!(BlockHeight(100).saturating_sub(BlockHeightInterval(100)), BlockHeight(0),);
933
934        // Saturates at MIN instead of underflowing
935        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        // Subtracting zero
940        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        // TooBigForRelativeHeightError - block interval too big for relative height
947        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            // BlockHeightDecoderError
956            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}