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