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::Height`] 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 = "serde")]
17use serde::{Deserialize, Serialize};
18
19#[cfg(doc)]
20use crate::locktime;
21use crate::locktime::{absolute, relative};
22
23/// The block height, zero denotes the genesis block.
24///
25/// This type is not meant for constructing height based timelocks, this is a general purpose block
26/// height abstraction. For locktimes please see [`locktime::absolute::Height`].
27///
28/// This is a thin wrapper around a `u32` that may take on all values of a `u32`.
29#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
30#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
31// Public to try and make it really clear that there are no invariants.
32pub struct BlockHeight(pub u32);
33
34impl BlockHeight {
35    /// Block height 0, the genesis block.
36    pub const ZERO: Self = BlockHeight(0);
37
38    /// The minimum block height (0), the genesis block.
39    pub const MIN: Self = Self::ZERO;
40
41    /// The maximum block height.
42    pub const MAX: Self = BlockHeight(u32::MAX);
43
44    /// Creates a block height from a `u32`.
45    // Because From<u32> is not const.
46    pub const fn from_u32(inner: u32) -> Self { Self(inner) }
47
48    /// Returns block height as a `u32`.
49    // Because type inference doesn't always work using `Into`.
50    pub const fn to_u32(&self) -> u32 { self.0 }
51}
52
53impl fmt::Display for BlockHeight {
54    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
55}
56
57crate::impl_parse_str_from_int_infallible!(BlockHeight, u32, from);
58
59impl From<u32> for BlockHeight {
60    fn from(inner: u32) -> Self { Self::from_u32(inner) }
61}
62
63impl From<BlockHeight> for u32 {
64    fn from(height: BlockHeight) -> Self { height.to_u32() }
65}
66
67impl From<absolute::Height> for BlockHeight {
68    /// Converts a [`locktime::absolute::Height`] to a [`BlockHeight`].
69    ///
70    /// An absolute locktime block height has a maximum value of [`absolute::LOCK_TIME_THRESHOLD`]
71    /// (500,000,000) where as a [`BlockHeight`] is a thin wrapper around a `u32`, the two types are
72    /// not interchangeable.
73    fn from(h: absolute::Height) -> Self { Self::from_u32(h.to_consensus_u32()) }
74}
75
76impl TryFrom<BlockHeight> for absolute::Height {
77    type Error = absolute::ConversionError;
78
79    /// Converts a [`BlockHeight`] to a [`locktime::absolute::Height`].
80    ///
81    /// An absolute locktime block height has a maximum value of [`absolute::LOCK_TIME_THRESHOLD`]
82    /// (500,000,000) where as a [`BlockHeight`] is a thin wrapper around a `u32`, the two types are
83    /// not interchangeable.
84    fn try_from(h: BlockHeight) -> Result<Self, Self::Error> {
85        absolute::Height::from_consensus(h.to_u32())
86    }
87}
88
89/// The block interval.
90///
91/// Block interval is an integer type denoting the number of blocks that has passed since some point
92/// i.e., this type is meant for usage as a relative block measure.
93///
94/// This type is not meant for constructing relative height based timelocks, this is a general
95/// purpose block interval abstraction. For locktimes please see [`locktime::relative::Height`].
96#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
97#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
98// Public to try and make it really clear that there are no invariants.
99pub struct BlockInterval(pub u32);
100
101impl BlockInterval {
102    /// Block interval 0 i.e., the current block.
103    pub const ZERO: Self = BlockInterval(0);
104
105    /// The minimum block interval (0).
106    pub const MIN: Self = Self::ZERO;
107
108    /// The maximum block interval.
109    pub const MAX: Self = BlockInterval(u32::MAX);
110
111    /// Creates a block interval from a `u32`.
112    // Because From<u32> is not const.
113    pub const fn from_u32(inner: u32) -> Self { Self(inner) }
114
115    /// Returns block interval as a `u32`.
116    // Because type inference doesn't always work using `Into`.
117    pub const fn to_u32(&self) -> u32 { self.0 }
118}
119
120impl fmt::Display for BlockInterval {
121    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
122}
123
124crate::impl_parse_str_from_int_infallible!(BlockInterval, u32, from);
125
126impl From<u32> for BlockInterval {
127    fn from(inner: u32) -> Self { Self::from_u32(inner) }
128}
129
130impl From<BlockInterval> for u32 {
131    fn from(height: BlockInterval) -> Self { height.to_u32() }
132}
133
134impl From<relative::Height> for BlockInterval {
135    /// Converts a [`locktime::relative::Height`] to a [`BlockInterval`].
136    ///
137    /// A relative locktime block height has a maximum value of `u16::MAX` where as a
138    /// [`BlockInterval`] is a thin wrapper around a `u32`, the two types are not interchangeable.
139    fn from(h: relative::Height) -> Self { Self::from_u32(h.value().into()) }
140}
141
142impl TryFrom<BlockInterval> for relative::Height {
143    type Error = TooBigForRelativeBlockHeightError;
144
145    /// Converts a [`BlockInterval`] to a [`locktime::relative::Height`].
146    ///
147    /// A relative locktime block height has a maximum value of `u16::MAX` where as a
148    /// [`BlockInterval`] is a thin wrapper around a `u32`, the two types are not interchangeable.
149    fn try_from(h: BlockInterval) -> Result<Self, Self::Error> {
150        let h = h.to_u32();
151        if h > u16::MAX as u32 {
152            return Err(TooBigForRelativeBlockHeightError(h));
153        }
154        Ok(relative::Height::from(h as u16)) // Cast ok, value checked above
155    }
156}
157
158/// Error returned when the block interval is too big to be used as a relative lock time.
159#[derive(Debug, Clone, PartialEq, Eq)]
160pub struct TooBigForRelativeBlockHeightError(u32);
161
162impl fmt::Display for TooBigForRelativeBlockHeightError {
163    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
164        write!(
165            f,
166            "block interval is too big to be used as a relative lock time: {} (max: {})",
167            self.0,
168            relative::Height::MAX
169        )
170    }
171}
172
173#[cfg(feature = "std")]
174impl std::error::Error for TooBigForRelativeBlockHeightError {}
175
176// height - height = interval
177impl ops::Sub<BlockHeight> for BlockHeight {
178    type Output = BlockInterval;
179
180    fn sub(self, rhs: BlockHeight) -> Self::Output {
181        let interval = self.to_u32() - rhs.to_u32();
182        BlockInterval::from_u32(interval)
183    }
184}
185
186// height + interval = height
187impl ops::Add<BlockInterval> for BlockHeight {
188    type Output = BlockHeight;
189
190    fn add(self, rhs: BlockInterval) -> Self::Output {
191        let height = self.to_u32() + rhs.to_u32();
192        BlockHeight::from_u32(height)
193    }
194}
195
196// height - interval = height
197impl ops::Sub<BlockInterval> for BlockHeight {
198    type Output = BlockHeight;
199
200    fn sub(self, rhs: BlockInterval) -> Self::Output {
201        let height = self.to_u32() - rhs.to_u32();
202        BlockHeight::from_u32(height)
203    }
204}
205
206// interval + interval = interval
207impl ops::Add<BlockInterval> for BlockInterval {
208    type Output = BlockInterval;
209
210    fn add(self, rhs: BlockInterval) -> Self::Output {
211        let height = self.to_u32() + rhs.to_u32();
212        BlockInterval::from_u32(height)
213    }
214}
215
216impl ops::AddAssign<BlockInterval> for BlockInterval {
217    fn add_assign(&mut self, rhs: BlockInterval) { self.0 = self.to_u32() + rhs.to_u32(); }
218}
219
220// interval - interval = interval
221impl ops::Sub<BlockInterval> for BlockInterval {
222    type Output = BlockInterval;
223
224    fn sub(self, rhs: BlockInterval) -> Self::Output {
225        let height = self.to_u32() - rhs.to_u32();
226        BlockInterval::from_u32(height)
227    }
228}
229
230impl ops::SubAssign<BlockInterval> for BlockInterval {
231    fn sub_assign(&mut self, rhs: BlockInterval) { self.0 = self.to_u32() - rhs.to_u32(); }
232}
233
234#[cfg(test)]
235mod tests {
236    use super::*;
237
238    // These tests are supposed to comprise an exhaustive list of available operations.
239    #[test]
240    fn all_available_ops() {
241        // height - height = interval
242        assert!(BlockHeight(100) - BlockHeight(99) == BlockInterval(1));
243
244        // height + interval = height
245        assert!(BlockHeight(100) + BlockInterval(1) == BlockHeight(101));
246
247        // height - interval == height
248        assert!(BlockHeight(100) - BlockInterval(1) == BlockHeight(99));
249
250        // interval + interval = interval
251        assert!(BlockInterval(1) + BlockInterval(2) == BlockInterval(3));
252
253        // interval - interval = interval
254        assert!(BlockInterval(3) - BlockInterval(2) == BlockInterval(1));
255
256        // interval += interval
257        let mut int = BlockInterval(1);
258        int += BlockInterval(2);
259        assert_eq!(int, BlockInterval(3));
260
261        // interval -= interval
262        let mut int = BlockInterval(3);
263        int -= BlockInterval(2);
264        assert_eq!(int, BlockInterval(1));
265    }
266}