Skip to main content

bitcoin_units/locktime/absolute/
mod.rs

1// SPDX-License-Identifier: CC0-1.0
2
3//! Provides type [`LockTime`] that implements the logic around `nLockTime`/`OP_CHECKLOCKTIMEVERIFY`.
4//!
5//! There are two types of lock time: lock-by-height and lock-by-time, distinguished by
6//! whether `LockTime < LOCKTIME_THRESHOLD`. To support these we provide the [`Height`] and
7//! [`MedianTimePast`] types.
8
9pub mod error;
10
11use core::fmt;
12
13#[cfg(feature = "arbitrary")]
14use arbitrary::{Arbitrary, Unstructured};
15use internals::error::InputString;
16
17use self::error::ParseError;
18#[cfg(doc)]
19use crate::absolute;
20use crate::parse_int::{self, PrefixedHexError, UnprefixedHexError};
21
22#[rustfmt::skip]                // Keep public re-exports separate.
23#[doc(no_inline)]
24pub use self::error::{
25    ConversionError, IncompatibleHeightError, IncompatibleTimeError, ParseHeightError, ParseTimeError,
26};
27#[cfg(feature = "encoding")]
28pub use self::error::LockTimeDecoderError;
29
30/// The Threshold for deciding whether a lock time value is a height or a time (see [Bitcoin Core]).
31///
32/// `LockTime` values _below_ the threshold are interpreted as block heights, values _above_ (or
33/// equal to) the threshold are interpreted as block times (UNIX timestamp, seconds since epoch).
34///
35/// Bitcoin is able to safely use this value because a block height greater than 500,000,000 would
36/// never occur because it would represent a height in approximately 9500 years. Conversely, block
37/// times under 500,000,000 will never happen because they would represent times before 1986 which
38/// are, for obvious reasons, not useful within the Bitcoin network.
39///
40/// [Bitcoin Core]: https://github.com/bitcoin/bitcoin/blob/9ccaee1d5e2e4b79b0a7c29aadb41b97e4741332/src/script/script.h#L39
41pub const LOCK_TIME_THRESHOLD: u32 = 500_000_000;
42
43/// An absolute lock time value, representing either a block height or a UNIX timestamp (seconds
44/// since epoch).
45///
46/// Used for transaction lock time (`nLockTime` in Bitcoin Core and `Transaction::lock_time`
47/// in `rust-bitcoin`) and also for the argument to opcode `OP_CHECKLOCKTIMEVERIFY`.
48///
49/// # Note on ordering
50///
51/// Locktimes may be height- or time-based, and these metrics are incommensurate; there is no total
52/// ordering on locktimes. In order to compare locktimes, instead of using `<` or `>` we provide the
53/// [`LockTime::is_satisfied_by`] API.
54///
55/// For transaction, which has a locktime field, we implement a total ordering to make
56/// it easy to store transactions in sorted data structures, and use the locktime's 32-bit integer
57/// consensus encoding to order it.
58///
59/// # Relevant BIPs
60///
61/// * [BIP-0065 OP_CHECKLOCKTIMEVERIFY](https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki)
62/// * [BIP-0113 Median time-past as endpoint for lock-time calculations](https://github.com/bitcoin/bips/blob/master/bip-0113.mediawiki)
63///
64/// # Examples
65///
66/// ```
67/// use bitcoin_units::absolute::{self, LockTime as L};
68/// # let n = absolute::LockTime::from_consensus(741521);          // n OP_CHECKLOCKTIMEVERIFY
69/// # let lock_time = absolute::LockTime::from_consensus(741521);  // nLockTime
70/// // To compare absolute lock times there are various `is_satisfied_*` methods, you may also use:
71/// let _is_satisfied = match (n, lock_time) {
72///     (L::Blocks(n), L::Blocks(lock_time)) => n <= lock_time,
73///     (L::Seconds(n), L::Seconds(lock_time)) => n <= lock_time,
74///     _ => panic!("handle invalid comparison error"),
75/// };
76/// ```
77#[derive(Clone, Copy, PartialEq, Eq, Hash)]
78pub enum LockTime {
79    /// A block height lock time value.
80    ///
81    /// # Examples
82    ///
83    /// ```rust
84    /// use bitcoin_units::absolute;
85    ///
86    /// let block: u32 = 741521;
87    /// let n = absolute::LockTime::from_height(block).expect("valid height");
88    /// assert!(n.is_block_height());
89    /// assert_eq!(n.to_consensus_u32(), block);
90    /// ```
91    Blocks(Height),
92    /// A UNIX timestamp lock time value.
93    ///
94    /// # Examples
95    ///
96    /// ```rust
97    /// use bitcoin_units::absolute;
98    ///
99    /// let seconds: u32 = 1653195600; // May 22nd, 5am UTC.
100    /// let n = absolute::LockTime::from_mtp(seconds).expect("valid time");
101    /// assert!(n.is_block_time());
102    /// assert_eq!(n.to_consensus_u32(), seconds);
103    /// ```
104    Seconds(MedianTimePast),
105}
106
107impl LockTime {
108    /// If transaction lock time is set to zero it is ignored, in other words a
109    /// transaction with nLocktime==0 is able to be included immediately in any block.
110    pub const ZERO: Self = Self::Blocks(Height::ZERO);
111
112    /// The number of bytes that the locktime contributes to the size of a transaction.
113    pub const SIZE: usize = 4; // Serialized length of a u32.
114
115    /// Constructs a new `LockTime` from a prefixed hex string.
116    ///
117    /// # Errors
118    ///
119    /// If the input string is not a valid hex representation of a locktime or it does not include
120    /// the `0x` prefix.
121    ///
122    /// # Examples
123    ///
124    /// ```
125    /// # use bitcoin_units::{absolute, parse_int};
126    /// let hex_str = "0x61cf9980"; // Unix timestamp for January 1, 2022
127    /// let lock_time = absolute::LockTime::from_hex(hex_str)?;
128    /// assert_eq!(lock_time.to_consensus_u32(), 0x61cf9980);
129    ///
130    /// # Ok::<_, parse_int::PrefixedHexError>(())
131    /// ```
132    #[inline]
133    pub fn from_hex(s: &str) -> Result<Self, PrefixedHexError> {
134        let lock_time = parse_int::hex_u32_prefixed(s)?;
135        Ok(Self::from_consensus(lock_time))
136    }
137
138    /// Constructs a new `LockTime` from an unprefixed hex string.
139    ///
140    /// # Errors
141    ///
142    /// If the input string is not a valid hex representation of a locktime or if it includes the
143    /// `0x` prefix.
144    ///
145    /// # Examples
146    ///
147    /// ```
148    /// # use bitcoin_units::{absolute, parse_int};
149    /// let hex_str = "61cf9980"; // Unix timestamp for January 1, 2022
150    /// let lock_time = absolute::LockTime::from_unprefixed_hex(hex_str)?;
151    /// assert_eq!(lock_time.to_consensus_u32(), 0x61cf9980);
152    ///
153    /// # Ok::<_, parse_int::UnprefixedHexError>(())
154    /// ```
155    #[inline]
156    pub fn from_unprefixed_hex(s: &str) -> Result<Self, UnprefixedHexError> {
157        let lock_time = parse_int::hex_u32_unprefixed(s)?;
158        Ok(Self::from_consensus(lock_time))
159    }
160
161    /// Constructs a new `LockTime` from an `nLockTime` value or the argument to `OP_CHECKLOCKTIMEVERIFY`.
162    ///
163    /// # Examples
164    ///
165    /// ```rust
166    /// # use bitcoin_units::absolute;
167    ///
168    /// // `from_consensus` roundtrips as expected with `to_consensus_u32`.
169    /// let n_lock_time: u32 = 741521;
170    /// let lock_time = absolute::LockTime::from_consensus(n_lock_time);
171    /// assert_eq!(lock_time.to_consensus_u32(), n_lock_time);
172    #[inline]
173    #[allow(clippy::missing_panics_doc)]
174    pub fn from_consensus(n: u32) -> Self {
175        if crate::locktime::absolute::is_block_height(n) {
176            Self::Blocks(Height::from_u32(n).expect("n is valid"))
177        } else {
178            Self::Seconds(MedianTimePast::from_u32(n).expect("n is valid"))
179        }
180    }
181
182    /// Constructs a new `LockTime` from `n`, expecting `n` to be a valid block height.
183    ///
184    /// # Note
185    ///
186    /// If the current block height is `h` and the locktime is set to `h`,
187    /// the transaction can be included in block `h+1` or later.
188    /// It is possible to broadcast the transaction at block height `h`.
189    ///
190    /// See [`LOCK_TIME_THRESHOLD`] for definition of a valid height value.
191    ///
192    /// # Errors
193    ///
194    /// If `n` does not represent a block height within the valid range for a locktime:
195    /// `[0, 499_999_999]`.
196    ///
197    /// # Examples
198    ///
199    /// ```rust
200    /// # use bitcoin_units::absolute;
201    /// assert!(absolute::LockTime::from_height(741521).is_ok());
202    /// assert!(absolute::LockTime::from_height(1653195600).is_err());
203    /// ```
204    #[inline]
205    pub fn from_height(n: u32) -> Result<Self, ConversionError> {
206        let height = Height::from_u32(n)?;
207        Ok(Self::Blocks(height))
208    }
209
210    #[inline]
211    #[deprecated(since = "1.0.0-rc.0", note = "use `from_mtp` instead")]
212    #[doc(hidden)]
213    pub fn from_time(n: u32) -> Result<Self, ConversionError> { Self::from_mtp(n) }
214
215    /// Constructs a new `LockTime` from `n`, expecting `n` to be a median-time-past (MTP)
216    /// which is in range for a locktime.
217    ///
218    /// # Note
219    ///
220    /// If the locktime is set to an MTP `T`, the transaction can be included in a block only if
221    /// the MTP of last recent 11 blocks is greater than `T`.
222    ///
223    /// It is possible to broadcast the transaction once the MTP is greater than `T`. See BIP-0113.
224    ///
225    /// [BIP-0113 Median time-past as endpoint for lock-time calculations](https://github.com/bitcoin/bips/blob/master/bip-0113.mediawiki)
226    ///
227    /// See [`LOCK_TIME_THRESHOLD`] for definition of a valid time value.
228    ///
229    /// # Errors
230    ///
231    /// If `n` is not in the allowable range of MTPs in a locktime: `[500_000_000, 2^32 - 1]`.
232    ///
233    /// # Examples
234    ///
235    /// ```rust
236    /// # use bitcoin_units::absolute;
237    /// assert!(absolute::LockTime::from_mtp(1653195600).is_ok());
238    /// assert!(absolute::LockTime::from_mtp(741521).is_err());
239    /// ```
240    #[inline]
241    pub fn from_mtp(n: u32) -> Result<Self, ConversionError> {
242        let time = MedianTimePast::from_u32(n)?;
243        Ok(Self::Seconds(time))
244    }
245
246    /// Returns true if both lock times use the same unit i.e., both height based or both time based.
247    #[inline]
248    pub const fn is_same_unit(self, other: Self) -> bool {
249        matches!(
250            (self, other),
251            (Self::Blocks(_), Self::Blocks(_)) | (Self::Seconds(_), Self::Seconds(_))
252        )
253    }
254
255    /// Returns true if this lock time value is a block height.
256    #[inline]
257    pub const fn is_block_height(self) -> bool { matches!(self, Self::Blocks(_)) }
258
259    /// Returns true if this lock time value is a block time (UNIX timestamp).
260    #[inline]
261    pub const fn is_block_time(self) -> bool { !self.is_block_height() }
262
263    /// Returns true if this timelock constraint is satisfied by the respective `height`/`time`.
264    ///
265    /// If `self` is a blockheight based lock then it is checked against `height` and if `self` is a
266    /// blocktime based lock it is checked against `time`.
267    ///
268    /// A 'timelock constraint' refers to the `n` from `n OP_CHECKLOCKTIMEVERIFY`, this constraint
269    /// is satisfied if a transaction with `nLockTime` set to `height`/`time` is valid.
270    ///
271    /// If `height` and `mtp` represent the current chain tip then a transaction with this
272    /// locktime can be broadcast for inclusion in the next block.
273    ///
274    /// If you do not have, or do not wish to calculate, both parameters consider using:
275    ///
276    /// * [`is_satisfied_by_height()`](absolute::LockTime::is_satisfied_by_height)
277    /// * [`is_satisfied_by_time()`](absolute::LockTime::is_satisfied_by_time)
278    ///
279    /// # Examples
280    ///
281    /// ```no_run
282    /// # use bitcoin_units::absolute;
283    /// // Can be implemented if block chain data is available.
284    /// fn get_height() -> absolute::Height { todo!("return the current block height") }
285    /// fn get_time() -> absolute::MedianTimePast { todo!("return the current block MTP") }
286    ///
287    /// let n = absolute::LockTime::from_consensus(741521); // `n OP_CHECKLOCKTIMEVERIFY`.
288    /// if n.is_satisfied_by(get_height(), get_time()) {
289    ///     // Can create and mine a transaction that satisfies the OP_CLTV timelock constraint.
290    /// }
291    /// ````
292    #[inline]
293    pub fn is_satisfied_by(self, height: Height, mtp: MedianTimePast) -> bool {
294        match self {
295            Self::Blocks(blocks) => blocks.is_satisfied_by(height),
296            Self::Seconds(time) => time.is_satisfied_by(mtp),
297        }
298    }
299
300    /// Returns true if a transaction with this locktime can be spent in the next block.
301    ///
302    /// If `height` is the current block height of the chain then a transaction with this locktime
303    /// can be broadcast for inclusion in the next block.
304    ///
305    /// # Errors
306    ///
307    /// Returns an error if this lock is not lock-by-height.
308    #[inline]
309    pub fn is_satisfied_by_height(self, height: Height) -> Result<bool, IncompatibleHeightError> {
310        match self {
311            Self::Blocks(blocks) => Ok(blocks.is_satisfied_by(height)),
312            Self::Seconds(time) =>
313                Err(IncompatibleHeightError { lock: time, incompatible: height }),
314        }
315    }
316
317    /// Returns true if a transaction with this locktime can be included in the next block.
318    ///
319    /// # Errors
320    ///
321    /// Returns an error if this lock is not lock-by-time.
322    #[inline]
323    pub fn is_satisfied_by_time(self, mtp: MedianTimePast) -> Result<bool, IncompatibleTimeError> {
324        match self {
325            Self::Seconds(time) => Ok(time.is_satisfied_by(mtp)),
326            Self::Blocks(blocks) => Err(IncompatibleTimeError { lock: blocks, incompatible: mtp }),
327        }
328    }
329
330    /// Returns true if satisfaction of `other` lock time implies satisfaction of this
331    /// [`absolute::LockTime`].
332    ///
333    /// A lock time can only be satisfied by n blocks being mined or n seconds passing. If you have
334    /// two lock times (same unit) then the larger lock time being satisfied implies (in a
335    /// mathematical sense) the smaller one being satisfied.
336    ///
337    /// This function serves multiple purposes:
338    ///
339    /// * When evaluating `OP_CHECKLOCKTIMEVERIFY` the argument must be less than or equal to the
340    ///   transactions nLockTime. If using this function to validate a script `self` is the argument
341    ///   to `CLTV` and `other` is the transaction nLockTime.
342    ///
343    /// * If you wish to check a lock time against various other locks e.g., filtering out locks
344    ///   which cannot be satisfied. Can also be used to remove the smaller value of two
345    ///   `OP_CHECKLOCKTIMEVERIFY` operations within one branch of the script.
346    ///
347    /// # Examples
348    ///
349    /// ```rust
350    /// # use bitcoin_units::absolute;
351    /// let lock_time = absolute::LockTime::from_consensus(741521);
352    /// let check = absolute::LockTime::from_consensus(741521 + 1);
353    /// assert!(lock_time.is_implied_by(check));
354    /// ```
355    #[inline]
356    pub fn is_implied_by(self, other: Self) -> bool {
357        match (self, other) {
358            (Self::Blocks(this), Self::Blocks(other)) => this <= other,
359            (Self::Seconds(this), Self::Seconds(other)) => this <= other,
360            _ => false, // Not the same units.
361        }
362    }
363
364    /// Returns the inner `u32` value. This is the value used when creating this `LockTime`
365    /// i.e., `n OP_CHECKLOCKTIMEVERIFY` or `nLockTime`.
366    ///
367    /// # Warning
368    ///
369    /// Do not compare values return by this method. The whole point of the `LockTime` type is to
370    /// assist in doing correct comparisons. Either use `is_satisfied_by`, `is_satisfied_by_lock`,
371    /// or use the pattern below:
372    ///
373    /// # Examples
374    ///
375    /// ```rust
376    /// use bitcoin_units::absolute::{self, LockTime as L};
377    /// # let n = absolute::LockTime::from_consensus(741521);  // n OP_CHECKLOCKTIMEVERIFY
378    /// # let lock_time = absolute::LockTime::from_consensus(741521 + 1);  // nLockTime
379    ///
380    /// let _is_satisfied = match (n, lock_time) {
381    ///     (L::Blocks(n), L::Blocks(lock_time)) => n <= lock_time,
382    ///     (L::Seconds(n), L::Seconds(lock_time)) => n <= lock_time,
383    ///     _ => panic!("invalid comparison"),
384    /// };
385    ///
386    /// // Or, if you have Rust 1.53 or greater
387    /// // let is_satisfied = n.partial_cmp(&lock_time).expect("invalid comparison").is_le();
388    /// ```
389    #[inline]
390    pub fn to_consensus_u32(self) -> u32 {
391        match self {
392            Self::Blocks(ref h) => h.to_u32(),
393            Self::Seconds(ref t) => t.to_u32(),
394        }
395    }
396}
397
398parse_int::impl_parse_str_from_int_infallible!(LockTime, u32, from_consensus);
399
400#[cfg(feature = "encoding")]
401encoding::encoder_newtype_exact! {
402    /// The encoder for the [`LockTime`] type.
403    pub struct LockTimeEncoder<'e>(encoding::ArrayEncoder<4>);
404}
405
406#[cfg(feature = "encoding")]
407impl encoding::Encodable for LockTime {
408    type Encoder<'e> = LockTimeEncoder<'e>;
409    fn encoder(&self) -> Self::Encoder<'_> {
410        LockTimeEncoder::new(encoding::ArrayEncoder::without_length_prefix(
411            self.to_consensus_u32().to_le_bytes(),
412        ))
413    }
414}
415
416/// The decoder for the [`LockTime`] type.
417#[cfg(feature = "encoding")]
418pub struct LockTimeDecoder(encoding::ArrayDecoder<4>);
419
420#[cfg(feature = "encoding")]
421impl LockTimeDecoder {
422    /// Constructs a new [`LockTime`] decoder.
423    pub const fn new() -> Self { Self(encoding::ArrayDecoder::new()) }
424}
425
426#[cfg(feature = "encoding")]
427impl Default for LockTimeDecoder {
428    fn default() -> Self { Self::new() }
429}
430
431#[cfg(feature = "encoding")]
432impl encoding::Decoder for LockTimeDecoder {
433    type Output = LockTime;
434    type Error = LockTimeDecoderError;
435
436    #[inline]
437    fn push_bytes(&mut self, bytes: &mut &[u8]) -> Result<bool, Self::Error> {
438        Ok(self.0.push_bytes(bytes).map_err(LockTimeDecoderError)?)
439    }
440
441    #[inline]
442    fn end(self) -> Result<Self::Output, Self::Error> {
443        let n = u32::from_le_bytes(self.0.end().map_err(LockTimeDecoderError)?);
444        Ok(LockTime::from_consensus(n))
445    }
446
447    #[inline]
448    fn read_limit(&self) -> usize { self.0.read_limit() }
449}
450
451#[cfg(feature = "encoding")]
452impl encoding::Decodable for LockTime {
453    type Decoder = LockTimeDecoder;
454    fn decoder() -> Self::Decoder { LockTimeDecoder(encoding::ArrayDecoder::<4>::new()) }
455}
456
457impl From<Height> for LockTime {
458    #[inline]
459    fn from(h: Height) -> Self { Self::Blocks(h) }
460}
461
462impl From<MedianTimePast> for LockTime {
463    #[inline]
464    fn from(t: MedianTimePast) -> Self { Self::Seconds(t) }
465}
466
467impl fmt::Debug for LockTime {
468    #[inline]
469    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
470        match *self {
471            Self::Blocks(ref h) => write!(f, "{} blocks", h),
472            Self::Seconds(ref t) => write!(f, "{} seconds", t),
473        }
474    }
475}
476
477impl fmt::Display for LockTime {
478    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
479        if f.alternate() {
480            match *self {
481                Self::Blocks(ref h) => write!(f, "block-height {}", h),
482                Self::Seconds(ref t) => write!(f, "block-time {} (seconds since epoch)", t),
483            }
484        } else {
485            match *self {
486                Self::Blocks(ref h) => fmt::Display::fmt(h, f),
487                Self::Seconds(ref t) => fmt::Display::fmt(t, f),
488            }
489        }
490    }
491}
492
493#[cfg(feature = "serde")]
494impl serde::Serialize for LockTime {
495    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
496    where
497        S: serde::Serializer,
498    {
499        self.to_consensus_u32().serialize(serializer)
500    }
501}
502
503#[cfg(feature = "serde")]
504impl<'de> serde::Deserialize<'de> for LockTime {
505    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
506    where
507        D: serde::Deserializer<'de>,
508    {
509        u32::deserialize(deserializer).map(Self::from_consensus)
510    }
511}
512
513/// An absolute block height, guaranteed to always contain a valid height value.
514#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
515pub struct Height(u32);
516
517impl Height {
518    /// Absolute block height 0, the genesis block.
519    pub const ZERO: Self = Self(0);
520
521    /// The minimum absolute block height (0), the genesis block.
522    pub const MIN: Self = Self::ZERO;
523
524    /// The maximum absolute block height.
525    pub const MAX: Self = Self(LOCK_TIME_THRESHOLD - 1);
526
527    /// Constructs a new [`Height`] from a hex string.
528    ///
529    /// The input string may or may not contain a typical hex prefix e.g., `0x`.
530    ///
531    /// # Errors
532    ///
533    /// If the input string is not a valid hex representation of a block height.
534    pub fn from_hex(s: &str) -> Result<Self, ParseHeightError> { parse_hex(s, Self::from_u32) }
535
536    #[deprecated(since = "1.0.0-rc.0", note = "use `from_u32` instead")]
537    #[doc(hidden)]
538    pub const fn from_consensus(n: u32) -> Result<Self, ConversionError> { Self::from_u32(n) }
539
540    #[deprecated(since = "1.0.0-rc.0", note = "use `to_u32` instead")]
541    #[doc(hidden)]
542    pub const fn to_consensus_u32(self) -> u32 { self.to_u32() }
543
544    /// Constructs a new block height directly from a `u32` value.
545    ///
546    /// # Errors
547    ///
548    /// If `n` does not represent a block height within the valid range for a locktime:
549    /// `[0, 499_999_999]`.
550    ///
551    /// # Examples
552    ///
553    /// ```rust
554    /// use bitcoin_units::locktime::absolute;
555    ///
556    /// let h: u32 = 741521;
557    /// let height = absolute::Height::from_u32(h)?;
558    /// assert_eq!(height.to_u32(), h);
559    /// # Ok::<_, absolute::error::ConversionError>(())
560    /// ```
561    #[inline]
562    pub const fn from_u32(n: u32) -> Result<Self, ConversionError> {
563        if is_block_height(n) {
564            Ok(Self(n))
565        } else {
566            Err(ConversionError::invalid_height(n))
567        }
568    }
569
570    /// Converts this [`Height`] to a raw `u32` value.
571    ///
572    /// # Examples
573    ///
574    /// ```rust
575    /// use bitcoin_units::locktime::absolute;
576    ///
577    /// assert_eq!(absolute::Height::MAX.to_u32(), 499_999_999);
578    /// ```
579    #[inline]
580    pub const fn to_u32(self) -> u32 { self.0 }
581
582    /// Returns true if a transaction with this locktime can be included in the next block.
583    ///
584    /// `self` is value of the `LockTime` and if `height` is the current chain tip then
585    /// a transaction with this lock can be broadcast for inclusion in the next block.
586    #[inline]
587    pub fn is_satisfied_by(self, height: Self) -> bool {
588        // Use u64 so that there can be no overflow.
589        let next_block_height = u64::from(height.to_u32()) + 1;
590        u64::from(self.to_u32()) <= next_block_height
591    }
592}
593
594crate::internal_macros::impl_fmt_traits_for_u32_wrapper!(Height);
595
596impl fmt::Display for Height {
597    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
598}
599
600parse_int::impl_parse_str!(Height, ParseHeightError, parser(Height::from_u32));
601
602#[deprecated(since = "1.0.0-rc.0", note = "use `MedianTimePast` instead")]
603#[doc(hidden)]
604pub type Time = MedianTimePast;
605
606/// The median timestamp of 11 consecutive blocks, representing "the timestamp" of the
607/// final block for locktime-checking purposes.
608///
609/// Time-based locktimes are not measured against the timestamps in individual block
610/// headers, since these are not monotone and may be subject to miner manipulation.
611/// Instead, locktimes use the "median-time-past" (MTP) of the most recent 11 blocks,
612/// a quantity which is required by consensus to be monotone and which is difficult
613/// for any individual miner to manipulate.
614#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
615pub struct MedianTimePast(u32);
616
617impl MedianTimePast {
618    /// The minimum MTP allowable in a locktime (Tue Nov 05 1985 00:53:20 GMT+0000).
619    pub const MIN: Self = Self(LOCK_TIME_THRESHOLD);
620
621    /// The maximum MTP allowable in a locktime (Sun Feb 07 2106 06:28:15 GMT+0000).
622    pub const MAX: Self = Self(u32::MAX);
623
624    /// Constructs an [`MedianTimePast`] by computing the median-time-past from the last
625    /// 11 block timestamps.
626    ///
627    /// Because block timestamps are not monotonic, this function internally sorts them;
628    /// it is therefore not important what order they appear in the array; use whatever
629    /// is most convenient.
630    ///
631    /// # Errors
632    ///
633    /// If the median block timestamp is not in the allowable range of MTPs in a
634    /// locktime: `[500_000_000, 2^32 - 1]`. Because there is a consensus rule that MTP
635    /// be monotonically increasing, and the MTP of the first 11 blocks exceeds `500_000_000`
636    /// for every real-life chain, this error typically cannot be hit in practice.
637    pub fn new(timestamps: [crate::BlockTime; 11]) -> Result<Self, ConversionError> {
638        crate::BlockMtp::new(timestamps).try_into()
639    }
640
641    /// Constructs a new [`MedianTimePast`] from a big-endian hex-encoded `u32`.
642    ///
643    /// The input string may or may not contain a typical hex prefix e.g., `0x`.
644    ///
645    /// # Errors
646    ///
647    /// If the input string is not a valid hex representation of a block time.
648    pub fn from_hex(s: &str) -> Result<Self, ParseTimeError> { parse_hex(s, Self::from_u32) }
649
650    #[deprecated(since = "1.0.0-rc.0", note = "use `from_u32` instead")]
651    #[doc(hidden)]
652    pub const fn from_consensus(n: u32) -> Result<Self, ConversionError> { Self::from_u32(n) }
653
654    #[deprecated(since = "1.0.0-rc.0", note = "use `to_u32` instead")]
655    #[doc(hidden)]
656    pub const fn to_consensus_u32(self) -> u32 { self.to_u32() }
657
658    /// Constructs a new MTP directly from a `u32` value.
659    ///
660    /// This function, with [`MedianTimePast::to_u32`], is used to obtain a raw MTP value. It is
661    /// **not** used to convert to or from a block timestamp, which is not a MTP.
662    ///
663    /// # Errors
664    ///
665    /// If `n` is not in the allowable range of MTPs in a locktime: `[500_000_000, 2^32 - 1]`.
666    ///
667    /// # Examples
668    ///
669    /// ```rust
670    /// use bitcoin_units::locktime::absolute;
671    ///
672    /// let t: u32 = 1653195600; // May 22nd, 5am UTC.
673    /// let time = absolute::MedianTimePast::from_u32(t)?;
674    /// assert_eq!(time.to_u32(), t);
675    /// # Ok::<_, absolute::error::ConversionError>(())
676    /// ```
677    #[inline]
678    pub const fn from_u32(n: u32) -> Result<Self, ConversionError> {
679        if is_block_time(n) {
680            Ok(Self(n))
681        } else {
682            Err(ConversionError::invalid_time(n))
683        }
684    }
685
686    /// Converts this [`MedianTimePast`] to a raw `u32` value.
687    ///
688    /// # Examples
689    ///
690    /// ```rust
691    /// use bitcoin_units::locktime::absolute;
692    ///
693    /// assert_eq!(absolute::MedianTimePast::MIN.to_u32(), 500_000_000);
694    /// ```
695    #[inline]
696    pub const fn to_u32(self) -> u32 { self.0 }
697
698    /// Returns true if a transaction with this locktime can be included in the next block.
699    ///
700    /// `self` is the value of the `LockTime` and if `time` is the median time past of the block at
701    /// the chain tip then a transaction with this lock can be broadcast for inclusion in the next
702    /// block.
703    #[inline]
704    pub fn is_satisfied_by(self, time: Self) -> bool {
705        // The locktime check in Core during block validation uses the MTP
706        // of the previous block - which is the expected to be `time` here.
707        self <= time
708    }
709}
710
711crate::internal_macros::impl_fmt_traits_for_u32_wrapper!(MedianTimePast);
712
713impl fmt::Display for MedianTimePast {
714    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
715}
716
717parse_int::impl_parse_str!(MedianTimePast, ParseTimeError, parser(MedianTimePast::from_u32));
718
719fn parser<T, E, S, F>(f: F) -> impl FnOnce(S) -> Result<T, E>
720where
721    E: From<ParseError>,
722    S: AsRef<str> + Into<InputString>,
723    F: FnOnce(u32) -> Result<T, ConversionError>,
724{
725    move |s| {
726        let n = s.as_ref().parse::<i64>().map_err(ParseError::invalid_int(s))?;
727        let n = u32::try_from(n).map_err(|_| ParseError::Conversion(n))?;
728        f(n).map_err(ParseError::from).map_err(Into::into)
729    }
730}
731
732fn parse_hex<T, E, S, F>(s: S, f: F) -> Result<T, E>
733where
734    E: From<ParseError>,
735    S: AsRef<str> + Into<InputString>,
736    F: FnOnce(u32) -> Result<T, ConversionError>,
737{
738    let n = i64::from_str_radix(parse_int::hex_remove_optional_prefix(s.as_ref()), 16)
739        .map_err(ParseError::invalid_int(s))?;
740    let n = u32::try_from(n).map_err(|_| ParseError::Conversion(n))?;
741    f(n).map_err(ParseError::from).map_err(Into::into)
742}
743
744/// Returns true if `n` is a block height i.e., less than 500,000,000.
745pub const fn is_block_height(n: u32) -> bool { n < LOCK_TIME_THRESHOLD }
746
747/// Returns true if `n` is a UNIX timestamp i.e., greater than or equal to 500,000,000.
748pub const fn is_block_time(n: u32) -> bool { n >= LOCK_TIME_THRESHOLD }
749
750#[cfg(feature = "arbitrary")]
751impl<'a> Arbitrary<'a> for LockTime {
752    fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
753        let l = u32::arbitrary(u)?;
754        Ok(Self::from_consensus(l))
755    }
756}
757
758#[cfg(feature = "arbitrary")]
759impl<'a> Arbitrary<'a> for Height {
760    fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
761        let choice = u.int_in_range(0..=2)?;
762        match choice {
763            0 => Ok(Self::MIN),
764            1 => Ok(Self::MAX),
765            _ => {
766                let min = Self::MIN.to_u32();
767                let max = Self::MAX.to_u32();
768                let h = u.int_in_range(min..=max)?;
769                Ok(Self::from_u32(h).unwrap())
770            }
771        }
772    }
773}
774
775#[cfg(feature = "arbitrary")]
776impl<'a> Arbitrary<'a> for MedianTimePast {
777    fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
778        let choice = u.int_in_range(0..=2)?;
779        match choice {
780            0 => Ok(Self::MIN),
781            1 => Ok(Self::MAX),
782            _ => {
783                let min = Self::MIN.to_u32();
784                let max = Self::MAX.to_u32();
785                let t = u.int_in_range(min..=max)?;
786                Ok(Self::from_u32(t).unwrap())
787            }
788        }
789    }
790}
791
792#[cfg(test)]
793mod tests {
794    #[cfg(feature = "alloc")]
795    use alloc::{boxed::Box, format, string::String};
796
797    use super::*;
798
799    #[test]
800    #[cfg(feature = "alloc")]
801    fn display_and_alternate() {
802        let lock_by_height = LockTime::from_height(741_521).unwrap();
803        let lock_by_time = LockTime::from_mtp(1_653_195_600).unwrap(); // May 22nd 2022, 5am UTC.
804
805        assert_eq!(format!("{}", lock_by_height), "741521");
806        assert_eq!(format!("{:#}", lock_by_height), "block-height 741521");
807        assert!(!format!("{:?}", lock_by_height).is_empty());
808
809        assert_eq!(format!("{}", lock_by_time), "1653195600");
810        assert_eq!(format!("{:#}", lock_by_time), "block-time 1653195600 (seconds since epoch)");
811        assert!(!format!("{:?}", lock_by_time).is_empty());
812    }
813
814    #[test]
815    fn roundtrips() {
816        let lock_by_height = LockTime::from_consensus(741_521);
817        let lock_by_time = LockTime::from_consensus(1_653_195_600);
818
819        assert_eq!(lock_by_height.to_consensus_u32(), 741_521);
820        assert_eq!(lock_by_time.to_consensus_u32(), 1_653_195_600);
821    }
822
823    #[test]
824    fn lock_time_from_hex_lower() {
825        let lock_by_time = LockTime::from_hex("0x6289c350").unwrap();
826        assert_eq!(lock_by_time, LockTime::from_consensus(0x6289_C350));
827    }
828
829    #[test]
830    fn lock_time_from_hex_upper() {
831        let lock_by_time = LockTime::from_hex("0X6289C350").unwrap();
832        assert_eq!(lock_by_time, LockTime::from_consensus(0x6289_C350));
833    }
834
835    #[test]
836    fn lock_time_from_unprefixed_hex_lower() {
837        let lock_by_time = LockTime::from_unprefixed_hex("6289c350").unwrap();
838        assert_eq!(lock_by_time, LockTime::from_consensus(0x6289_C350));
839    }
840
841    #[test]
842    fn lock_time_from_unprefixed_hex_upper() {
843        let lock_by_time = LockTime::from_unprefixed_hex("6289C350").unwrap();
844        assert_eq!(lock_by_time, LockTime::from_consensus(0x6289_C350));
845    }
846
847    #[test]
848    fn invalid_hex() {
849        assert!(LockTime::from_hex("0xzb93").is_err());
850        assert!(LockTime::from_unprefixed_hex("zb93").is_err());
851    }
852
853    #[test]
854    fn invalid_locktime_type() {
855        assert!(LockTime::from_height(499_999_999).is_ok()); // Below the threshold.
856        assert!(LockTime::from_height(500_000_000).is_err()); // The threshold.
857        assert!(LockTime::from_height(500_000_001).is_err()); // Above the threshold.
858
859        assert!(LockTime::from_mtp(499_999_999).is_err()); // Below the threshold.
860        assert!(LockTime::from_mtp(500_000_000).is_ok()); // The threshold.
861        assert!(LockTime::from_mtp(500_000_001).is_ok()); // Above the threshold.
862    }
863
864    #[test]
865    fn parses_correctly_to_height_or_time() {
866        let lock_by_height = LockTime::from_consensus(750_000);
867
868        assert!(lock_by_height.is_block_height());
869        assert!(!lock_by_height.is_block_time());
870
871        let t: u32 = 1_653_195_600; // May 22nd, 5am UTC.
872        let lock_by_time = LockTime::from_consensus(t);
873
874        assert!(!lock_by_time.is_block_height());
875        assert!(lock_by_time.is_block_time());
876
877        // Test is_same_unit() logic
878        assert!(lock_by_height.is_same_unit(LockTime::from_consensus(800_000)));
879        assert!(!lock_by_height.is_same_unit(lock_by_time));
880        assert!(lock_by_time.is_same_unit(LockTime::from_consensus(1_653_282_000)));
881        assert!(!lock_by_time.is_same_unit(lock_by_height));
882    }
883
884    #[test]
885    fn satisfied_by_height() {
886        let height_below = Height::from_u32(700_000).unwrap();
887        let height = Height::from_u32(750_000).unwrap();
888        let height_above = Height::from_u32(800_000).unwrap();
889
890        let lock_by_height = LockTime::from(height);
891
892        let t: u32 = 1_653_195_600; // May 22nd, 5am UTC.
893        let time = MedianTimePast::from_u32(t).unwrap();
894
895        assert!(!lock_by_height.is_satisfied_by(height_below, time));
896        assert!(lock_by_height.is_satisfied_by(height, time));
897        assert!(lock_by_height.is_satisfied_by(height_above, time));
898    }
899
900    #[test]
901    fn satisfied_by_time() {
902        let time_before = MedianTimePast::from_u32(1_653_109_200).unwrap(); // "May 21th 2022, 5am UTC.
903        let time = MedianTimePast::from_u32(1_653_195_600).unwrap(); // "May 22nd 2022, 5am UTC.
904        let time_after = MedianTimePast::from_u32(1_653_282_000).unwrap(); // "May 23rd 2022, 5am UTC.
905
906        let lock_by_time = LockTime::from(time);
907
908        let height = Height::from_u32(800_000).unwrap();
909
910        assert!(!lock_by_time.is_satisfied_by(height, time_before));
911        assert!(lock_by_time.is_satisfied_by(height, time));
912        assert!(lock_by_time.is_satisfied_by(height, time_after));
913    }
914
915    #[test]
916    fn height_correctly_implies() {
917        let lock_by_height = LockTime::from_consensus(750_005);
918
919        assert!(!lock_by_height.is_implied_by(LockTime::from_consensus(750_004)));
920        assert!(lock_by_height.is_implied_by(LockTime::from_consensus(750_005)));
921        assert!(lock_by_height.is_implied_by(LockTime::from_consensus(750_006)));
922    }
923
924    #[test]
925    fn time_correctly_implies() {
926        let t: u32 = 1_700_000_005;
927        let lock_by_time = LockTime::from_consensus(t);
928
929        assert!(!lock_by_time.is_implied_by(LockTime::from_consensus(1_700_000_004)));
930        assert!(lock_by_time.is_implied_by(LockTime::from_consensus(1_700_000_005)));
931        assert!(lock_by_time.is_implied_by(LockTime::from_consensus(1_700_000_006)));
932    }
933
934    #[test]
935    fn incorrect_units_do_not_imply() {
936        let lock_by_height = LockTime::from_consensus(750_005);
937        assert!(!lock_by_height.is_implied_by(LockTime::from_consensus(1_700_000_004)));
938    }
939
940    #[test]
941    fn time_from_str_hex_happy_path() {
942        let actual = MedianTimePast::from_hex("0x6289C350").unwrap();
943        let expected = MedianTimePast::from_u32(0x6289_C350).unwrap();
944        assert_eq!(actual, expected);
945    }
946
947    #[test]
948    fn time_from_str_hex_no_prefix_happy_path() {
949        let time = MedianTimePast::from_hex("6289C350").unwrap();
950        assert_eq!(time, MedianTimePast(0x6289_C350));
951    }
952
953    #[test]
954    fn time_from_str_hex_invalid_hex_should_err() {
955        let hex = "0xzb93";
956        let result = MedianTimePast::from_hex(hex);
957        assert!(result.is_err());
958    }
959
960    #[test]
961    fn height_from_str_hex_happy_path() {
962        let actual = Height::from_hex("0xBA70D").unwrap();
963        let expected = Height(0xBA70D);
964        assert_eq!(actual, expected);
965    }
966
967    #[test]
968    fn height_from_str_hex_no_prefix_happy_path() {
969        let height = Height::from_hex("BA70D").unwrap();
970        assert_eq!(height, Height(0xBA70D));
971    }
972
973    #[test]
974    fn height_from_str_hex_invalid_hex_should_err() {
975        let hex = "0xzb93";
976        let result = Height::from_hex(hex);
977        assert!(result.is_err());
978    }
979
980    #[test]
981    fn height_try_from_stringlike_happy_path() {
982        let want = Height::from_u32(10).unwrap();
983        assert_eq!("10".parse::<Height>().unwrap(), want);
984        assert_eq!(Height::try_from("10").unwrap(), want);
985        #[cfg(feature = "alloc")]
986        {
987            assert_eq!(Height::try_from(String::from("10")).unwrap(), want);
988            assert_eq!(Height::try_from(Box::<str>::from("10")).unwrap(), want);
989        }
990    }
991
992    #[test]
993    fn height_try_from_stringlike_hex_error_path() {
994        // Only base-10 values should parse
995        assert!("0xab".parse::<Height>().is_err());
996        assert!(Height::try_from("0xab").is_err());
997        #[cfg(feature = "alloc")]
998        {
999            assert!(Height::try_from(String::from("0xab")).is_err());
1000            assert!(Height::try_from(Box::<str>::from("0xab")).is_err());
1001        }
1002    }
1003
1004    #[test]
1005    fn height_try_from_stringlike_decimal_error_path() {
1006        // Only integers should parse
1007        assert!("10.123".parse::<Height>().is_err());
1008        assert!(Height::try_from("10.123").is_err());
1009        #[cfg(feature = "alloc")]
1010        {
1011            assert!(Height::try_from(String::from("10.123")).is_err());
1012            assert!(Height::try_from(Box::<str>::from("10.123")).is_err());
1013        }
1014    }
1015
1016    #[test]
1017    fn is_block_height_or_time() {
1018        assert!(is_block_height(499_999_999));
1019        assert!(!is_block_height(500_000_000));
1020
1021        assert!(!is_block_time(499_999_999));
1022        assert!(is_block_time(500_000_000));
1023    }
1024
1025    #[test]
1026    fn valid_chain_computes_mtp() {
1027        use crate::BlockTime;
1028
1029        let mut timestamps = [
1030            BlockTime::from_u32(500_000_010),
1031            BlockTime::from_u32(500_000_003),
1032            BlockTime::from_u32(500_000_005),
1033            BlockTime::from_u32(500_000_008),
1034            BlockTime::from_u32(500_000_001),
1035            BlockTime::from_u32(500_000_004),
1036            BlockTime::from_u32(500_000_006),
1037            BlockTime::from_u32(500_000_009),
1038            BlockTime::from_u32(500_000_002),
1039            BlockTime::from_u32(500_000_007),
1040            BlockTime::from_u32(500_000_000),
1041        ];
1042
1043        // Try various reorderings
1044        assert_eq!(MedianTimePast::new(timestamps).unwrap().to_u32(), 500_000_005);
1045        timestamps.reverse();
1046        assert_eq!(MedianTimePast::new(timestamps).unwrap().to_u32(), 500_000_005);
1047        timestamps.sort();
1048        assert_eq!(MedianTimePast::new(timestamps).unwrap().to_u32(), 500_000_005);
1049        timestamps.reverse();
1050        assert_eq!(MedianTimePast::new(timestamps).unwrap().to_u32(), 500_000_005);
1051    }
1052
1053    #[test]
1054    fn height_is_satisfied_by() {
1055        let chain_tip = Height::from_u32(100).unwrap();
1056
1057        // lock is satisfied if transaction can go in the next block (height <= chain_tip + 1).
1058        let locktime = Height::from_u32(100).unwrap();
1059        assert!(locktime.is_satisfied_by(chain_tip));
1060        let locktime = Height::from_u32(101).unwrap();
1061        assert!(locktime.is_satisfied_by(chain_tip));
1062
1063        // It is not satisfied if the lock height is after the next block.
1064        let locktime = Height::from_u32(102).unwrap();
1065        assert!(!locktime.is_satisfied_by(chain_tip));
1066    }
1067
1068    #[test]
1069    fn median_time_past_is_satisfied_by() {
1070        let mtp = MedianTimePast::from_u32(500_000_001).unwrap();
1071
1072        // lock is satisfied if transaction can go in the next block (locktime <= mtp).
1073        let locktime = MedianTimePast::from_u32(500_000_000).unwrap();
1074        assert!(locktime.is_satisfied_by(mtp));
1075        let locktime = MedianTimePast::from_u32(500_000_001).unwrap();
1076        assert!(locktime.is_satisfied_by(mtp));
1077
1078        // It is not satisfied if the lock time is after the median time past.
1079        let locktime = MedianTimePast::from_u32(500_000_002).unwrap();
1080        assert!(!locktime.is_satisfied_by(mtp));
1081    }
1082}