miniscript/primitives/
absolute_locktime.rs

1// SPDX-License-Identifier: CC0-1.0
2
3//! Absolute Locktimes
4
5use core::{cmp, fmt};
6
7use bitcoin::absolute;
8
9/// Maximum allowed absolute locktime value.
10pub const MAX_ABSOLUTE_LOCKTIME: u32 = 0x8000_0000;
11
12/// Minimum allowed absolute locktime value.
13///
14/// In Bitcoin 0 is an allowed value, but in Miniscript it is not, because we
15/// (ab)use the locktime value as a boolean in our Script fragments, and avoiding
16/// this would reduce efficiency.
17pub const MIN_ABSOLUTE_LOCKTIME: u32 = 1;
18
19/// Error parsing an absolute locktime.
20#[derive(Debug, PartialEq)]
21pub struct AbsLockTimeError {
22    value: u32,
23}
24
25impl fmt::Display for AbsLockTimeError {
26    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
27        if self.value < MIN_ABSOLUTE_LOCKTIME {
28            f.write_str("absolute locktimes in Miniscript have a minimum value of 1")
29        } else {
30            debug_assert!(self.value > MAX_ABSOLUTE_LOCKTIME);
31            write!(
32                f,
33                "absolute locktimes in Miniscript have a maximum value of 0x{:08x}; got 0x{:08x}",
34                MAX_ABSOLUTE_LOCKTIME, self.value
35            )
36        }
37    }
38}
39
40#[cfg(feature = "std")]
41impl std::error::Error for AbsLockTimeError {
42    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
43}
44
45/// An absolute locktime that implements `Ord`.
46#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
47pub struct AbsLockTime(absolute::LockTime);
48
49impl AbsLockTime {
50    /// Constructs an `AbsLockTime` from an nLockTime value or the argument to `CHEKCLOCKTIMEVERIFY`.
51    pub fn from_consensus(n: u32) -> Result<Self, AbsLockTimeError> {
52        if n >= MIN_ABSOLUTE_LOCKTIME && n <= MAX_ABSOLUTE_LOCKTIME {
53            Ok(AbsLockTime(absolute::LockTime::from_consensus(n)))
54        } else {
55            Err(AbsLockTimeError { value: n })
56        }
57    }
58
59    /// Returns the inner `u32` value. This is the value used when creating this `LockTime`
60    /// i.e., `n OP_CHECKLOCKTIMEVERIFY` or nLockTime.
61    ///
62    /// This calls through to `absolute::LockTime::to_consensus_u32()` and the same usage warnings
63    /// apply.
64    pub fn to_consensus_u32(self) -> u32 { self.0.to_consensus_u32() }
65
66    /// Whether this is a height-based locktime.
67    pub fn is_block_height(&self) -> bool { self.0.is_block_height() }
68
69    /// Whether this is a time-based locktime.
70    pub fn is_block_time(&self) -> bool { self.0.is_block_time() }
71}
72
73impl From<AbsLockTime> for absolute::LockTime {
74    fn from(lock_time: AbsLockTime) -> absolute::LockTime { lock_time.0 }
75}
76
77impl cmp::PartialOrd for AbsLockTime {
78    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> { Some(self.cmp(other)) }
79}
80
81impl cmp::Ord for AbsLockTime {
82    fn cmp(&self, other: &Self) -> cmp::Ordering {
83        let this = self.0.to_consensus_u32();
84        let that = other.0.to_consensus_u32();
85        this.cmp(&that)
86    }
87}
88
89impl fmt::Display for AbsLockTime {
90    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
91}