bitcoin_units/locktime/
relative.rs

1// SPDX-License-Identifier: CC0-1.0
2
3//! Provides type `Height` and `Time` types used by the `rust-bitcoin` `relative::LockTime` type.
4
5use core::fmt;
6
7#[cfg(feature = "serde")]
8use serde::{Deserialize, Serialize};
9
10/// A relative lock time lock-by-blockheight value.
11#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
12#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
13pub struct Height(u16);
14
15impl Height {
16    /// Relative block height 0, can be included in any block.
17    pub const ZERO: Self = Height(0);
18
19    /// The minimum relative block height (0), can be included in any block.
20    pub const MIN: Self = Self::ZERO;
21
22    /// The maximum relative block height.
23    pub const MAX: Self = Height(u16::max_value());
24
25    /// Create a [`Height`] using a count of blocks.
26    #[inline]
27    pub const fn from_height(blocks: u16) -> Self { Height(blocks) }
28
29    /// Returns the inner `u16` value.
30    #[inline]
31    pub fn value(self) -> u16 { self.0 }
32
33    /// Returns the `u32` value used to encode this locktime in an nSequence field or
34    /// argument to `OP_CHECKSEQUENCEVERIFY`.
35    #[inline]
36    pub fn to_consensus_u32(&self) -> u32 { self.0.into() }
37}
38
39impl From<u16> for Height {
40    #[inline]
41    fn from(value: u16) -> Self { Height(value) }
42}
43
44crate::impl_parse_str_from_int_infallible!(Height, u16, from);
45
46impl fmt::Display for Height {
47    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
48}
49
50/// A relative lock time lock-by-blocktime value.
51///
52/// For BIP 68 relative lock-by-blocktime locks, time is measure in 512 second intervals.
53#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
54#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
55pub struct Time(u16);
56
57impl Time {
58    /// Relative block time 0, can be included in any block.
59    pub const ZERO: Self = Time(0);
60
61    /// The minimum relative block time (0), can be included in any block.
62    pub const MIN: Self = Time::ZERO;
63
64    /// The maximum relative block time (33,554,432 seconds or approx 388 days).
65    pub const MAX: Self = Time(u16::max_value());
66
67    /// Create a [`Time`] using time intervals where each interval is equivalent to 512 seconds.
68    ///
69    /// Encoding finer granularity of time for relative lock-times is not supported in Bitcoin.
70    #[inline]
71    pub const fn from_512_second_intervals(intervals: u16) -> Self { Time(intervals) }
72
73    /// Create a [`Time`] from seconds, converting the seconds into 512 second interval with
74    /// truncating division.
75    ///
76    /// # Errors
77    ///
78    /// Will return an error if the input cannot be encoded in 16 bits.
79    #[inline]
80    #[rustfmt::skip] // moves comments to unrelated code
81    pub const fn from_seconds_floor(seconds: u32) -> Result<Self, TimeOverflowError> {
82        let interval = seconds / 512;
83        if interval <= u16::MAX as u32 { // infallible cast, needed by const code
84            Ok(Time::from_512_second_intervals(interval as u16)) // cast checked above, needed by const code
85        } else {
86            Err(TimeOverflowError { seconds })
87        }
88    }
89
90    /// Create a [`Time`] from seconds, converting the seconds into 512 second interval with ceiling
91    /// division.
92    ///
93    /// # Errors
94    ///
95    /// Will return an error if the input cannot be encoded in 16 bits.
96    #[inline]
97    #[rustfmt::skip] // moves comments to unrelated code
98    pub const fn from_seconds_ceil(seconds: u32) -> Result<Self, TimeOverflowError> {
99        let interval = (seconds + 511) / 512;
100        if interval <= u16::MAX as u32 { // infallible cast, needed by const code
101            Ok(Time::from_512_second_intervals(interval as u16)) // cast checked above, needed by const code
102        } else {
103            Err(TimeOverflowError { seconds })
104        }
105    }
106
107    /// Returns the inner `u16` value.
108    #[inline]
109    pub fn value(self) -> u16 { self.0 }
110
111    /// Returns the `u32` value used to encode this locktime in an nSequence field or
112    /// argument to `OP_CHECKSEQUENCEVERIFY`.
113    #[inline]
114    pub fn to_consensus_u32(&self) -> u32 { (1u32 << 22) | u32::from(self.0) }
115}
116
117crate::impl_parse_str_from_int_infallible!(Time, u16, from_512_second_intervals);
118
119impl fmt::Display for Time {
120    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
121}
122
123/// Input time in seconds was too large to be encoded to a 16 bit 512 second interval.
124#[derive(Debug, Clone, PartialEq, Eq)]
125pub struct TimeOverflowError {
126    /// Time value in seconds that overflowed.
127    // Private because we maintain an invariant that the `seconds` value does actually overflow.
128    pub(crate) seconds: u32,
129}
130
131impl TimeOverflowError {
132    /// Creates a new `TimeOverflowError` using `seconds`.
133    ///
134    /// # Panics
135    ///
136    /// If `seconds` would not actually overflow a `u16`.
137    pub fn new(seconds: u32) -> Self {
138        assert!(u16::try_from((seconds + 511) / 512).is_err());
139        Self { seconds }
140    }
141}
142
143impl fmt::Display for TimeOverflowError {
144    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
145        write!(
146            f,
147            "{} seconds is too large to be encoded to a 16 bit 512 second interval",
148            self.seconds
149        )
150    }
151}
152
153#[cfg(feature = "std")]
154impl std::error::Error for TimeOverflowError {}