From f27e675e1e3d5a72189174d66631e303ab7e94e1 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Mon, 18 Mar 2024 12:55:33 +0000 Subject: [PATCH] relative locktime: add "obvious" constructors Adds constructors to allow directly creating locktimes from time or block counts; adds a flooring constructor to Time to match the ceiling one; adds an explicit constructor to Height since the From was not very discoverable. --- bitcoin/src/blockdata/locktime/relative.rs | 42 ++++++++++++++++++++++ units/src/locktime/relative.rs | 21 ++++++++++- 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/bitcoin/src/blockdata/locktime/relative.rs b/bitcoin/src/blockdata/locktime/relative.rs index dbad4d31..70d4b27b 100644 --- a/bitcoin/src/blockdata/locktime/relative.rs +++ b/bitcoin/src/blockdata/locktime/relative.rs @@ -43,6 +43,48 @@ pub enum LockTime { } impl LockTime { + /// A relative locktime of 0 is always valid, and is assumed valid for inputs that + /// are not yet confirmed. + 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 `n`, expecting `n` to be a 16-bit count of blocks. + #[inline] + pub const fn from_height(n: u16) -> Self { LockTime::Blocks(Height::from_height(n)) } + + /// Constructs a `LockTime` from `n`, expecting `n` to be a count of 512-second intervals. + /// + /// This function is a little awkward to use, and users may wish to instead use + /// [`Self::from_seconds_floor`] or [`Self::from_seconds_ceil`]. + #[inline] + pub const fn from_512_second_intervals(intervals: u16) -> Self { + LockTime::Time(Time::from_512_second_intervals(intervals)) + } + + /// Create a [`LockTime`] from seconds, converting the seconds into 512 second interval + /// with truncating division. + /// + /// # Errors + /// + /// Will return an error if the input cannot be encoded in 16 bits. + #[inline] + pub fn from_seconds_floor(seconds: u32) -> Result { + Time::from_seconds_floor(seconds).map(LockTime::Time) + } + + /// Create a [`LockTime`] from seconds, converting the seconds into 512 second interval + /// with ceiling division. + /// + /// # Errors + /// + /// Will return an error if the input cannot be encoded in 16 bits. + #[inline] + pub fn from_seconds_ceil(seconds: u32) -> Result { + Time::from_seconds_ceil(seconds).map(LockTime::Time) + } + /// Returns true if this [`relative::LockTime`] is satisfied by either height or time. /// /// # Examples diff --git a/units/src/locktime/relative.rs b/units/src/locktime/relative.rs index a125414c..d6b22bcf 100644 --- a/units/src/locktime/relative.rs +++ b/units/src/locktime/relative.rs @@ -22,6 +22,10 @@ impl Height { /// The maximum relative block height. pub const MAX: Self = Height(u16::max_value()); + /// Create a [`Height`] using a count of blocks. + #[inline] + pub const fn from_height(blocks: u16) -> Self { Height(blocks) } + /// Returns the inner `u16` value. #[inline] pub fn value(self) -> u16 { self.0 } @@ -59,7 +63,22 @@ impl Time { /// /// Encoding finer granularity of time for relative lock-times is not supported in Bitcoin. #[inline] - pub fn from_512_second_intervals(intervals: u16) -> Self { Time(intervals) } + pub const fn from_512_second_intervals(intervals: u16) -> Self { Time(intervals) } + + /// Create a [`Time`] from seconds, converting the seconds into 512 second interval with + /// truncating division. + /// + /// # Errors + /// + /// Will return an error if the input cannot be encoded in 16 bits. + #[inline] + pub fn from_seconds_floor(seconds: u32) -> Result { + if let Ok(interval) = u16::try_from(seconds / 512) { + Ok(Time::from_512_second_intervals(interval)) + } else { + Err(TimeOverflowError { seconds }) + } + } /// Create a [`Time`] from seconds, converting the seconds into 512 second interval with ceiling /// division.