// SPDX-License-Identifier: CC0-1.0 //! Provides type [`LockTime`] that implements the logic around nLockTime/OP_CHECKLOCKTIMEVERIFY. //! //! There are two types of lock time: lock-by-blockheight and lock-by-blocktime, distinguished by //! whether `LockTime < LOCKTIME_THRESHOLD`. //! use core::cmp::{Ordering, PartialOrd}; use core::{fmt, mem}; use internals::write_err; use io::{BufRead, Write}; #[cfg(all(test, mutate))] use mutagen::mutate; #[cfg(doc)] use crate::absolute; use crate::consensus::encode::{self, Decodable, Encodable}; use crate::error::ParseIntError; use crate::parse::{impl_parse_str_from_int_fallible, impl_parse_str_from_int_infallible}; use crate::prelude::*; use crate::string::FromHexStr; /// The Threshold for deciding whether a lock time value is a height or a time (see [Bitcoin Core]). /// /// `LockTime` values _below_ the threshold are interpreted as block heights, values _above_ (or /// equal to) the threshold are interpreted as block times (UNIX timestamp, seconds since epoch). /// /// Bitcoin is able to safely use this value because a block height greater than 500,000,000 would /// never occur because it would represent a height in approximately 9500 years. Conversely, block /// times under 500,000,000 will never happen because they would represent times before 1986 which /// are, for obvious reasons, not useful within the Bitcoin network. /// /// [Bitcoin Core]: https://github.com/bitcoin/bitcoin/blob/9ccaee1d5e2e4b79b0a7c29aadb41b97e4741332/src/script/script.h#L39 pub const LOCK_TIME_THRESHOLD: u32 = 500_000_000; /// An absolute lock time value, representing either a block height or a UNIX timestamp (seconds /// since epoch). /// /// Used for transaction lock time (`nLockTime` in Bitcoin Core and [`crate::Transaction::lock_time`] /// in this library) and also for the argument to opcode 'OP_CHECKLOCKTIMEVERIFY`. /// /// ### Note on ordering /// /// Because locktimes may be height- or time-based, and these metrics are incommensurate, there /// is no total ordering on locktimes. We therefore have implemented [`PartialOrd`] but not [`Ord`]. /// For [`crate::Transaction`], which has a locktime field, we implement a total ordering to make /// it easy to store transactions in sorted data structures, and use the locktime's 32-bit integer /// consensus encoding to order it. /// /// ### Relevant BIPs /// /// * [BIP-65 OP_CHECKLOCKTIMEVERIFY](https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki) /// * [BIP-113 Median time-past as endpoint for lock-time calculations](https://github.com/bitcoin/bips/blob/master/bip-0113.mediawiki) /// /// # Examples /// ``` /// # use bitcoin::absolute::{LockTime, LockTime::*}; /// # let n = LockTime::from_consensus(741521); // n OP_CHECKLOCKTIMEVERIFY /// # let lock_time = LockTime::from_consensus(741521); // nLockTime /// // To compare absolute lock times there are various `is_satisfied_*` methods, you may also use: /// let is_satisfied = match (n, lock_time) { /// (Blocks(n), Blocks(lock_time)) => n <= lock_time, /// (Seconds(n), Seconds(lock_time)) => n <= lock_time, /// _ => panic!("handle invalid comparison error"), /// }; /// ``` #[derive(Clone, Copy, PartialEq, Eq, Hash)] pub enum LockTime { /// A block height lock time value. /// /// # Examples /// ```rust /// use bitcoin::absolute::LockTime; /// /// let block: u32 = 741521; /// let n = LockTime::from_height(block).expect("valid height"); /// assert!(n.is_block_height()); /// assert_eq!(n.to_consensus_u32(), block); /// ``` Blocks(Height), /// A UNIX timestamp lock time value. /// /// # Examples /// ```rust /// use bitcoin::absolute::LockTime; /// /// let seconds: u32 = 1653195600; // May 22nd, 5am UTC. /// let n = LockTime::from_time(seconds).expect("valid time"); /// assert!(n.is_block_time()); /// assert_eq!(n.to_consensus_u32(), seconds); /// ``` Seconds(Time), } impl LockTime { /// If [`crate::Transaction::lock_time`] is set to zero it is ignored, in other words a /// transaction with nLocktime==0 is able to be included immediately in any block. pub const ZERO: LockTime = LockTime::Blocks(Height::ZERO); /// The number of bytes that the locktime contributes to the size of a transaction. pub const SIZE: usize = 4; // Serialized length of a u32. /// Constructs a `LockTime` from an nLockTime value or the argument to OP_CHEKCLOCKTIMEVERIFY. /// /// # Examples /// /// ```rust /// # use bitcoin::absolute::LockTime; /// # let n = LockTime::from_consensus(741521); // n OP_CHECKLOCKTIMEVERIFY /// /// // `from_consensus` roundtrips as expected with `to_consensus_u32`. /// let n_lock_time: u32 = 741521; /// let lock_time = LockTime::from_consensus(n_lock_time); /// assert_eq!(lock_time.to_consensus_u32(), n_lock_time); #[inline] pub fn from_consensus(n: u32) -> Self { if is_block_height(n) { Self::Blocks(Height::from_consensus(n).expect("n is valid")) } else { Self::Seconds(Time::from_consensus(n).expect("n is valid")) } } /// Constructs a `LockTime` from `n`, expecting `n` to be a valid block height. /// /// See [`LOCK_TIME_THRESHOLD`] for definition of a valid height value. /// /// # Examples /// ```rust /// # use bitcoin::absolute::LockTime; /// assert!(LockTime::from_height(741521).is_ok()); /// assert!(LockTime::from_height(1653195600).is_err()); /// ``` #[inline] pub fn from_height(n: u32) -> Result { let height = Height::from_consensus(n)?; Ok(LockTime::Blocks(height)) } /// Constructs a `LockTime` from `n`, expecting `n` to be a valid block time. /// /// See [`LOCK_TIME_THRESHOLD`] for definition of a valid time value. /// /// # Examples /// ```rust /// # use bitcoin::absolute::LockTime; /// assert!(LockTime::from_time(1653195600).is_ok()); /// assert!(LockTime::from_time(741521).is_err()); /// ``` #[inline] pub fn from_time(n: u32) -> Result { let time = Time::from_consensus(n)?; Ok(LockTime::Seconds(time)) } /// Returns true if both lock times use the same unit i.e., both height based or both time based. #[inline] pub fn is_same_unit(&self, other: LockTime) -> bool { mem::discriminant(self) == mem::discriminant(&other) } /// Returns true if this lock time value is a block height. #[inline] pub fn is_block_height(&self) -> bool { match *self { LockTime::Blocks(_) => true, LockTime::Seconds(_) => false, } } /// Returns true if this lock time value is a block time (UNIX timestamp). #[inline] pub fn is_block_time(&self) -> bool { !self.is_block_height() } /// Returns true if this timelock constraint is satisfied by the respective `height`/`time`. /// /// If `self` is a blockheight based lock then it is checked against `height` and if `self` is a /// blocktime based lock it is checked against `time`. /// /// A 'timelock constraint' refers to the `n` from `n OP_CHEKCLOCKTIMEVERIFY`, this constraint /// is satisfied if a transaction with nLockTime ([`crate::Transaction::lock_time`]) set to /// `height`/`time` is valid. /// /// # Examples /// ```no_run /// # use bitcoin::absolute::{LockTime, Height, Time}; /// // Can be implemented if block chain data is available. /// fn get_height() -> Height { todo!("return the current block height") } /// fn get_time() -> Time { todo!("return the current block time") } /// /// let n = LockTime::from_consensus(741521); // `n OP_CHEKCLOCKTIMEVERIFY`. /// if n.is_satisfied_by(get_height(), get_time()) { /// // Can create and mine a transaction that satisfies the OP_CLTV timelock constraint. /// } /// ```` #[inline] #[cfg_attr(all(test, mutate), mutate)] pub fn is_satisfied_by(&self, height: Height, time: Time) -> bool { use LockTime::*; match *self { Blocks(n) => n <= height, Seconds(n) => n <= time, } } /// Returns true if satisfaction of `other` lock time implies satisfaction of this /// [`absolute::LockTime`]. /// /// A lock time can only be satisfied by n blocks being mined or n seconds passing. If you have /// two lock times (same unit) then the larger lock time being satisfied implies (in a /// mathematical sense) the smaller one being satisfied. /// /// This function is useful if you wish to check a lock time against various other locks e.g., /// filtering out locks which cannot be satisfied. Can also be used to remove the smaller value /// of two `OP_CHECKLOCKTIMEVERIFY` operations within one branch of the script. /// /// # Examples /// /// ```rust /// # use bitcoin::absolute::{LockTime, LockTime::*}; /// let lock_time = LockTime::from_consensus(741521); /// let check = LockTime::from_consensus(741521 + 1); /// assert!(lock_time.is_implied_by(check)); /// ``` #[inline] #[cfg_attr(all(test, mutate), mutate)] pub fn is_implied_by(&self, other: LockTime) -> bool { use LockTime::*; match (*self, other) { (Blocks(this), Blocks(other)) => this <= other, (Seconds(this), Seconds(other)) => this <= other, _ => false, // Not the same units. } } /// Returns the inner `u32` value. This is the value used when creating this `LockTime` /// i.e., `n OP_CHECKLOCKTIMEVERIFY` or nLockTime. /// /// # Warning /// /// Do not compare values return by this method. The whole point of the `LockTime` type is to /// assist in doing correct comparisons. Either use `is_satisfied_by`, `is_satisfied_by_lock`, /// or use the pattern below: /// /// # Examples /// /// ```rust /// # use bitcoin::absolute::{LockTime, LockTime::*}; /// # let n = LockTime::from_consensus(741521); // n OP_CHECKLOCKTIMEVERIFY /// # let lock_time = LockTime::from_consensus(741521 + 1); // nLockTime /// /// let is_satisfied = match (n, lock_time) { /// (Blocks(n), Blocks(lock_time)) => n <= lock_time, /// (Seconds(n), Seconds(lock_time)) => n <= lock_time, /// _ => panic!("invalid comparison"), /// }; /// /// // Or, if you have Rust 1.53 or greater /// // let is_satisfied = n.partial_cmp(&lock_time).expect("invalid comparison").is_le(); /// ``` #[inline] pub fn to_consensus_u32(self) -> u32 { match self { LockTime::Blocks(ref h) => h.to_consensus_u32(), LockTime::Seconds(ref t) => t.to_consensus_u32(), } } } impl_parse_str_from_int_infallible!(LockTime, u32, from_consensus); impl From for LockTime { #[inline] fn from(h: Height) -> Self { LockTime::Blocks(h) } } impl From