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
14#[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    /// A block height. Zero denotes the genesis block.
90    ///
91    /// This type is not meant for constructing height based timelocks. It is a general purpose
92    /// blockheight abstraction. For locktimes please see [`locktime::absolute::Height`].
93    ///
94    /// This is a thin wrapper around a `u32` that may take on all values of a `u32`.
95    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
96    pub struct BlockHeight(u32);
97}
98
99impl BlockHeight {
100    /// Block height 0, the genesis block.
101    pub const ZERO: Self = Self(0);
102
103    /// The minimum block height (0), the genesis block.
104    pub const MIN: Self = Self::ZERO;
105
106    /// The maximum block height.
107    pub const MAX: Self = Self(u32::MAX);
108
109    /// Constructs a new block height from a `u32`.
110    pub const fn from_u32(inner: u32) -> Self { Self(inner) }
111
112    /// Returns block height as a `u32`.
113    pub const fn to_u32(self) -> u32 { self.0 }
114
115    /// Attempt to subtract two [`BlockHeight`]s, returning `None` if overflow occurred.
116    #[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    /// Attempt to add an interval to this [`BlockHeight`], returning `None` if overflow occurred.
122    #[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    /// Saturating integer addition.
128    ///
129    /// Computes self + rhs, saturating at `BlockHeight::MAX` instead of overflowing.
130    #[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    /// Saturating integer subtraction.
137    ///
138    /// Computes self - rhs, saturating at `BlockHeight::MIN` instead of overflowing.
139    #[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    /// Converts a [`locktime::absolute::Height`] to a [`BlockHeight`].
150    ///
151    /// An absolute locktime block height has a maximum value of [`absolute::LOCK_TIME_THRESHOLD`]
152    /// minus one, while [`BlockHeight`] may take the full range of `u32`.
153    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    /// Converts a [`BlockHeight`] to a [`locktime::absolute::Height`].
160    ///
161    /// An absolute locktime block height has a maximum value of [`absolute::LOCK_TIME_THRESHOLD`]
162    /// minus one, while [`BlockHeight`] may take the full range of `u32`.
163    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    /// The encoder for the [`BlockHeight`] type.
169    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/// The decoder for the [`BlockHeight`] type.
183#[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    /// Constructs a new [`BlockHeight`] decoder.
194    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/// An error consensus decoding an `BlockHeight`.
224#[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    /// An unsigned block interval.
247    ///
248    /// Block interval is an integer type representing a difference between the heights of two blocks.
249    ///
250    /// This type is not meant for constructing relative height based timelocks. It is a general
251    /// purpose block interval abstraction. For locktimes please see [`locktime::relative::NumberOfBlocks`].
252    #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
253    pub struct BlockHeightInterval(u32);
254}
255
256impl BlockHeightInterval {
257    /// Block interval 0.
258    pub const ZERO: Self = Self(0);
259
260    /// The minimum block interval, equivalent to `Self::ZERO`.
261    pub const MIN: Self = Self::ZERO;
262
263    /// The maximum block interval.
264    pub const MAX: Self = Self(u32::MAX);
265
266    /// Constructs a new block interval from a `u32`.
267    pub const fn from_u32(inner: u32) -> Self { Self(inner) }
268
269    /// Returns block interval as a `u32`.
270    pub const fn to_u32(self) -> u32 { self.0 }
271
272    /// Attempt to subtract two [`BlockHeightInterval`]s, returning `None` if overflow occurred.
273    #[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    /// Attempt to add two [`BlockHeightInterval`]s, returning `None` if overflow occurred.
279    #[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    /// Converts a [`locktime::relative::NumberOfBlocks`] to a [`BlockHeightInterval`].
289    ///
290    /// A relative locktime block height has a maximum value of `u16::MAX` where as a
291    /// [`BlockHeightInterval`] is a thin wrapper around a `u32`, the two types are not interchangeable.
292    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    /// Converts a [`BlockHeightInterval`] to a [`locktime::relative::NumberOfBlocks`].
299    ///
300    /// A relative locktime block height has a maximum value of `u16::MAX` where as a
301    /// [`BlockHeightInterval`] is a thin wrapper around a `u32`, the two types are not interchangeable.
302    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    /// The median timestamp of 11 consecutive blocks.
311    ///
312    /// This type is not meant for constructing time-based timelocks. It is a general purpose
313    /// MTP abstraction. For locktimes please see [`locktime::absolute::MedianTimePast`].
314    ///
315    /// This is a thin wrapper around a `u32` that may take on all values of a `u32`.
316    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
317    pub struct BlockMtp(u32);
318}
319
320impl BlockMtp {
321    /// Block MTP 0.
322    ///
323    /// Since MTP is a timestamp, 0 is before Bitcoin was invented. This const may still be useful
324    /// for some use cases e.g., folding a sum of intervals.
325    pub const ZERO: Self = Self(0);
326
327    /// The minimum block MTP, equivalent to `Self::ZERO`.
328    pub const MIN: Self = Self::ZERO;
329
330    /// The maximum block MTP.
331    pub const MAX: Self = Self(u32::MAX);
332
333    /// Constructs a new block MTP from a `u32`.
334    pub const fn from_u32(inner: u32) -> Self { Self(inner) }
335
336    /// Returns block MTP as a `u32`.
337    pub const fn to_u32(self) -> u32 { self.0 }
338
339    /// Constructs a [`BlockMtp`] by computing the median‐time‐past from the last 11 block timestamps
340    ///
341    /// Because block timestamps are not monotonic, this function internally sorts them;
342    /// it is therefore not important what order they appear in the array; use whatever
343    /// is most convenient.
344    pub fn new(mut timestamps: [crate::BlockTime; 11]) -> Self {
345        timestamps.sort_unstable();
346        Self::from_u32(u32::from(timestamps[5]))
347    }
348
349    /// Attempt to subtract two [`BlockMtp`]s, returning `None` if overflow occurred.
350    #[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    /// Attempt to add an interval to this [`BlockMtp`], returning `None` if overflow occurred.
356    #[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    /// Converts a [`locktime::absolute::MedianTimePast`] to a [`BlockMtp`].
366    ///
367    /// An absolute locktime MTP has a minimum value of [`absolute::LOCK_TIME_THRESHOLD`],
368    /// while [`BlockMtp`] may take the full range of `u32`.
369    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    /// Converts a [`BlockHeight`] to a [`locktime::absolute::Height`].
376    ///
377    /// An absolute locktime MTP has a minimum value of [`absolute::LOCK_TIME_THRESHOLD`],
378    /// while [`BlockMtp`] may take the full range of `u32`.
379    fn try_from(h: BlockMtp) -> Result<Self, Self::Error> { Self::from_u32(h.to_u32()) }
380}
381
382impl_u32_wrapper! {
383    /// An unsigned difference between two [`BlockMtp`]s.
384    ///
385    /// This type is not meant for constructing time-based timelocks. It is a general purpose
386    /// MTP abstraction. For locktimes please see [`locktime::relative::NumberOf512Seconds`].
387    ///
388    /// This is a thin wrapper around a `u32` that may take on all values of a `u32`.
389    #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
390    pub struct BlockMtpInterval(u32);
391}
392
393impl BlockMtpInterval {
394    /// Block MTP interval 0.
395    pub const ZERO: Self = Self(0);
396
397    /// The minimum block MTP interval, equivalent to `Self::ZERO`.
398    pub const MIN: Self = Self::ZERO;
399
400    /// The maximum block MTP interval.
401    pub const MAX: Self = Self(u32::MAX);
402
403    /// Constructs a new block MTP interval from a `u32`.
404    pub const fn from_u32(inner: u32) -> Self { Self(inner) }
405
406    /// Returns block MTP interval as a `u32`.
407    pub const fn to_u32(self) -> u32 { self.0 }
408
409    /// Converts a [`BlockMtpInterval`] to a [`locktime::relative::NumberOf512Seconds`], rounding down.
410    ///
411    /// Relative timelock MTP intervals have a resolution of 512 seconds, while
412    /// [`BlockMtpInterval`], like all block timestamp types, has a one-second resolution.
413    ///
414    /// # Errors
415    ///
416    /// Errors if the MTP is out-of-range (in excess of 512 times `u16::MAX` seconds, or about
417    /// 388 days) for a time-based relative locktime.
418    #[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    /// Converts a [`BlockMtpInterval`] to a [`locktime::relative::NumberOf512Seconds`], rounding up.
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_ceil(
436        self,
437    ) -> Result<relative::NumberOf512Seconds, relative::TimeOverflowError> {
438        relative::NumberOf512Seconds::from_seconds_ceil(self.to_u32())
439    }
440
441    /// Attempt to subtract two [`BlockMtpInterval`]s, returning `None` if overflow occurred.
442    #[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    /// Attempt to add two [`BlockMtpInterval`]s, returning `None` if overflow occurred.
448    #[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    /// Converts a [`locktime::relative::NumberOf512Seconds`] to a [`BlockMtpInterval `].
458    ///
459    /// A relative locktime MTP interval has a resolution of 512 seconds, and a maximum value
460    /// of `u16::MAX` 512-second intervals. [`BlockMtpInterval`] may take the full range of
461    /// `u32`.
462    fn from(h: relative::NumberOf512Seconds) -> Self { Self::from_u32(h.to_seconds()) }
463}
464
465/// Error returned when the block interval is too big to be used as a relative lock time.
466#[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    // height - height = interval
485    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    // height + interval = height
495    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    // height - interval = height
505    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    // interval + interval = interval
515    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    // interval - interval = interval
525    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    // height - height = interval
535    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    // height + interval = height
545    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    // height - interval = height
555    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    // interval + interval = interval
565    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    // interval - interval = interval
575    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    // These tests are supposed to comprise an exhaustive list of available operations.
654    #[test]
655    fn all_available_ops() {
656        // height - height = interval
657        assert!(BlockHeight(10) - BlockHeight(7) == BlockHeightInterval(3));
658
659        // height + interval = height
660        assert!(BlockHeight(100) + BlockHeightInterval(1) == BlockHeight(101));
661
662        // height - interval == height
663        assert!(BlockHeight(100) - BlockHeightInterval(1) == BlockHeight(99));
664
665        // interval + interval = interval
666        assert!(BlockHeightInterval(1) + BlockHeightInterval(2) == BlockHeightInterval(3));
667
668        // interval - interval = interval
669        assert!(BlockHeightInterval(10) - BlockHeightInterval(7) == BlockHeightInterval(3));
670
671        // Sum for BlockHeightInterval by reference and by value
672        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        // Sum for BlockMtpInterval by reference and by value
686        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        // interval += interval
700        let mut int = BlockHeightInterval(1);
701        int += BlockHeightInterval(2);
702        assert_eq!(int, BlockHeightInterval(3));
703
704        // interval -= interval
705        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); // Should floor down to 1
769        assert_ne!(interval.to_relative_mtp_interval_ceil().unwrap(), time); // Should ceil up to 2
770
771        // Check overflow limit
772        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); // Should ceil up to 2
793        assert_ne!(interval.to_relative_mtp_interval_floor().unwrap(), time); // Should floor down to 1
794
795        // Check overflow limit
796        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]; // 3 bytes is an EOF error
812
813        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    // Test a impl_u32_wrapper! type serde serialisation roundtrip.
821    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"); // ASCII number representation
830
831                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        // Normal addition
845        assert_eq!(BlockHeight(100).saturating_add(BlockHeightInterval(50)), BlockHeight(150),);
846        assert_eq!(BlockHeight::ZERO.saturating_add(BlockHeightInterval(1)), BlockHeight(1),);
847
848        // Saturates at MAX instead of overflowing
849        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        // Adding zero
857        assert_eq!(BlockHeight(500).saturating_add(BlockHeightInterval::ZERO), BlockHeight(500),);
858    }
859
860    #[test]
861    fn block_height_saturating_sub() {
862        // Normal subtraction
863        assert_eq!(BlockHeight(100).saturating_sub(BlockHeightInterval(50)), BlockHeight(50),);
864        assert_eq!(BlockHeight(100).saturating_sub(BlockHeightInterval(100)), BlockHeight(0),);
865
866        // Saturates at MIN instead of underflowing
867        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        // Subtracting zero
872        assert_eq!(BlockHeight(500).saturating_sub(BlockHeightInterval::ZERO), BlockHeight(500),);
873    }
874}