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")]
401impl encoding::Encode for LockTime {
402    type Encoder<'e> = LockTimeEncoder<'e>;
403    #[inline]
404    fn encoder(&self) -> Self::Encoder<'_> {
405        LockTimeEncoder::new(encoding::ArrayEncoder::without_length_prefix(
406            self.to_consensus_u32().to_le_bytes(),
407        ))
408    }
409}
410
411#[cfg(feature = "encoding")]
412impl encoding::Decode for LockTime {
413    type Decoder = LockTimeDecoder;
414}
415
416#[cfg(feature = "encoding")]
417encoding::encoder_newtype_exact! {
418    /// The encoder for the [`LockTime`] type.
419    #[derive(Debug, Clone)]
420    pub struct LockTimeEncoder<'e>(encoding::ArrayEncoder<4>);
421}
422
423#[cfg(feature = "encoding")]
424crate::decoder_newtype! {
425    /// The decoder for the [`LockTime`] type.
426    #[derive(Debug, Clone)]
427    pub struct LockTimeDecoder(encoding::ArrayDecoder<4>);
428
429    /// Constructs a new [`LockTime`] decoder.
430    pub const fn new() -> Self { Self(encoding::ArrayDecoder::new()) }
431
432    fn end(result: Result<[u8; 4], encoding::UnexpectedEofError>) -> Result<LockTime, LockTimeDecoderError> {
433        let value = result.map_err(LockTimeDecoderError)?;
434        let n = u32::from_le_bytes(value);
435        Ok(LockTime::from_consensus(n))
436    }
437}
438
439impl From<Height> for LockTime {
440    #[inline]
441    fn from(h: Height) -> Self { Self::Blocks(h) }
442}
443
444impl From<MedianTimePast> for LockTime {
445    #[inline]
446    fn from(t: MedianTimePast) -> Self { Self::Seconds(t) }
447}
448
449impl fmt::Debug for LockTime {
450    #[inline]
451    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
452        match *self {
453            Self::Blocks(ref h) => write!(f, "{} blocks", h),
454            Self::Seconds(ref t) => write!(f, "{} seconds", t),
455        }
456    }
457}
458
459impl fmt::Display for LockTime {
460    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
461        if f.alternate() {
462            match *self {
463                Self::Blocks(ref h) => write!(f, "block-height {}", h),
464                Self::Seconds(ref t) => write!(f, "block-time {} (seconds since epoch)", t),
465            }
466        } else {
467            match *self {
468                Self::Blocks(ref h) => fmt::Display::fmt(h, f),
469                Self::Seconds(ref t) => fmt::Display::fmt(t, f),
470            }
471        }
472    }
473}
474
475#[cfg(feature = "serde")]
476impl serde::Serialize for LockTime {
477    #[inline]
478    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
479    where
480        S: serde::Serializer,
481    {
482        self.to_consensus_u32().serialize(serializer)
483    }
484}
485
486#[cfg(feature = "serde")]
487impl<'de> serde::Deserialize<'de> for LockTime {
488    #[inline]
489    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
490    where
491        D: serde::Deserializer<'de>,
492    {
493        u32::deserialize(deserializer).map(Self::from_consensus)
494    }
495}
496
497/// An absolute block height, guaranteed to always contain a valid height value.
498#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
499pub struct Height(u32);
500
501impl Height {
502    /// Absolute block height 0, the genesis block.
503    pub const ZERO: Self = Self(0);
504
505    /// The minimum absolute block height (0), the genesis block.
506    pub const MIN: Self = Self::ZERO;
507
508    /// The maximum absolute block height.
509    pub const MAX: Self = Self(LOCK_TIME_THRESHOLD - 1);
510
511    /// Constructs a new [`Height`] from a prefixed hex string.
512    ///
513    /// # Errors
514    ///
515    /// If the input string is not a valid hex representation of a block height or it does not
516    /// include the `0x` prefix.
517    #[inline]
518    pub fn from_hex(s: &str) -> Result<Self, ParseHeightError> {
519        let height = parse_int::hex_u32_prefixed(s).map_err(ParseError::PrefixedHex)?;
520        Ok(Self::from_u32(height).map_err(|_| ParseError::Conversion(height.into()))?)
521    }
522
523    /// Constructs a new [`Height`] from an unprefixed hex string.
524    ///
525    /// # Errors
526    ///
527    /// If the input string is not a valid hex representation of a block height or if it
528    /// includes the `0x` prefix.
529    #[inline]
530    pub fn from_unprefixed_hex(s: &str) -> Result<Self, ParseHeightError> {
531        let height = parse_int::hex_u32_unprefixed(s).map_err(ParseError::UnprefixedHex)?;
532        Ok(Self::from_u32(height).map_err(|_| ParseError::Conversion(height.into()))?)
533    }
534
535    #[deprecated(since = "1.0.0-rc.0", note = "use `from_u32` instead")]
536    #[doc(hidden)]
537    pub const fn from_consensus(n: u32) -> Result<Self, ConversionError> { Self::from_u32(n) }
538
539    #[deprecated(since = "1.0.0-rc.0", note = "use `to_u32` instead")]
540    #[doc(hidden)]
541    pub const fn to_consensus_u32(self) -> u32 { self.to_u32() }
542
543    /// Constructs a new block height directly from a `u32` value.
544    ///
545    /// # Errors
546    ///
547    /// If `n` does not represent a block height within the valid range for a locktime:
548    /// `[0, 499_999_999]`.
549    ///
550    /// # Examples
551    ///
552    /// ```rust
553    /// use bitcoin_units::locktime::absolute;
554    ///
555    /// let h: u32 = 741521;
556    /// let height = absolute::Height::from_u32(h)?;
557    /// assert_eq!(height.to_u32(), h);
558    /// # Ok::<_, absolute::error::ConversionError>(())
559    /// ```
560    #[inline]
561    pub const fn from_u32(n: u32) -> Result<Self, ConversionError> {
562        if is_block_height(n) {
563            Ok(Self(n))
564        } else {
565            Err(ConversionError::invalid_height(n))
566        }
567    }
568
569    /// Converts this [`Height`] to a raw `u32` value.
570    ///
571    /// # Examples
572    ///
573    /// ```rust
574    /// use bitcoin_units::locktime::absolute;
575    ///
576    /// assert_eq!(absolute::Height::MAX.to_u32(), 499_999_999);
577    /// ```
578    #[inline]
579    pub const fn to_u32(self) -> u32 { self.0 }
580
581    /// Returns true if a transaction with this locktime can be included in the next block.
582    ///
583    /// `self` is value of the `LockTime` and if `height` is the current chain tip then
584    /// a transaction with this lock can be broadcast for inclusion in the next block.
585    #[inline]
586    pub fn is_satisfied_by(self, height: Self) -> bool {
587        // Use u64 so that there can be no overflow.
588        let next_block_height = u64::from(height.to_u32()) + 1;
589        u64::from(self.to_u32()) <= next_block_height
590    }
591}
592
593crate::internal_macros::impl_fmt_traits_for_u32_wrapper!(Height);
594
595impl fmt::Display for Height {
596    #[inline]
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    #[inline]
638    pub fn new(timestamps: [crate::BlockTime; 11]) -> Result<Self, ConversionError> {
639        crate::BlockMtp::new(timestamps).try_into()
640    }
641
642    /// Constructs a new [`MedianTimePast`] from a prefixed hex string.
643    ///
644    /// # Errors
645    ///
646    /// If the input string is not a valid hex representation of a block time or it does not
647    /// include the `0x` prefix.
648    #[inline]
649    pub fn from_hex(s: &str) -> Result<Self, ParseTimeError> {
650        let height = parse_int::hex_u32_prefixed(s).map_err(ParseError::PrefixedHex)?;
651        Ok(Self::from_u32(height).map_err(|_| ParseError::Conversion(height.into()))?)
652    }
653
654    /// Constructs a new [`MedianTimePast`] from an unprefixed hex string.
655    ///
656    /// # Errors
657    ///
658    /// If the input string is not a valid hex representation of a block time or if it
659    /// includes the `0x` prefix.
660    #[inline]
661    pub fn from_unprefixed_hex(s: &str) -> Result<Self, ParseTimeError> {
662        let height = parse_int::hex_u32_unprefixed(s).map_err(ParseError::UnprefixedHex)?;
663        Ok(Self::from_u32(height).map_err(|_| ParseError::Conversion(height.into()))?)
664    }
665
666    #[deprecated(since = "1.0.0-rc.0", note = "use `from_u32` instead")]
667    #[doc(hidden)]
668    pub const fn from_consensus(n: u32) -> Result<Self, ConversionError> { Self::from_u32(n) }
669
670    #[deprecated(since = "1.0.0-rc.0", note = "use `to_u32` instead")]
671    #[doc(hidden)]
672    pub const fn to_consensus_u32(self) -> u32 { self.to_u32() }
673
674    /// Constructs a new MTP directly from a `u32` value.
675    ///
676    /// This function, with [`MedianTimePast::to_u32`], is used to obtain a raw MTP value. It is
677    /// **not** used to convert to or from a block timestamp, which is not a MTP.
678    ///
679    /// # Errors
680    ///
681    /// If `n` is not in the allowable range of MTPs in a locktime: `[500_000_000, 2^32 - 1]`.
682    ///
683    /// # Examples
684    ///
685    /// ```rust
686    /// use bitcoin_units::locktime::absolute;
687    ///
688    /// let t: u32 = 1653195600; // May 22nd, 5am UTC.
689    /// let time = absolute::MedianTimePast::from_u32(t)?;
690    /// assert_eq!(time.to_u32(), t);
691    /// # Ok::<_, absolute::error::ConversionError>(())
692    /// ```
693    #[inline]
694    pub const fn from_u32(n: u32) -> Result<Self, ConversionError> {
695        if is_block_time(n) {
696            Ok(Self(n))
697        } else {
698            Err(ConversionError::invalid_time(n))
699        }
700    }
701
702    /// Converts this [`MedianTimePast`] to a raw `u32` value.
703    ///
704    /// # Examples
705    ///
706    /// ```rust
707    /// use bitcoin_units::locktime::absolute;
708    ///
709    /// assert_eq!(absolute::MedianTimePast::MIN.to_u32(), 500_000_000);
710    /// ```
711    #[inline]
712    pub const fn to_u32(self) -> u32 { self.0 }
713
714    /// Returns true if a transaction with this locktime can be included in the next block.
715    ///
716    /// `self` is the value of the `LockTime` and if `time` is the median time past of the block at
717    /// the chain tip then a transaction with this lock can be broadcast for inclusion in the next
718    /// block.
719    #[inline]
720    pub fn is_satisfied_by(self, time: Self) -> bool {
721        // The locktime check in Core during block validation uses the MTP
722        // of the previous block - which is the expected to be `time` here.
723        self <= time
724    }
725}
726
727crate::internal_macros::impl_fmt_traits_for_u32_wrapper!(MedianTimePast);
728
729impl fmt::Display for MedianTimePast {
730    #[inline]
731    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
732}
733
734parse_int::impl_parse_str!(MedianTimePast, ParseTimeError, parser(MedianTimePast::from_u32));
735
736fn parser<T, E, S, F>(f: F) -> impl FnOnce(S) -> Result<T, E>
737where
738    E: From<ParseError>,
739    S: AsRef<str> + Into<InputString>,
740    F: FnOnce(u32) -> Result<T, ConversionError>,
741{
742    move |s| {
743        let n = s.as_ref().parse::<i64>().map_err(ParseError::invalid_int(s))?;
744        let n = u32::try_from(n).map_err(|_| ParseError::Conversion(n))?;
745        f(n).map_err(ParseError::from).map_err(Into::into)
746    }
747}
748
749/// Returns true if `n` is a block height i.e., less than 500,000,000.
750#[inline]
751pub const fn is_block_height(n: u32) -> bool { n < LOCK_TIME_THRESHOLD }
752
753/// Returns true if `n` is a UNIX timestamp i.e., greater than or equal to 500,000,000.
754#[inline]
755pub const fn is_block_time(n: u32) -> bool { n >= LOCK_TIME_THRESHOLD }
756
757#[cfg(feature = "arbitrary")]
758impl<'a> Arbitrary<'a> for LockTime {
759    fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
760        let l = u32::arbitrary(u)?;
761        Ok(Self::from_consensus(l))
762    }
763}
764
765#[cfg(feature = "arbitrary")]
766impl<'a> Arbitrary<'a> for Height {
767    fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
768        let choice = u.int_in_range(0..=2)?;
769        match choice {
770            0 => Ok(Self::MIN),
771            1 => Ok(Self::MAX),
772            _ => {
773                let min = Self::MIN.to_u32();
774                let max = Self::MAX.to_u32();
775                let h = u.int_in_range(min..=max)?;
776                Ok(Self::from_u32(h).unwrap())
777            }
778        }
779    }
780}
781
782#[cfg(feature = "arbitrary")]
783impl<'a> Arbitrary<'a> for MedianTimePast {
784    fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
785        let choice = u.int_in_range(0..=2)?;
786        match choice {
787            0 => Ok(Self::MIN),
788            1 => Ok(Self::MAX),
789            _ => {
790                let min = Self::MIN.to_u32();
791                let max = Self::MAX.to_u32();
792                let t = u.int_in_range(min..=max)?;
793                Ok(Self::from_u32(t).unwrap())
794            }
795        }
796    }
797}
798
799#[cfg(test)]
800mod tests {
801    #[cfg(feature = "alloc")]
802    use alloc::{boxed::Box, format, string::String};
803
804    use super::*;
805
806    #[test]
807    #[cfg(feature = "alloc")]
808    fn display_and_alternate() {
809        let lock_by_height = LockTime::from_height(741_521).unwrap();
810        let lock_by_time = LockTime::from_mtp(1_653_195_600).unwrap(); // May 22nd 2022, 5am UTC.
811
812        assert_eq!(format!("{}", lock_by_height), "741521");
813        assert_eq!(format!("{:#}", lock_by_height), "block-height 741521");
814        assert!(!format!("{:?}", lock_by_height).is_empty());
815
816        assert_eq!(format!("{}", lock_by_time), "1653195600");
817        assert_eq!(format!("{:#}", lock_by_time), "block-time 1653195600 (seconds since epoch)");
818        assert!(!format!("{:?}", lock_by_time).is_empty());
819    }
820
821    #[test]
822    fn roundtrips() {
823        let lock_by_height = LockTime::from_consensus(741_521);
824        let lock_by_time = LockTime::from_consensus(1_653_195_600);
825
826        assert_eq!(lock_by_height.to_consensus_u32(), 741_521);
827        assert_eq!(lock_by_time.to_consensus_u32(), 1_653_195_600);
828    }
829
830    #[test]
831    fn lock_time_from_hex_lower() {
832        let lock_by_time = LockTime::from_hex("0x6289c350").unwrap();
833        assert_eq!(lock_by_time, LockTime::from_consensus(0x6289_C350));
834    }
835
836    #[test]
837    fn lock_time_from_hex_upper() {
838        let lock_by_time = LockTime::from_hex("0X6289C350").unwrap();
839        assert_eq!(lock_by_time, LockTime::from_consensus(0x6289_C350));
840    }
841
842    #[test]
843    fn lock_time_from_unprefixed_hex_lower() {
844        let lock_by_time = LockTime::from_unprefixed_hex("6289c350").unwrap();
845        assert_eq!(lock_by_time, LockTime::from_consensus(0x6289_C350));
846    }
847
848    #[test]
849    fn lock_time_from_unprefixed_hex_upper() {
850        let lock_by_time = LockTime::from_unprefixed_hex("6289C350").unwrap();
851        assert_eq!(lock_by_time, LockTime::from_consensus(0x6289_C350));
852    }
853
854    #[test]
855    fn invalid_hex() {
856        assert!(LockTime::from_hex("0xzb93").is_err());
857        assert!(LockTime::from_unprefixed_hex("zb93").is_err());
858    }
859
860    #[test]
861    fn invalid_locktime_type() {
862        assert!(LockTime::from_height(499_999_999).is_ok()); // Below the threshold.
863        assert!(LockTime::from_height(500_000_000).is_err()); // The threshold.
864        assert!(LockTime::from_height(500_000_001).is_err()); // Above the threshold.
865
866        assert!(LockTime::from_mtp(499_999_999).is_err()); // Below the threshold.
867        assert!(LockTime::from_mtp(500_000_000).is_ok()); // The threshold.
868        assert!(LockTime::from_mtp(500_000_001).is_ok()); // Above the threshold.
869    }
870
871    #[test]
872    fn parses_correctly_to_height_or_time() {
873        let lock_by_height = LockTime::from_consensus(750_000);
874
875        assert!(lock_by_height.is_block_height());
876        assert!(!lock_by_height.is_block_time());
877
878        let t: u32 = 1_653_195_600; // May 22nd, 5am UTC.
879        let lock_by_time = LockTime::from_consensus(t);
880
881        assert!(!lock_by_time.is_block_height());
882        assert!(lock_by_time.is_block_time());
883
884        // Test is_same_unit() logic
885        assert!(lock_by_height.is_same_unit(LockTime::from_consensus(800_000)));
886        assert!(!lock_by_height.is_same_unit(lock_by_time));
887        assert!(lock_by_time.is_same_unit(LockTime::from_consensus(1_653_282_000)));
888        assert!(!lock_by_time.is_same_unit(lock_by_height));
889    }
890
891    #[test]
892    fn satisfied_by_height() {
893        let height_below = Height::from_u32(700_000).unwrap();
894        let height = Height::from_u32(750_000).unwrap();
895        let height_above = Height::from_u32(800_000).unwrap();
896
897        let lock_by_height = LockTime::from(height);
898
899        let t: u32 = 1_653_195_600; // May 22nd, 5am UTC.
900        let time = MedianTimePast::from_u32(t).unwrap();
901
902        assert!(!lock_by_height.is_satisfied_by(height_below, time));
903        assert!(lock_by_height.is_satisfied_by(height, time));
904        assert!(lock_by_height.is_satisfied_by(height_above, time));
905    }
906
907    #[test]
908    fn satisfied_by_time() {
909        let time_before = MedianTimePast::from_u32(1_653_109_200).unwrap(); // "May 21th 2022, 5am UTC.
910        let time = MedianTimePast::from_u32(1_653_195_600).unwrap(); // "May 22nd 2022, 5am UTC.
911        let time_after = MedianTimePast::from_u32(1_653_282_000).unwrap(); // "May 23rd 2022, 5am UTC.
912
913        let lock_by_time = LockTime::from(time);
914
915        let height = Height::from_u32(800_000).unwrap();
916
917        assert!(!lock_by_time.is_satisfied_by(height, time_before));
918        assert!(lock_by_time.is_satisfied_by(height, time));
919        assert!(lock_by_time.is_satisfied_by(height, time_after));
920    }
921
922    #[test]
923    fn height_correctly_implies() {
924        let lock_by_height = LockTime::from_consensus(750_005);
925
926        assert!(!lock_by_height.is_implied_by(LockTime::from_consensus(750_004)));
927        assert!(lock_by_height.is_implied_by(LockTime::from_consensus(750_005)));
928        assert!(lock_by_height.is_implied_by(LockTime::from_consensus(750_006)));
929    }
930
931    #[test]
932    fn time_correctly_implies() {
933        let t: u32 = 1_700_000_005;
934        let lock_by_time = LockTime::from_consensus(t);
935
936        assert!(!lock_by_time.is_implied_by(LockTime::from_consensus(1_700_000_004)));
937        assert!(lock_by_time.is_implied_by(LockTime::from_consensus(1_700_000_005)));
938        assert!(lock_by_time.is_implied_by(LockTime::from_consensus(1_700_000_006)));
939    }
940
941    #[test]
942    fn incorrect_units_do_not_imply() {
943        let lock_by_height = LockTime::from_consensus(750_005);
944        assert!(!lock_by_height.is_implied_by(LockTime::from_consensus(1_700_000_004)));
945    }
946
947    #[test]
948    fn time_from_str_hex_happy_path() {
949        let actual = MedianTimePast::from_hex("0x6289C350").unwrap();
950        let expected = MedianTimePast::from_u32(0x6289_C350).unwrap();
951        assert_eq!(actual, expected);
952    }
953
954    #[test]
955    fn time_from_str_hex_no_prefix_happy_path() {
956        let time = MedianTimePast::from_unprefixed_hex("6289C350").unwrap();
957        assert_eq!(time, MedianTimePast(0x6289_C350));
958    }
959
960    #[test]
961    fn time_from_str_hex_invalid_hex_should_err() {
962        let hex = "0xzb93";
963        let result = MedianTimePast::from_hex(hex);
964        assert!(result.is_err());
965    }
966
967    #[test]
968    fn height_from_str_hex_happy_path() {
969        let actual = Height::from_hex("0xBA70D").unwrap();
970        let expected = Height(0xBA70D);
971        assert_eq!(actual, expected);
972    }
973
974    #[test]
975    fn height_from_str_hex_no_prefix_happy_path() {
976        let height = Height::from_unprefixed_hex("BA70D").unwrap();
977        assert_eq!(height, Height(0xBA70D));
978    }
979
980    #[test]
981    fn height_from_str_hex_invalid_hex_should_err() {
982        let hex = "0xzb93";
983        let result = Height::from_hex(hex);
984        assert!(result.is_err());
985    }
986
987    #[test]
988    fn height_try_from_stringlike_happy_path() {
989        let want = Height::from_u32(10).unwrap();
990        assert_eq!("10".parse::<Height>().unwrap(), want);
991        assert_eq!(Height::try_from("10").unwrap(), want);
992        #[cfg(feature = "alloc")]
993        {
994            assert_eq!(Height::try_from(String::from("10")).unwrap(), want);
995            assert_eq!(Height::try_from(Box::<str>::from("10")).unwrap(), want);
996        }
997    }
998
999    #[test]
1000    fn height_try_from_stringlike_hex_error_path() {
1001        // Only base-10 values should parse
1002        assert!("0xab".parse::<Height>().is_err());
1003        assert!(Height::try_from("0xab").is_err());
1004        #[cfg(feature = "alloc")]
1005        {
1006            assert!(Height::try_from(String::from("0xab")).is_err());
1007            assert!(Height::try_from(Box::<str>::from("0xab")).is_err());
1008        }
1009    }
1010
1011    #[test]
1012    fn height_try_from_stringlike_decimal_error_path() {
1013        // Only integers should parse
1014        assert!("10.123".parse::<Height>().is_err());
1015        assert!(Height::try_from("10.123").is_err());
1016        #[cfg(feature = "alloc")]
1017        {
1018            assert!(Height::try_from(String::from("10.123")).is_err());
1019            assert!(Height::try_from(Box::<str>::from("10.123")).is_err());
1020        }
1021    }
1022
1023    #[test]
1024    fn is_block_height_or_time() {
1025        assert!(is_block_height(499_999_999));
1026        assert!(!is_block_height(500_000_000));
1027
1028        assert!(!is_block_time(499_999_999));
1029        assert!(is_block_time(500_000_000));
1030    }
1031
1032    #[test]
1033    fn valid_chain_computes_mtp() {
1034        use crate::BlockTime;
1035
1036        let mut timestamps = [
1037            BlockTime::from_u32(500_000_010),
1038            BlockTime::from_u32(500_000_003),
1039            BlockTime::from_u32(500_000_005),
1040            BlockTime::from_u32(500_000_008),
1041            BlockTime::from_u32(500_000_001),
1042            BlockTime::from_u32(500_000_004),
1043            BlockTime::from_u32(500_000_006),
1044            BlockTime::from_u32(500_000_009),
1045            BlockTime::from_u32(500_000_002),
1046            BlockTime::from_u32(500_000_007),
1047            BlockTime::from_u32(500_000_000),
1048        ];
1049
1050        // Try various reorderings
1051        assert_eq!(MedianTimePast::new(timestamps).unwrap().to_u32(), 500_000_005);
1052        timestamps.reverse();
1053        assert_eq!(MedianTimePast::new(timestamps).unwrap().to_u32(), 500_000_005);
1054        timestamps.sort();
1055        assert_eq!(MedianTimePast::new(timestamps).unwrap().to_u32(), 500_000_005);
1056        timestamps.reverse();
1057        assert_eq!(MedianTimePast::new(timestamps).unwrap().to_u32(), 500_000_005);
1058    }
1059
1060    #[test]
1061    fn height_is_satisfied_by() {
1062        let chain_tip = Height::from_u32(100).unwrap();
1063
1064        // lock is satisfied if transaction can go in the next block (height <= chain_tip + 1).
1065        let locktime = Height::from_u32(100).unwrap();
1066        assert!(locktime.is_satisfied_by(chain_tip));
1067        let locktime = Height::from_u32(101).unwrap();
1068        assert!(locktime.is_satisfied_by(chain_tip));
1069
1070        // It is not satisfied if the lock height is after the next block.
1071        let locktime = Height::from_u32(102).unwrap();
1072        assert!(!locktime.is_satisfied_by(chain_tip));
1073    }
1074
1075    #[test]
1076    fn median_time_past_is_satisfied_by() {
1077        let mtp = MedianTimePast::from_u32(500_000_001).unwrap();
1078
1079        // lock is satisfied if transaction can go in the next block (locktime <= mtp).
1080        let locktime = MedianTimePast::from_u32(500_000_000).unwrap();
1081        assert!(locktime.is_satisfied_by(mtp));
1082        let locktime = MedianTimePast::from_u32(500_000_001).unwrap();
1083        assert!(locktime.is_satisfied_by(mtp));
1084
1085        // It is not satisfied if the lock time is after the median time past.
1086        let locktime = MedianTimePast::from_u32(500_000_002).unwrap();
1087        assert!(!locktime.is_satisfied_by(mtp));
1088    }
1089}