dca4266205 units: Fix rustdoc column width (Tobin C. Harding)
d557caf552 Run the formatter (Tobin C. Harding)
7c2115b68f Rename MtpInterval to NumberOf512Seconds (Tobin C. Harding)
3a97ea2259 Rename HeightInterval to NumberOfBlocks (Tobin C. Harding)
c3b7457f6c Rename Mtp to MedianTimePast (Tobin C. Harding)
b38d2256fd Run the formatter (Tobin C. Harding)

Pull request description:

  Naming things is hard, naming lock time things is _really_ hard. This is another attempt at improving the very low level types in the `units::locktime` modules.

  Formatting done separately so that the diffs are easier to tab through.

ACKs for top commit:
  apoelstra:
    ACK dca4266205361eb0aee802a46164b163b797d0ee; successfully ran local tests

Tree-SHA512: 24d1b0cae3d7f926622177f00aedc50c53164e04f9d400f9c2c009157f36fd1f55ac2d1b70ceb10b0a165130ffe7eef25d64dc6ea5e6f3caec812c39ab0bbd66
This commit is contained in:
merge-script 2025-05-09 12:12:37 +00:00
commit 3a6a399f48
No known key found for this signature in database
GPG Key ID: C588D63CE41B97C1
12 changed files with 255 additions and 246 deletions

View File

@ -30,9 +30,7 @@ use crate::transaction::{Transaction, TransactionExt as _, Wtxid};
#[doc(inline)] #[doc(inline)]
pub use primitives::block::{Block, Checked, Unchecked, Validation, Version, BlockHash, Header, WitnessCommitment}; pub use primitives::block::{Block, Checked, Unchecked, Validation, Version, BlockHash, Header, WitnessCommitment};
#[doc(inline)] #[doc(inline)]
pub use units::block::{ pub use units::block::{BlockHeight, BlockHeightInterval, TooBigForRelativeHeightError};
BlockHeight, BlockHeightInterval, TooBigForRelativeBlockHeightIntervalError,
};
#[deprecated(since = "TBD", note = "use `BlockHeightInterval` instead")] #[deprecated(since = "TBD", note = "use `BlockHeightInterval` instead")]
#[doc(hidden)] #[doc(hidden)]

View File

@ -41,11 +41,11 @@ pub mod locktime {
/// Re-export everything from the `primitives::locktime::absolute` module. /// Re-export everything from the `primitives::locktime::absolute` module.
#[rustfmt::skip] // Keep public re-exports separate. #[rustfmt::skip] // Keep public re-exports separate.
pub use primitives::locktime::absolute::{ConversionError, Height, LockTime, ParseHeightError, ParseTimeError, Mtp}; pub use primitives::locktime::absolute::{ConversionError, Height, LockTime, ParseHeightError, ParseTimeError, MedianTimePast};
#[deprecated(since = "TBD", note = "use `Mtp` instead")] #[deprecated(since = "TBD", note = "use `MedianTimePast` instead")]
#[doc(hidden)] #[doc(hidden)]
pub type Time = Mtp; pub type Time = MedianTimePast;
impl Encodable for LockTime { impl Encodable for LockTime {
#[inline] #[inline]
@ -71,17 +71,17 @@ pub mod locktime {
/// Re-export everything from the `primitives::locktime::relative` module. /// Re-export everything from the `primitives::locktime::relative` module.
pub use primitives::locktime::relative::{ pub use primitives::locktime::relative::{
DisabledLockTimeError, HeightInterval, IncompatibleHeightError, IncompatibleTimeError, DisabledLockTimeError, IncompatibleHeightError, IncompatibleTimeError, LockTime,
LockTime, MtpInterval, TimeOverflowError, NumberOf512Seconds, NumberOfBlocks, TimeOverflowError,
}; };
#[deprecated(since = "TBD", note = "use `Mtp` instead")] #[deprecated(since = "TBD", note = "use `NumberOfBlocks` instead")]
#[doc(hidden)] #[doc(hidden)]
pub type Height = HeightInterval; pub type Height = NumberOfBlocks;
#[deprecated(since = "TBD", note = "use `Mtp` instead")] #[deprecated(since = "TBD", note = "use `NumberOf512Seconds` instead")]
#[doc(hidden)] #[doc(hidden)]
pub type Time = MtpInterval; pub type Time = NumberOf512Seconds;
} }
} }

View File

@ -20,7 +20,7 @@ use primitives::Sequence;
use super::Weight; use super::Weight;
use crate::consensus::{self, encode, Decodable, Encodable}; use crate::consensus::{self, encode, Decodable, Encodable};
use crate::internal_macros::{impl_consensus_encoding, impl_hashencode}; use crate::internal_macros::{impl_consensus_encoding, impl_hashencode};
use crate::locktime::absolute::{self, Height, Mtp}; use crate::locktime::absolute::{self, Height, MedianTimePast};
use crate::prelude::{Borrow, Vec}; use crate::prelude::{Borrow, Vec};
use crate::script::{Script, ScriptBuf, ScriptExt as _, ScriptExtPriv as _}; use crate::script::{Script, ScriptBuf, ScriptExt as _, ScriptExtPriv as _};
#[cfg(doc)] #[cfg(doc)]
@ -295,7 +295,7 @@ pub trait TransactionExt: sealed::Sealed {
/// By definition if the lock time is not enabled the transaction's absolute timelock is /// By definition if the lock time is not enabled the transaction's absolute timelock is
/// considered to be satisfied i.e., there are no timelock constraints restricting this /// considered to be satisfied i.e., there are no timelock constraints restricting this
/// transaction from being mined immediately. /// transaction from being mined immediately.
fn is_absolute_timelock_satisfied(&self, height: Height, time: Mtp) -> bool; fn is_absolute_timelock_satisfied(&self, height: Height, time: MedianTimePast) -> bool;
/// Returns `true` if this transactions nLockTime is enabled ([BIP-65]). /// Returns `true` if this transactions nLockTime is enabled ([BIP-65]).
/// ///
@ -393,7 +393,7 @@ impl TransactionExt for Transaction {
fn is_explicitly_rbf(&self) -> bool { self.input.iter().any(|input| input.sequence.is_rbf()) } fn is_explicitly_rbf(&self) -> bool { self.input.iter().any(|input| input.sequence.is_rbf()) }
fn is_absolute_timelock_satisfied(&self, height: Height, time: Mtp) -> bool { fn is_absolute_timelock_satisfied(&self, height: Height, time: MedianTimePast) -> bool {
if !self.is_lock_time_enabled() { if !self.is_lock_time_enabled() {
return true; return true;
} }

View File

@ -16,11 +16,11 @@ use crate::{absolute, Transaction};
#[rustfmt::skip] // Keep public re-exports separate. #[rustfmt::skip] // Keep public re-exports separate.
#[doc(inline)] #[doc(inline)]
pub use units::locktime::absolute::{ConversionError, Height, ParseHeightError, ParseTimeError, Mtp, LOCK_TIME_THRESHOLD}; pub use units::locktime::absolute::{ConversionError, Height, ParseHeightError, ParseTimeError, MedianTimePast, LOCK_TIME_THRESHOLD};
#[deprecated(since = "TBD", note = "use `Mtp` instead")] #[deprecated(since = "TBD", note = "use `MedianTimePast` instead")]
#[doc(hidden)] #[doc(hidden)]
pub type Time = Mtp; pub type Time = MedianTimePast;
/// An absolute lock time value, representing either a block height or a UNIX timestamp (seconds /// An absolute lock time value, representing either a block height or a UNIX timestamp (seconds
/// since epoch). /// since epoch).
@ -83,7 +83,7 @@ pub enum LockTime {
/// assert!(n.is_block_time()); /// assert!(n.is_block_time());
/// assert_eq!(n.to_consensus_u32(), seconds); /// assert_eq!(n.to_consensus_u32(), seconds);
/// ``` /// ```
Seconds(Mtp), Seconds(MedianTimePast),
} }
impl LockTime { impl LockTime {
@ -147,7 +147,7 @@ impl LockTime {
if units::locktime::absolute::is_block_height(n) { if units::locktime::absolute::is_block_height(n) {
Self::Blocks(Height::from_u32(n).expect("n is valid")) Self::Blocks(Height::from_u32(n).expect("n is valid"))
} else { } else {
Self::Seconds(Mtp::from_u32(n).expect("n is valid")) Self::Seconds(MedianTimePast::from_u32(n).expect("n is valid"))
} }
} }
@ -202,7 +202,7 @@ impl LockTime {
/// ``` /// ```
#[inline] #[inline]
pub fn from_mtp(n: u32) -> Result<Self, ConversionError> { pub fn from_mtp(n: u32) -> Result<Self, ConversionError> {
let time = Mtp::from_u32(n)?; let time = MedianTimePast::from_u32(n)?;
Ok(LockTime::Seconds(time)) Ok(LockTime::Seconds(time))
} }
@ -239,7 +239,7 @@ impl LockTime {
/// # use bitcoin_primitives::absolute; /// # use bitcoin_primitives::absolute;
/// // Can be implemented if block chain data is available. /// // Can be implemented if block chain data is available.
/// fn get_height() -> absolute::Height { todo!("return the current block height") } /// fn get_height() -> absolute::Height { todo!("return the current block height") }
/// fn get_time() -> absolute::Mtp { todo!("return the current block time") } /// fn get_time() -> absolute::MedianTimePast { todo!("return the current block time") }
/// ///
/// let n = absolute::LockTime::from_consensus(741521); // `n OP_CHEKCLOCKTIMEVERIFY`. /// let n = absolute::LockTime::from_consensus(741521); // `n OP_CHEKCLOCKTIMEVERIFY`.
/// if n.is_satisfied_by(get_height(), get_time()) { /// if n.is_satisfied_by(get_height(), get_time()) {
@ -247,7 +247,7 @@ impl LockTime {
/// } /// }
/// ```` /// ````
#[inline] #[inline]
pub fn is_satisfied_by(self, height: Height, time: Mtp) -> bool { pub fn is_satisfied_by(self, height: Height, time: MedianTimePast) -> bool {
use LockTime as L; use LockTime as L;
match self { match self {
@ -333,9 +333,9 @@ impl From<Height> for LockTime {
fn from(h: Height) -> Self { LockTime::Blocks(h) } fn from(h: Height) -> Self { LockTime::Blocks(h) }
} }
impl From<Mtp> for LockTime { impl From<MedianTimePast> for LockTime {
#[inline] #[inline]
fn from(t: Mtp) -> Self { LockTime::Seconds(t) } fn from(t: MedianTimePast) -> Self { LockTime::Seconds(t) }
} }
impl fmt::Debug for LockTime { impl fmt::Debug for LockTime {
@ -512,7 +512,7 @@ mod tests {
let lock_by_height = LockTime::from(height); let lock_by_height = LockTime::from(height);
let t: u32 = 1_653_195_600; // May 22nd, 5am UTC. let t: u32 = 1_653_195_600; // May 22nd, 5am UTC.
let time = Mtp::from_u32(t).unwrap(); let time = MedianTimePast::from_u32(t).unwrap();
assert!(!lock_by_height.is_satisfied_by(height_below, time)); assert!(!lock_by_height.is_satisfied_by(height_below, time));
assert!(lock_by_height.is_satisfied_by(height, time)); assert!(lock_by_height.is_satisfied_by(height, time));
@ -521,9 +521,9 @@ mod tests {
#[test] #[test]
fn satisfied_by_time() { fn satisfied_by_time() {
let time_before = Mtp::from_u32(1_653_109_200).unwrap(); // "May 21th 2022, 5am UTC. let time_before = MedianTimePast::from_u32(1_653_109_200).unwrap(); // "May 21th 2022, 5am UTC.
let time = Mtp::from_u32(1_653_195_600).unwrap(); // "May 22nd 2022, 5am UTC. let time = MedianTimePast::from_u32(1_653_195_600).unwrap(); // "May 22nd 2022, 5am UTC.
let time_after = Mtp::from_u32(1_653_282_000).unwrap(); // "May 23rd 2022, 5am UTC. let time_after = MedianTimePast::from_u32(1_653_282_000).unwrap(); // "May 23rd 2022, 5am UTC.
let lock_by_time = LockTime::from(time); let lock_by_time = LockTime::from(time);

View File

@ -13,16 +13,16 @@ use crate::{relative, TxIn};
#[rustfmt::skip] // Keep public re-exports separate. #[rustfmt::skip] // Keep public re-exports separate.
#[doc(inline)] #[doc(inline)]
pub use units::locktime::relative::{HeightInterval, MtpInterval, TimeOverflowError}; pub use units::locktime::relative::{NumberOfBlocks, NumberOf512Seconds, TimeOverflowError};
use units::{BlockHeight, BlockMtp}; use units::{BlockHeight, BlockMtp};
#[deprecated(since = "TBD", note = "use `Mtp` instead")] #[deprecated(since = "TBD", note = "use `NumberOfBlocks` instead")]
#[doc(hidden)] #[doc(hidden)]
pub type Height = HeightInterval; pub type Height = NumberOfBlocks;
#[deprecated(since = "TBD", note = "use `Mtp` instead")] #[deprecated(since = "TBD", note = "use `NumberOf512Seconds` instead")]
#[doc(hidden)] #[doc(hidden)]
pub type Time = MtpInterval; pub type Time = NumberOf512Seconds;
/// A relative lock time value, representing either a block height or time (512 second intervals). /// A relative lock time value, representing either a block height or time (512 second intervals).
/// ///
@ -68,7 +68,7 @@ pub type Time = MtpInterval;
/// let utxo_height = BlockHeight::from(80); /// let utxo_height = BlockHeight::from(80);
/// let utxo_mtp = BlockMtp::new(utxo_timestamps); /// let utxo_mtp = BlockMtp::new(utxo_timestamps);
/// ///
/// let locktime = relative::LockTime::Time(relative::MtpInterval::from_512_second_intervals(10)); /// let locktime = relative::LockTime::Time(relative::NumberOf512Seconds::from_512_second_intervals(10));
/// ///
/// // Check if locktime is satisfied /// // Check if locktime is satisfied
/// assert!(locktime.is_satisfied_by(current_height, current_mtp, utxo_height, utxo_mtp)); /// assert!(locktime.is_satisfied_by(current_height, current_mtp, utxo_height, utxo_mtp));
@ -77,15 +77,15 @@ pub type Time = MtpInterval;
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum LockTime { pub enum LockTime {
/// A block height lock time value. /// A block height lock time value.
Blocks(HeightInterval), Blocks(NumberOfBlocks),
/// A 512 second time interval value. /// A 512 second time interval value.
Time(MtpInterval), Time(NumberOf512Seconds),
} }
impl LockTime { impl LockTime {
/// A relative locktime of 0 is always valid, and is assumed valid for inputs that /// A relative locktime of 0 is always valid, and is assumed valid for inputs that
/// are not yet confirmed. /// are not yet confirmed.
pub const ZERO: LockTime = LockTime::Blocks(HeightInterval::ZERO); pub const ZERO: LockTime = LockTime::Blocks(NumberOfBlocks::ZERO);
/// The number of bytes that the locktime contributes to the size of a transaction. /// The number of bytes that the locktime contributes to the size of a transaction.
pub const SIZE: usize = 4; // Serialized length of a u32. pub const SIZE: usize = 4; // Serialized length of a u32.
@ -164,7 +164,7 @@ impl LockTime {
/// Constructs a new `LockTime` from `n`, expecting `n` to be a 16-bit count of blocks. /// Constructs a new `LockTime` from `n`, expecting `n` to be a 16-bit count of blocks.
#[inline] #[inline]
pub const fn from_height(n: u16) -> Self { LockTime::Blocks(HeightInterval::from_height(n)) } pub const fn from_height(n: u16) -> Self { LockTime::Blocks(NumberOfBlocks::from_height(n)) }
/// Constructs a new `LockTime` from `n`, expecting `n` to be a count of 512-second intervals. /// Constructs a new `LockTime` from `n`, expecting `n` to be a count of 512-second intervals.
/// ///
@ -172,7 +172,7 @@ impl LockTime {
/// [`Self::from_seconds_floor`] or [`Self::from_seconds_ceil`]. /// [`Self::from_seconds_floor`] or [`Self::from_seconds_ceil`].
#[inline] #[inline]
pub const fn from_512_second_intervals(intervals: u16) -> Self { pub const fn from_512_second_intervals(intervals: u16) -> Self {
LockTime::Time(MtpInterval::from_512_second_intervals(intervals)) LockTime::Time(NumberOf512Seconds::from_512_second_intervals(intervals))
} }
/// Construct a new [`LockTime`] from seconds, converting the seconds into 512 second interval /// Construct a new [`LockTime`] from seconds, converting the seconds into 512 second interval
@ -183,7 +183,7 @@ impl LockTime {
/// Will return an error if the input cannot be encoded in 16 bits. /// Will return an error if the input cannot be encoded in 16 bits.
#[inline] #[inline]
pub const fn from_seconds_floor(seconds: u32) -> Result<Self, TimeOverflowError> { pub const fn from_seconds_floor(seconds: u32) -> Result<Self, TimeOverflowError> {
match MtpInterval::from_seconds_floor(seconds) { match NumberOf512Seconds::from_seconds_floor(seconds) {
Ok(time) => Ok(LockTime::Time(time)), Ok(time) => Ok(LockTime::Time(time)),
Err(e) => Err(e), Err(e) => Err(e),
} }
@ -197,7 +197,7 @@ impl LockTime {
/// Will return an error if the input cannot be encoded in 16 bits. /// Will return an error if the input cannot be encoded in 16 bits.
#[inline] #[inline]
pub const fn from_seconds_ceil(seconds: u32) -> Result<Self, TimeOverflowError> { pub const fn from_seconds_ceil(seconds: u32) -> Result<Self, TimeOverflowError> {
match MtpInterval::from_seconds_ceil(seconds) { match NumberOf512Seconds::from_seconds_ceil(seconds) {
Ok(time) => Ok(LockTime::Time(time)), Ok(time) => Ok(LockTime::Time(time)),
Err(e) => Err(e), Err(e) => Err(e),
} }
@ -332,7 +332,7 @@ impl LockTime {
} }
} }
/// Returns true if this [`relative::LockTime`] is satisfied by [`HeightInterval`]. /// Returns true if this [`relative::LockTime`] is satisfied by [`NumberOfBlocks`].
/// ///
/// # Errors /// # Errors
/// ///
@ -346,12 +346,12 @@ impl LockTime {
/// ///
/// let required_height: u16 = 100; /// let required_height: u16 = 100;
/// let lock = Sequence::from_height(required_height).to_relative_lock_time().expect("valid height"); /// let lock = Sequence::from_height(required_height).to_relative_lock_time().expect("valid height");
/// assert!(lock.is_satisfied_by_height(relative::HeightInterval::from(required_height + 1)).expect("a height")); /// assert!(lock.is_satisfied_by_height(relative::NumberOfBlocks::from(required_height + 1)).expect("a height"));
/// ``` /// ```
#[inline] #[inline]
pub fn is_satisfied_by_height( pub fn is_satisfied_by_height(
self, self,
height: HeightInterval, height: NumberOfBlocks,
) -> Result<bool, IncompatibleHeightError> { ) -> Result<bool, IncompatibleHeightError> {
use LockTime as L; use LockTime as L;
@ -378,7 +378,10 @@ impl LockTime {
/// assert!(lock.is_satisfied_by_time(relative::Time::from_512_second_intervals(intervals + 10)).expect("a time")); /// assert!(lock.is_satisfied_by_time(relative::Time::from_512_second_intervals(intervals + 10)).expect("a time"));
/// ``` /// ```
#[inline] #[inline]
pub fn is_satisfied_by_time(self, time: MtpInterval) -> Result<bool, IncompatibleTimeError> { pub fn is_satisfied_by_time(
self,
time: NumberOf512Seconds,
) -> Result<bool, IncompatibleTimeError> {
use LockTime as L; use LockTime as L;
match self { match self {
@ -388,14 +391,14 @@ impl LockTime {
} }
} }
impl From<HeightInterval> for LockTime { impl From<NumberOfBlocks> for LockTime {
#[inline] #[inline]
fn from(h: HeightInterval) -> Self { LockTime::Blocks(h) } fn from(h: NumberOfBlocks) -> Self { LockTime::Blocks(h) }
} }
impl From<MtpInterval> for LockTime { impl From<NumberOf512Seconds> for LockTime {
#[inline] #[inline]
fn from(t: MtpInterval) -> Self { LockTime::Time(t) } fn from(t: NumberOf512Seconds) -> Self { LockTime::Time(t) }
} }
impl fmt::Display for LockTime { impl fmt::Display for LockTime {
@ -455,17 +458,17 @@ impl std::error::Error for DisabledLockTimeError {}
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct IncompatibleHeightError { pub struct IncompatibleHeightError {
/// Attempted to satisfy a lock-by-blocktime lock with this height. /// Attempted to satisfy a lock-by-blocktime lock with this height.
height: HeightInterval, height: NumberOfBlocks,
/// The inner time value of the lock-by-blocktime lock. /// The inner time value of the lock-by-blocktime lock.
time: MtpInterval, time: NumberOf512Seconds,
} }
impl IncompatibleHeightError { impl IncompatibleHeightError {
/// Returns the height that was erroneously used to try and satisfy a lock-by-blocktime lock. /// Returns the height that was erroneously used to try and satisfy a lock-by-blocktime lock.
pub fn incompatible(&self) -> HeightInterval { self.height } pub fn incompatible(&self) -> NumberOfBlocks { self.height }
/// Returns the time value of the lock-by-blocktime lock. /// Returns the time value of the lock-by-blocktime lock.
pub fn expected(&self) -> MtpInterval { self.time } pub fn expected(&self) -> NumberOf512Seconds { self.time }
} }
impl fmt::Display for IncompatibleHeightError { impl fmt::Display for IncompatibleHeightError {
@ -486,17 +489,17 @@ impl std::error::Error for IncompatibleHeightError {}
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct IncompatibleTimeError { pub struct IncompatibleTimeError {
/// Attempted to satisfy a lock-by-blockheight lock with this time. /// Attempted to satisfy a lock-by-blockheight lock with this time.
time: MtpInterval, time: NumberOf512Seconds,
/// The inner height value of the lock-by-blockheight lock. /// The inner height value of the lock-by-blockheight lock.
height: HeightInterval, height: NumberOfBlocks,
} }
impl IncompatibleTimeError { impl IncompatibleTimeError {
/// Returns the time that was erroneously used to try and satisfy a lock-by-blockheight lock. /// Returns the time that was erroneously used to try and satisfy a lock-by-blockheight lock.
pub fn incompatible(&self) -> MtpInterval { self.time } pub fn incompatible(&self) -> NumberOf512Seconds { self.time }
/// Returns the height value of the lock-by-blockheight lock. /// Returns the height value of the lock-by-blockheight lock.
pub fn expected(&self) -> HeightInterval { self.height } pub fn expected(&self) -> NumberOfBlocks { self.height }
} }
impl fmt::Display for IncompatibleTimeError { impl fmt::Display for IncompatibleTimeError {
@ -551,10 +554,10 @@ mod tests {
#[test] #[test]
fn parses_correctly_to_height_or_time() { fn parses_correctly_to_height_or_time() {
let height1 = HeightInterval::from(10); let height1 = NumberOfBlocks::from(10);
let height2 = HeightInterval::from(11); let height2 = NumberOfBlocks::from(11);
let time1 = MtpInterval::from_512_second_intervals(70); let time1 = NumberOf512Seconds::from_512_second_intervals(70);
let time2 = MtpInterval::from_512_second_intervals(71); let time2 = NumberOf512Seconds::from_512_second_intervals(71);
let lock_by_height1 = LockTime::from(height1); let lock_by_height1 = LockTime::from(height1);
let lock_by_height2 = LockTime::from(height2); let lock_by_height2 = LockTime::from(height2);
@ -576,34 +579,31 @@ mod tests {
#[test] #[test]
fn height_correctly_implies() { fn height_correctly_implies() {
let height = HeightInterval::from(10); let height = NumberOfBlocks::from(10);
let lock_by_height = LockTime::from(height); let lock_by_height = LockTime::from(height);
assert!(!lock_by_height.is_implied_by(LockTime::from(HeightInterval::from(9)))); assert!(!lock_by_height.is_implied_by(LockTime::from(NumberOfBlocks::from(9))));
assert!(lock_by_height.is_implied_by(LockTime::from(HeightInterval::from(10)))); assert!(lock_by_height.is_implied_by(LockTime::from(NumberOfBlocks::from(10))));
assert!(lock_by_height.is_implied_by(LockTime::from(HeightInterval::from(11)))); assert!(lock_by_height.is_implied_by(LockTime::from(NumberOfBlocks::from(11))));
} }
#[test] #[test]
fn time_correctly_implies() { fn time_correctly_implies() {
let time = MtpInterval::from_512_second_intervals(70); let time = NumberOf512Seconds::from_512_second_intervals(70);
let lock_by_time = LockTime::from(time); let lock_by_time = LockTime::from(time);
assert!( assert!(!lock_by_time
!lock_by_time.is_implied_by(LockTime::from(MtpInterval::from_512_second_intervals(69))) .is_implied_by(LockTime::from(NumberOf512Seconds::from_512_second_intervals(69))));
); assert!(lock_by_time
assert!( .is_implied_by(LockTime::from(NumberOf512Seconds::from_512_second_intervals(70))));
lock_by_time.is_implied_by(LockTime::from(MtpInterval::from_512_second_intervals(70))) assert!(lock_by_time
); .is_implied_by(LockTime::from(NumberOf512Seconds::from_512_second_intervals(71))));
assert!(
lock_by_time.is_implied_by(LockTime::from(MtpInterval::from_512_second_intervals(71)))
);
} }
#[test] #[test]
fn sequence_correctly_implies() { fn sequence_correctly_implies() {
let height = HeightInterval::from(10); let height = NumberOfBlocks::from(10);
let time = MtpInterval::from_512_second_intervals(70); let time = NumberOf512Seconds::from_512_second_intervals(70);
let lock_by_height = LockTime::from(height); let lock_by_height = LockTime::from(height);
let lock_by_time = LockTime::from(time); let lock_by_time = LockTime::from(time);
@ -624,8 +624,8 @@ mod tests {
#[test] #[test]
fn incorrect_units_do_not_imply() { fn incorrect_units_do_not_imply() {
let time = MtpInterval::from_512_second_intervals(70); let time = NumberOf512Seconds::from_512_second_intervals(70);
let height = HeightInterval::from(10); let height = NumberOfBlocks::from(10);
let lock_by_time = LockTime::from(time); let lock_by_time = LockTime::from(time);
assert!(!lock_by_time.is_implied_by(LockTime::from(height))); assert!(!lock_by_time.is_implied_by(LockTime::from(height)));
@ -664,8 +664,8 @@ mod tests {
#[test] #[test]
fn incompatible_height_error() { fn incompatible_height_error() {
let height = HeightInterval::from(10); let height = NumberOfBlocks::from(10);
let time = MtpInterval::from_512_second_intervals(70); let time = NumberOf512Seconds::from_512_second_intervals(70);
let lock_by_time = LockTime::from(time); let lock_by_time = LockTime::from(time);
let err = lock_by_time.is_satisfied_by_height(height).unwrap_err(); let err = lock_by_time.is_satisfied_by_height(height).unwrap_err();
@ -676,8 +676,8 @@ mod tests {
#[test] #[test]
fn incompatible_time_error() { fn incompatible_time_error() {
let height = HeightInterval::from(10); let height = NumberOfBlocks::from(10);
let time = MtpInterval::from_512_second_intervals(70); let time = NumberOf512Seconds::from_512_second_intervals(70);
let lock_by_height = LockTime::from(height); let lock_by_height = LockTime::from(height);
let err = lock_by_height.is_satisfied_by_time(time).unwrap_err(); let err = lock_by_height.is_satisfied_by_time(time).unwrap_err();
@ -704,16 +704,16 @@ mod tests {
let utxo_height = BlockHeight::from_u32(80); let utxo_height = BlockHeight::from_u32(80);
let utxo_mtp = BlockMtp::new(utxo_timestamps); let utxo_mtp = BlockMtp::new(utxo_timestamps);
let lock1 = LockTime::Blocks(HeightInterval::from(10)); let lock1 = LockTime::Blocks(NumberOfBlocks::from(10));
assert!(lock1.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp)); assert!(lock1.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp));
let lock2 = LockTime::Blocks(HeightInterval::from(21)); let lock2 = LockTime::Blocks(NumberOfBlocks::from(21));
assert!(!lock2.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp)); assert!(!lock2.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp));
let lock3 = LockTime::Time(MtpInterval::from_512_second_intervals(10)); let lock3 = LockTime::Time(NumberOf512Seconds::from_512_second_intervals(10));
assert!(lock3.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp)); assert!(lock3.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp));
let lock4 = LockTime::Time(MtpInterval::from_512_second_intervals(20000)); let lock4 = LockTime::Time(NumberOf512Seconds::from_512_second_intervals(20000));
assert!(!lock4.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp)); assert!(!lock4.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp));
assert!(LockTime::ZERO.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp)); assert!(LockTime::ZERO.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp));
@ -727,10 +727,10 @@ mod tests {
let lock6 = LockTime::from_seconds_floor(5000).unwrap(); let lock6 = LockTime::from_seconds_floor(5000).unwrap();
assert!(lock6.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp)); assert!(lock6.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp));
let max_height_lock = LockTime::Blocks(HeightInterval::MAX); let max_height_lock = LockTime::Blocks(NumberOfBlocks::MAX);
assert!(!max_height_lock.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp)); assert!(!max_height_lock.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp));
let max_time_lock = LockTime::Time(MtpInterval::MAX); let max_time_lock = LockTime::Time(NumberOf512Seconds::MAX);
assert!(!max_time_lock.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp)); assert!(!max_time_lock.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp));
let max_chain_height = BlockHeight::from_u32(u32::MAX); let max_chain_height = BlockHeight::from_u32(u32::MAX);

View File

@ -187,7 +187,7 @@ impl Sequence {
/// Constructs a new [`relative::LockTime`] from this [`Sequence`] number. /// Constructs a new [`relative::LockTime`] from this [`Sequence`] number.
#[inline] #[inline]
pub fn to_relative_lock_time(self) -> Option<relative::LockTime> { pub fn to_relative_lock_time(self) -> Option<relative::LockTime> {
use crate::locktime::relative::{HeightInterval, LockTime, MtpInterval}; use crate::locktime::relative::{LockTime, NumberOf512Seconds, NumberOfBlocks};
if !self.is_relative_lock_time() { if !self.is_relative_lock_time() {
return None; return None;
@ -196,9 +196,9 @@ impl Sequence {
let lock_value = self.low_u16(); let lock_value = self.low_u16();
if self.is_time_locked() { if self.is_time_locked() {
Some(LockTime::from(MtpInterval::from_512_second_intervals(lock_value))) Some(LockTime::from(NumberOf512Seconds::from_512_second_intervals(lock_value)))
} else { } else {
Some(LockTime::from(HeightInterval::from(lock_value))) Some(LockTime::from(NumberOfBlocks::from(lock_value)))
} }
} }
@ -261,15 +261,15 @@ impl<'a> Arbitrary<'a> for Sequence {
1 => Ok(Sequence::ZERO), 1 => Ok(Sequence::ZERO),
2 => Ok(Sequence::MIN_NO_RBF), 2 => Ok(Sequence::MIN_NO_RBF),
3 => Ok(Sequence::ENABLE_LOCKTIME_AND_RBF), 3 => Ok(Sequence::ENABLE_LOCKTIME_AND_RBF),
4 => Ok(Sequence::from_consensus(u32::from(relative::HeightInterval::MIN.to_height()))), 4 => Ok(Sequence::from_consensus(u32::from(relative::NumberOfBlocks::MIN.to_height()))),
5 => Ok(Sequence::from_consensus(u32::from(relative::HeightInterval::MAX.to_height()))), 5 => Ok(Sequence::from_consensus(u32::from(relative::NumberOfBlocks::MAX.to_height()))),
6 => Ok(Sequence::from_consensus( 6 => Ok(Sequence::from_consensus(
Sequence::LOCK_TYPE_MASK Sequence::LOCK_TYPE_MASK
| u32::from(relative::MtpInterval::MIN.to_512_second_intervals()), | u32::from(relative::NumberOf512Seconds::MIN.to_512_second_intervals()),
)), )),
7 => Ok(Sequence::from_consensus( 7 => Ok(Sequence::from_consensus(
Sequence::LOCK_TYPE_MASK Sequence::LOCK_TYPE_MASK
| u32::from(relative::MtpInterval::MAX.to_512_second_intervals()), | u32::from(relative::NumberOf512Seconds::MAX.to_512_second_intervals()),
)), )),
_ => Ok(Sequence(u.arbitrary()?)), _ => Ok(Sequence(u.arbitrary()?)),
} }

View File

@ -142,18 +142,18 @@ impl BlockHeightInterval {
pub fn checked_add(self, other: Self) -> Option<Self> { self.0.checked_add(other.0).map(Self) } pub fn checked_add(self, other: Self) -> Option<Self> { self.0.checked_add(other.0).map(Self) }
} }
impl From<relative::HeightInterval> for BlockHeightInterval { impl From<relative::NumberOfBlocks> for BlockHeightInterval {
/// Converts a [`locktime::relative::HeightInterval`] to a [`BlockHeightInterval`]. /// Converts a [`locktime::relative::NumberOfBlocks`] to a [`BlockHeightInterval`].
/// ///
/// A relative locktime block height has a maximum value of `u16::MAX` where as a /// A relative locktime block height has a maximum value of `u16::MAX` where as a
/// [`BlockHeightInterval`] is a thin wrapper around a `u32`, the two types are not interchangeable. /// [`BlockHeightInterval`] is a thin wrapper around a `u32`, the two types are not interchangeable.
fn from(h: relative::HeightInterval) -> Self { Self::from_u32(h.to_height().into()) } fn from(h: relative::NumberOfBlocks) -> Self { Self::from_u32(h.to_height().into()) }
} }
impl TryFrom<BlockHeightInterval> for relative::HeightInterval { impl TryFrom<BlockHeightInterval> for relative::NumberOfBlocks {
type Error = TooBigForRelativeBlockHeightIntervalError; type Error = TooBigForRelativeHeightError;
/// Converts a [`BlockHeightInterval`] to a [`locktime::relative::HeightInterval`]. /// Converts a [`BlockHeightInterval`] to a [`locktime::relative::NumberOfBlocks`].
/// ///
/// A relative locktime block height has a maximum value of `u16::MAX` where as a /// A relative locktime block height has a maximum value of `u16::MAX` where as a
/// [`BlockHeightInterval`] is a thin wrapper around a `u32`, the two types are not interchangeable. /// [`BlockHeightInterval`] is a thin wrapper around a `u32`, the two types are not interchangeable.
@ -161,9 +161,9 @@ impl TryFrom<BlockHeightInterval> for relative::HeightInterval {
let h = h.to_u32(); let h = h.to_u32();
if h > u32::from(u16::MAX) { if h > u32::from(u16::MAX) {
return Err(TooBigForRelativeBlockHeightIntervalError(h)); return Err(TooBigForRelativeHeightError(h));
} }
Ok(relative::HeightInterval::from(h as u16)) // Cast ok, value checked above. Ok(relative::NumberOfBlocks::from(h as u16)) // Cast ok, value checked above.
} }
} }
@ -171,7 +171,7 @@ impl_u32_wrapper! {
/// The median timestamp of 11 consecutive blocks. /// The median timestamp of 11 consecutive blocks.
/// ///
/// This type is not meant for constructing time-based timelocks. It is a general purpose /// This type is not meant for constructing time-based timelocks. It is a general purpose
/// MTP abstraction. For locktimes please see [`locktime::absolute::Mtp`]. /// MTP abstraction. For locktimes please see [`locktime::absolute::MedianTimePast`].
/// ///
/// This is a thin wrapper around a `u32` that may take on all values of a `u32`. /// This is a thin wrapper around a `u32` that may take on all values of a `u32`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
@ -202,29 +202,31 @@ impl BlockMtp {
} }
} }
impl From<absolute::Mtp> for BlockMtp { impl From<absolute::MedianTimePast> for BlockMtp {
/// Converts a [`locktime::absolute::Mtp`] to a [`BlockMtp`]. /// Converts a [`locktime::absolute::MedianTimePast`] to a [`BlockMtp`].
/// ///
/// An absolute locktime MTP has a minimum value of [`absolute::LOCK_TIME_THRESHOLD`], /// An absolute locktime MTP has a minimum value of [`absolute::LOCK_TIME_THRESHOLD`],
/// while [`BlockMtp`] may take the full range of `u32`. /// while [`BlockMtp`] may take the full range of `u32`.
fn from(h: absolute::Mtp) -> Self { Self::from_u32(h.to_u32()) } fn from(h: absolute::MedianTimePast) -> Self { Self::from_u32(h.to_u32()) }
} }
impl TryFrom<BlockMtp> for absolute::Mtp { impl TryFrom<BlockMtp> for absolute::MedianTimePast {
type Error = absolute::ConversionError; type Error = absolute::ConversionError;
/// Converts a [`BlockHeight`] to a [`locktime::absolute::Height`]. /// Converts a [`BlockHeight`] to a [`locktime::absolute::Height`].
/// ///
/// An absolute locktime MTP has a minimum value of [`absolute::LOCK_TIME_THRESHOLD`], /// An absolute locktime MTP has a minimum value of [`absolute::LOCK_TIME_THRESHOLD`],
/// while [`BlockMtp`] may take the full range of `u32`. /// while [`BlockMtp`] may take the full range of `u32`.
fn try_from(h: BlockMtp) -> Result<Self, Self::Error> { absolute::Mtp::from_u32(h.to_u32()) } fn try_from(h: BlockMtp) -> Result<Self, Self::Error> {
absolute::MedianTimePast::from_u32(h.to_u32())
}
} }
impl_u32_wrapper! { impl_u32_wrapper! {
/// An unsigned difference between two [`BlockMtp`]s. /// An unsigned difference between two [`BlockMtp`]s.
/// ///
/// This type is not meant for constructing time-based timelocks. It is a general purpose /// This type is not meant for constructing time-based timelocks. It is a general purpose
/// MTP abstraction. For locktimes please see [`locktime::relative::MtpInterval`]. /// MTP abstraction. For locktimes please see [`locktime::relative::NumberOf512Seconds`].
/// ///
/// This is a thin wrapper around a `u32` that may take on all values of a `u32`. /// This is a thin wrapper around a `u32` that may take on all values of a `u32`.
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
@ -234,7 +236,7 @@ impl_u32_wrapper! {
} }
impl BlockMtpInterval { impl BlockMtpInterval {
/// Converts a [`BlockMtpInterval`] to a [`locktime::relative::MtpInterval`], rounding down. /// Converts a [`BlockMtpInterval`] to a [`locktime::relative::NumberOf512Seconds`], rounding down.
/// ///
/// Relative timelock MTP intervals have a resolution of 512 seconds, while /// Relative timelock MTP intervals have a resolution of 512 seconds, while
/// [`BlockMtpInterval`], like all block timestamp types, has a one-second resolution. /// [`BlockMtpInterval`], like all block timestamp types, has a one-second resolution.
@ -246,11 +248,11 @@ impl BlockMtpInterval {
#[inline] #[inline]
pub const fn to_relative_mtp_interval_floor( pub const fn to_relative_mtp_interval_floor(
self, self,
) -> Result<relative::MtpInterval, relative::TimeOverflowError> { ) -> Result<relative::NumberOf512Seconds, relative::TimeOverflowError> {
relative::MtpInterval::from_seconds_floor(self.to_u32()) relative::NumberOf512Seconds::from_seconds_floor(self.to_u32())
} }
/// Converts a [`BlockMtpInterval`] to a [`locktime::relative::MtpInterval`], rounding up. /// Converts a [`BlockMtpInterval`] to a [`locktime::relative::NumberOf512Seconds`], rounding up.
/// ///
/// Relative timelock MTP intervals have a resolution of 512 seconds, while /// Relative timelock MTP intervals have a resolution of 512 seconds, while
/// [`BlockMtpInterval`], like all block timestamp types, has a one-second resolution. /// [`BlockMtpInterval`], like all block timestamp types, has a one-second resolution.
@ -262,8 +264,8 @@ impl BlockMtpInterval {
#[inline] #[inline]
pub const fn to_relative_mtp_interval_ceil( pub const fn to_relative_mtp_interval_ceil(
self, self,
) -> Result<relative::MtpInterval, relative::TimeOverflowError> { ) -> Result<relative::NumberOf512Seconds, relative::TimeOverflowError> {
relative::MtpInterval::from_seconds_ceil(self.to_u32()) relative::NumberOf512Seconds::from_seconds_ceil(self.to_u32())
} }
/// Attempt to subtract two [`BlockMtpInterval`]s, returning `None` in case of overflow. /// Attempt to subtract two [`BlockMtpInterval`]s, returning `None` in case of overflow.
@ -273,32 +275,32 @@ impl BlockMtpInterval {
pub fn checked_add(self, other: Self) -> Option<Self> { self.0.checked_add(other.0).map(Self) } pub fn checked_add(self, other: Self) -> Option<Self> { self.0.checked_add(other.0).map(Self) }
} }
impl From<relative::MtpInterval> for BlockMtpInterval { impl From<relative::NumberOf512Seconds> for BlockMtpInterval {
/// Converts a [`locktime::relative::MtpInterval`] to a [`BlockMtpInterval `]. /// Converts a [`locktime::relative::NumberOf512Seconds`] to a [`BlockMtpInterval `].
/// ///
/// A relative locktime MTP interval has a resolution of 512 seconds, and a maximum value /// A relative locktime MTP interval has a resolution of 512 seconds, and a maximum value
/// of `u16::MAX` 512-second intervals. [`BlockMtpInterval`] may take the full range of /// of `u16::MAX` 512-second intervals. [`BlockMtpInterval`] may take the full range of
/// `u32`. /// `u32`.
fn from(h: relative::MtpInterval) -> Self { Self::from_u32(h.to_seconds()) } fn from(h: relative::NumberOf512Seconds) -> Self { Self::from_u32(h.to_seconds()) }
} }
/// Error returned when the block interval is too big to be used as a relative lock time. /// Error returned when the block interval is too big to be used as a relative lock time.
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct TooBigForRelativeBlockHeightIntervalError(u32); pub struct TooBigForRelativeHeightError(u32);
impl fmt::Display for TooBigForRelativeBlockHeightIntervalError { impl fmt::Display for TooBigForRelativeHeightError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!( write!(
f, f,
"block interval is too big to be used as a relative lock time: {} (max: {})", "block interval is too big to be used as a relative lock time: {} (max: {})",
self.0, self.0,
relative::HeightInterval::MAX relative::NumberOfBlocks::MAX
) )
} }
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl std::error::Error for TooBigForRelativeBlockHeightIntervalError {} impl std::error::Error for TooBigForRelativeHeightError {}
crate::internal_macros::impl_op_for_references! { crate::internal_macros::impl_op_for_references! {
// height - height = interval // height - height = interval
@ -454,15 +456,15 @@ mod tests {
assert_eq!(interval, 100); assert_eq!(interval, 100);
let interval_from_height: BlockHeightInterval = let interval_from_height: BlockHeightInterval =
relative::HeightInterval::from(10u16).into(); relative::NumberOfBlocks::from(10u16).into();
assert_eq!(interval_from_height.to_u32(), 10u32); assert_eq!(interval_from_height.to_u32(), 10u32);
let invalid_height_greater = let invalid_height_greater =
relative::HeightInterval::try_from(BlockHeightInterval(u32::from(u16::MAX) + 1)); relative::NumberOfBlocks::try_from(BlockHeightInterval(u32::from(u16::MAX) + 1));
assert!(invalid_height_greater.is_err()); assert!(invalid_height_greater.is_err());
let valid_height = let valid_height =
relative::HeightInterval::try_from(BlockHeightInterval(u32::from(u16::MAX))); relative::NumberOfBlocks::try_from(BlockHeightInterval(u32::from(u16::MAX)));
assert!(valid_height.is_ok()); assert!(valid_height.is_ok());
} }

View File

@ -14,9 +14,8 @@
use core::ops; use core::ops;
use NumOpResult as R; use NumOpResult as R;
use crate::NumOpError as E;
use crate::{Amount, FeeRate, MathOp, NumOpResult, OptionExt, Weight}; use crate::{Amount, FeeRate, MathOp, NumOpError as E, NumOpResult, OptionExt, Weight};
impl Amount { impl Amount {
/// Checked weight ceiling division. /// Checked weight ceiling division.
@ -119,7 +118,9 @@ impl FeeRate {
/// [`NumOpResult::Error`] if an overflow occurred. /// [`NumOpResult::Error`] if an overflow occurred.
/// ///
/// This is equivalent to `Self::checked_mul_by_weight()`. /// This is equivalent to `Self::checked_mul_by_weight()`.
pub fn to_fee(self, weight: Weight) -> NumOpResult<Amount> { self.checked_mul_by_weight(weight) } pub fn to_fee(self, weight: Weight) -> NumOpResult<Amount> {
self.checked_mul_by_weight(weight)
}
/// Calculates the fee by multiplying this fee rate by weight, in weight units, returning [`None`] /// Calculates the fee by multiplying this fee rate by weight, in weight units, returning [`None`]
/// if an overflow occurred. /// if an overflow occurred.
@ -150,7 +151,7 @@ impl FeeRate {
/// ///
/// Returns [`NumOpResult::Error`] if overflow occurred. /// Returns [`NumOpResult::Error`] if overflow occurred.
pub const fn checked_mul_by_weight(self, weight: Weight) -> NumOpResult<Amount> { pub const fn checked_mul_by_weight(self, weight: Weight) -> NumOpResult<Amount> {
if let Some(fee) = self.to_sat_per_kwu().checked_mul(weight.to_wu()) { if let Some(fee) = self.to_sat_per_kwu().checked_mul(weight.to_wu()) {
if let Some(round_up) = fee.checked_add(999) { if let Some(round_up) = fee.checked_add(999) {
if let Ok(ret) = Amount::from_sat(round_up / 1_000) { if let Ok(ret) = Amount::from_sat(round_up / 1_000) {
return NumOpResult::Valid(ret); return NumOpResult::Valid(ret);

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: CC0-1.0 // SPDX-License-Identifier: CC0-1.0
//! Provides [`Height`] and [`Mtp`] types used by the `rust-bitcoin` `absolute::LockTime` type. //! Provides [`Height`] and [`MedianTimePast`] types used by the `rust-bitcoin` `absolute::LockTime` type.
use core::convert::Infallible; use core::convert::Infallible;
use core::fmt; use core::fmt;
@ -132,9 +132,9 @@ impl serde::Serialize for Height {
} }
} }
#[deprecated(since = "TBD", note = "use `Mtp` instead")] #[deprecated(since = "TBD", note = "use `MedianTimePast` instead")]
#[doc(hidden)] #[doc(hidden)]
pub type Time = Mtp; pub type Time = MedianTimePast;
/// The median timestamp of 11 consecutive blocks, representing "the timestamp" of the /// The median timestamp of 11 consecutive blocks, representing "the timestamp" of the
/// final block for locktime-checking purposes. /// final block for locktime-checking purposes.
@ -145,16 +145,16 @@ pub type Time = Mtp;
/// a quantity which is required by consensus to be monotone and which is difficult /// a quantity which is required by consensus to be monotone and which is difficult
/// for any individual miner to manipulate. /// for any individual miner to manipulate.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Mtp(u32); pub struct MedianTimePast(u32);
impl Mtp { impl MedianTimePast {
/// The minimum MTP allowable in a locktime (Tue Nov 05 1985 00:53:20 GMT+0000). /// The minimum MTP allowable in a locktime (Tue Nov 05 1985 00:53:20 GMT+0000).
pub const MIN: Self = Mtp(LOCK_TIME_THRESHOLD); pub const MIN: Self = MedianTimePast(LOCK_TIME_THRESHOLD);
/// The maximum MTP allowable in a locktime (Sun Feb 07 2106 06:28:15 GMT+0000). /// The maximum MTP allowable in a locktime (Sun Feb 07 2106 06:28:15 GMT+0000).
pub const MAX: Self = Mtp(u32::MAX); pub const MAX: Self = MedianTimePast(u32::MAX);
/// Constructs an [`Mtp`] by computing the mediantimepast from the last 11 block timestamps /// Constructs an [`MedianTimePast`] by computing the mediantimepast from the last 11 block timestamps
/// ///
/// Because block timestamps are not monotonic, this function internally sorts them; /// Because block timestamps are not monotonic, this function internally sorts them;
/// it is therefore not important what order they appear in the array; use whatever /// it is therefore not important what order they appear in the array; use whatever
@ -170,7 +170,7 @@ impl Mtp {
crate::BlockMtp::new(timestamps).try_into() crate::BlockMtp::new(timestamps).try_into()
} }
/// Constructs a new [`Mtp`] from a big-endian hex-encoded `u32`. /// Constructs a new [`MedianTimePast`] from a big-endian hex-encoded `u32`.
/// ///
/// The input string may or may not contain a typical hex prefix e.g., `0x`. /// The input string may or may not contain a typical hex prefix e.g., `0x`.
/// ///
@ -189,7 +189,7 @@ impl Mtp {
/// Constructs a new MTP directly from a `u32` value. /// Constructs a new MTP directly from a `u32` value.
/// ///
/// This function, with [`Mtp::to_u32`], is used to obtain a raw MTP value. It is /// This function, with [`MedianTimePast::to_u32`], is used to obtain a raw MTP value. It is
/// **not** used to convert to or from a block timestamp, which is not a MTP. /// **not** used to convert to or from a block timestamp, which is not a MTP.
/// ///
/// # Errors /// # Errors
@ -199,10 +199,10 @@ impl Mtp {
/// # Examples /// # Examples
/// ///
/// ```rust /// ```rust
/// use bitcoin_units::locktime::absolute::Mtp; /// use bitcoin_units::locktime::absolute::MedianTimePast;
/// ///
/// let t: u32 = 1653195600; // May 22nd, 5am UTC. /// let t: u32 = 1653195600; // May 22nd, 5am UTC.
/// let time = Mtp::from_u32(t).expect("invalid time value"); /// let time = MedianTimePast::from_u32(t).expect("invalid time value");
/// assert_eq!(time.to_consensus_u32(), t); /// assert_eq!(time.to_consensus_u32(), t);
/// ``` /// ```
#[inline] #[inline]
@ -214,30 +214,30 @@ impl Mtp {
} }
} }
/// Converts this [`Mtp`] to a raw `u32` value. /// Converts this [`MedianTimePast`] to a raw `u32` value.
#[inline] #[inline]
pub const fn to_u32(self) -> u32 { self.0 } pub const fn to_u32(self) -> u32 { self.0 }
} }
impl fmt::Display for Mtp { impl fmt::Display for MedianTimePast {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) } fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
} }
crate::impl_parse_str!(Mtp, ParseTimeError, parser(Mtp::from_u32)); crate::impl_parse_str!(MedianTimePast, ParseTimeError, parser(MedianTimePast::from_u32));
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for Mtp { impl<'de> serde::Deserialize<'de> for MedianTimePast {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where
D: serde::Deserializer<'de>, D: serde::Deserializer<'de>,
{ {
let u = u32::deserialize(deserializer)?; let u = u32::deserialize(deserializer)?;
Mtp::from_u32(u).map_err(serde::de::Error::custom) MedianTimePast::from_u32(u).map_err(serde::de::Error::custom)
} }
} }
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
impl serde::Serialize for Mtp { impl serde::Serialize for MedianTimePast {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where where
S: serde::Serializer, S: serde::Serializer,
@ -383,11 +383,11 @@ impl ParseError {
E::ParseInt(ParseIntError { input, bits: _, is_signed: _, source }) E::ParseInt(ParseIntError { input, bits: _, is_signed: _, source })
if *source.kind() == IntErrorKind::PosOverflow => if *source.kind() == IntErrorKind::PosOverflow =>
{ {
// Outputs "failed to parse <input_string> as absolute Height/Mtp (<subject> is above limit <upper_bound>)" // Outputs "failed to parse <input_string> as absolute Height/MedianTimePast (<subject> is above limit <upper_bound>)"
write!( write!(
f, f,
"{} ({} is above limit {})", "{} ({} is above limit {})",
input.display_cannot_parse("absolute Height/Mtp"), input.display_cannot_parse("absolute Height/MedianTimePast"),
subject, subject,
upper_bound upper_bound
) )
@ -395,17 +395,22 @@ impl ParseError {
E::ParseInt(ParseIntError { input, bits: _, is_signed: _, source }) E::ParseInt(ParseIntError { input, bits: _, is_signed: _, source })
if *source.kind() == IntErrorKind::NegOverflow => if *source.kind() == IntErrorKind::NegOverflow =>
{ {
// Outputs "failed to parse <input_string> as absolute Height/Mtp (<subject> is below limit <lower_bound>)" // Outputs "failed to parse <input_string> as absolute Height/MedianTimePast (<subject> is below limit <lower_bound>)"
write!( write!(
f, f,
"{} ({} is below limit {})", "{} ({} is below limit {})",
input.display_cannot_parse("absolute Height/Mtp"), input.display_cannot_parse("absolute Height/MedianTimePast"),
subject, subject,
lower_bound lower_bound
) )
} }
E::ParseInt(ParseIntError { input, bits: _, is_signed: _, source: _ }) => { E::ParseInt(ParseIntError { input, bits: _, is_signed: _, source: _ }) => {
write!(f, "{} ({})", input.display_cannot_parse("absolute Height/Mtp"), subject) write!(
f,
"{} ({})",
input.display_cannot_parse("absolute Height/MedianTimePast"),
subject
)
} }
E::Conversion(value) if *value < i64::from(lower_bound) => { E::Conversion(value) if *value < i64::from(lower_bound) => {
write!(f, "{} {} is below limit {}", subject, value, lower_bound) write!(f, "{} {} is below limit {}", subject, value, lower_bound)
@ -458,17 +463,17 @@ impl<'a> Arbitrary<'a> for Height {
} }
#[cfg(feature = "arbitrary")] #[cfg(feature = "arbitrary")]
impl<'a> Arbitrary<'a> for Mtp { impl<'a> Arbitrary<'a> for MedianTimePast {
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> { fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
let choice = u.int_in_range(0..=2)?; let choice = u.int_in_range(0..=2)?;
match choice { match choice {
0 => Ok(Mtp::MIN), 0 => Ok(MedianTimePast::MIN),
1 => Ok(Mtp::MAX), 1 => Ok(MedianTimePast::MAX),
_ => { _ => {
let min = Mtp::MIN.to_u32(); let min = MedianTimePast::MIN.to_u32();
let max = Mtp::MAX.to_u32(); let max = MedianTimePast::MAX.to_u32();
let t = u.int_in_range(min..=max)?; let t = u.int_in_range(min..=max)?;
Ok(Mtp::from_u32(t).unwrap()) Ok(MedianTimePast::from_u32(t).unwrap())
} }
} }
} }
@ -483,21 +488,21 @@ mod tests {
#[test] #[test]
fn time_from_str_hex_happy_path() { fn time_from_str_hex_happy_path() {
let actual = Mtp::from_hex("0x6289C350").unwrap(); let actual = MedianTimePast::from_hex("0x6289C350").unwrap();
let expected = Mtp::from_u32(0x6289_C350).unwrap(); let expected = MedianTimePast::from_u32(0x6289_C350).unwrap();
assert_eq!(actual, expected); assert_eq!(actual, expected);
} }
#[test] #[test]
fn time_from_str_hex_no_prefix_happy_path() { fn time_from_str_hex_no_prefix_happy_path() {
let time = Mtp::from_hex("6289C350").unwrap(); let time = MedianTimePast::from_hex("6289C350").unwrap();
assert_eq!(time, Mtp(0x6289_C350)); assert_eq!(time, MedianTimePast(0x6289_C350));
} }
#[test] #[test]
fn time_from_str_hex_invalid_hex_should_err() { fn time_from_str_hex_invalid_hex_should_err() {
let hex = "0xzb93"; let hex = "0xzb93";
let result = Mtp::from_hex(hex); let result = MedianTimePast::from_hex(hex);
assert!(result.is_err()); assert!(result.is_err());
} }
@ -541,8 +546,8 @@ mod tests {
#[test] #[test]
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
pub fn encode_decode_time() { pub fn encode_decode_time() {
serde_round_trip!(Mtp::MIN); serde_round_trip!(MedianTimePast::MIN);
serde_round_trip!(Mtp::MAX); serde_round_trip!(MedianTimePast::MAX);
} }
#[test] #[test]
@ -575,12 +580,12 @@ mod tests {
]; ];
// Try various reorderings // Try various reorderings
assert_eq!(Mtp::new(timestamps).unwrap().to_u32(), 500_000_005); assert_eq!(MedianTimePast::new(timestamps).unwrap().to_u32(), 500_000_005);
timestamps.reverse(); timestamps.reverse();
assert_eq!(Mtp::new(timestamps).unwrap().to_u32(), 500_000_005); assert_eq!(MedianTimePast::new(timestamps).unwrap().to_u32(), 500_000_005);
timestamps.sort(); timestamps.sort();
assert_eq!(Mtp::new(timestamps).unwrap().to_u32(), 500_000_005); assert_eq!(MedianTimePast::new(timestamps).unwrap().to_u32(), 500_000_005);
timestamps.reverse(); timestamps.reverse();
assert_eq!(Mtp::new(timestamps).unwrap().to_u32(), 500_000_005); assert_eq!(MedianTimePast::new(timestamps).unwrap().to_u32(), 500_000_005);
} }
} }

View File

@ -1,6 +1,7 @@
// SPDX-License-Identifier: CC0-1.0 // SPDX-License-Identifier: CC0-1.0
//! Provides [`Height`] and [`MtpInterval`] types used by the `rust-bitcoin` `relative::LockTime` type. //! Provides [`NumberOfBlocks`] and [`NumberOf512Seconds`] types used by the
//! `rust-bitcoin` `relative::LockTime` type.
use core::fmt; use core::fmt;
@ -9,16 +10,16 @@ use arbitrary::{Arbitrary, Unstructured};
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[deprecated(since = "TBD", note = "use `HeightIterval` instead")] #[deprecated(since = "TBD", note = "use `NumberOfBlocks` instead")]
#[doc(hidden)] #[doc(hidden)]
pub type Height = HeightInterval; pub type Height = NumberOfBlocks;
/// A relative lock time lock-by-blockheight value. /// A relative lock time lock-by-blockheight value.
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct HeightInterval(u16); pub struct NumberOfBlocks(u16);
impl HeightInterval { impl NumberOfBlocks {
/// Relative block height 0, can be included in any block. /// Relative block height 0, can be included in any block.
pub const ZERO: Self = Self(0); pub const ZERO: Self = Self(0);
@ -28,7 +29,7 @@ impl HeightInterval {
/// The maximum relative block height. /// The maximum relative block height.
pub const MAX: Self = Self(u16::MAX); pub const MAX: Self = Self(u16::MAX);
/// Constructs a new [`HeightInterval`] using a count of blocks. /// Constructs a new [`NumberOfBlocks`] using a count of blocks.
#[inline] #[inline]
pub const fn from_height(blocks: u16) -> Self { Self(blocks) } pub const fn from_height(blocks: u16) -> Self { Self(blocks) }
@ -80,51 +81,51 @@ impl HeightInterval {
} }
} }
impl From<u16> for HeightInterval { impl From<u16> for NumberOfBlocks {
#[inline] #[inline]
fn from(value: u16) -> Self { HeightInterval(value) } fn from(value: u16) -> Self { NumberOfBlocks(value) }
} }
crate::impl_parse_str_from_int_infallible!(HeightInterval, u16, from); crate::impl_parse_str_from_int_infallible!(NumberOfBlocks, u16, from);
impl fmt::Display for HeightInterval { impl fmt::Display for NumberOfBlocks {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) } fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
} }
#[deprecated(since = "TBD", note = "use `Mtp` instead")] #[deprecated(since = "TBD", note = "use `NumberOf512Seconds` instead")]
#[doc(hidden)] #[doc(hidden)]
pub type Time = MtpInterval; pub type Time = NumberOf512Seconds;
/// A relative lock time lock-by-blocktime value. /// A relative lock time lock-by-blocktime value.
/// ///
/// For BIP 68 relative lock-by-blocktime locks, time is measured in 512 second intervals. /// For BIP 68 relative lock-by-blocktime locks, time is measured in 512 second intervals.
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct MtpInterval(u16); pub struct NumberOf512Seconds(u16);
impl MtpInterval { impl NumberOf512Seconds {
/// Relative block time 0, can be included in any block. /// Relative block time 0, can be included in any block.
pub const ZERO: Self = MtpInterval(0); pub const ZERO: Self = NumberOf512Seconds(0);
/// The minimum relative block time (0), can be included in any block. /// The minimum relative block time (0), can be included in any block.
pub const MIN: Self = MtpInterval::ZERO; pub const MIN: Self = NumberOf512Seconds::ZERO;
/// The maximum relative block time (33,554,432 seconds or approx 388 days). /// The maximum relative block time (33,554,432 seconds or approx 388 days).
pub const MAX: Self = MtpInterval(u16::MAX); pub const MAX: Self = NumberOf512Seconds(u16::MAX);
/// Constructs a new [`MtpInterval`] using time intervals where each interval is equivalent to 512 seconds. /// Constructs a new [`NumberOf512Seconds`] using time intervals where each interval is equivalent to 512 seconds.
/// ///
/// Encoding finer granularity of time for relative lock-times is not supported in Bitcoin. /// Encoding finer granularity of time for relative lock-times is not supported in Bitcoin.
#[inline] #[inline]
pub const fn from_512_second_intervals(intervals: u16) -> Self { MtpInterval(intervals) } pub const fn from_512_second_intervals(intervals: u16) -> Self { NumberOf512Seconds(intervals) }
/// Express the [`MtpInterval`] as an integer number of 512-second intervals. /// Express the [`NumberOf512Seconds`] as an integer number of 512-second intervals.
#[inline] #[inline]
#[must_use] #[must_use]
pub const fn to_512_second_intervals(self) -> u16 { self.0 } pub const fn to_512_second_intervals(self) -> u16 { self.0 }
/// Constructs a new [`MtpInterval`] from seconds, converting the seconds into 512 second interval with /// Constructs a new [`NumberOf512Seconds`] from seconds, converting the seconds into 512 second
/// truncating division. /// interval with truncating division.
/// ///
/// # Errors /// # Errors
/// ///
@ -134,14 +135,14 @@ impl MtpInterval {
pub const fn from_seconds_floor(seconds: u32) -> Result<Self, TimeOverflowError> { pub const fn from_seconds_floor(seconds: u32) -> Result<Self, TimeOverflowError> {
let interval = seconds / 512; let interval = seconds / 512;
if interval <= u16::MAX as u32 { // infallible cast, needed by const code if interval <= u16::MAX as u32 { // infallible cast, needed by const code
Ok(MtpInterval::from_512_second_intervals(interval as u16)) // Cast checked above, needed by const code. Ok(NumberOf512Seconds::from_512_second_intervals(interval as u16)) // Cast checked above, needed by const code.
} else { } else {
Err(TimeOverflowError { seconds }) Err(TimeOverflowError { seconds })
} }
} }
/// Constructs a new [`MtpInterval`] from seconds, converting the seconds into 512 second intervals with /// Constructs a new [`NumberOf512Seconds`] from seconds, converting the seconds into 512 second
/// ceiling division. /// intervals with ceiling division.
/// ///
/// # Errors /// # Errors
/// ///
@ -151,13 +152,13 @@ impl MtpInterval {
pub const fn from_seconds_ceil(seconds: u32) -> Result<Self, TimeOverflowError> { pub const fn from_seconds_ceil(seconds: u32) -> Result<Self, TimeOverflowError> {
if seconds <= u16::MAX as u32 * 512 { if seconds <= u16::MAX as u32 * 512 {
let interval = (seconds + 511) / 512; let interval = (seconds + 511) / 512;
Ok(MtpInterval::from_512_second_intervals(interval as u16)) // Cast checked above, needed by const code. Ok(NumberOf512Seconds::from_512_second_intervals(interval as u16)) // Cast checked above, needed by const code.
} else { } else {
Err(TimeOverflowError { seconds }) Err(TimeOverflowError { seconds })
} }
} }
/// Represents the [`MtpInterval`] as an integer number of seconds. /// Represents the [`NumberOf512Seconds`] as an integer number of seconds.
#[inline] #[inline]
pub const fn to_seconds(self) -> u32 { pub const fn to_seconds(self) -> u32 {
self.0 as u32 * 512 // u16->u32 cast ok, const context self.0 as u32 * 512 // u16->u32 cast ok, const context
@ -206,9 +207,9 @@ impl MtpInterval {
} }
} }
crate::impl_parse_str_from_int_infallible!(MtpInterval, u16, from_512_second_intervals); crate::impl_parse_str_from_int_infallible!(NumberOf512Seconds, u16, from_512_second_intervals);
impl fmt::Display for MtpInterval { impl fmt::Display for NumberOf512Seconds {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) } fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
} }
@ -246,27 +247,27 @@ impl fmt::Display for TimeOverflowError {
impl std::error::Error for TimeOverflowError {} impl std::error::Error for TimeOverflowError {}
#[cfg(feature = "arbitrary")] #[cfg(feature = "arbitrary")]
impl<'a> Arbitrary<'a> for HeightInterval { impl<'a> Arbitrary<'a> for NumberOfBlocks {
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> { fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
let choice = u.int_in_range(0..=2)?; let choice = u.int_in_range(0..=2)?;
match choice { match choice {
0 => Ok(HeightInterval::MIN), 0 => Ok(NumberOfBlocks::MIN),
1 => Ok(HeightInterval::MAX), 1 => Ok(NumberOfBlocks::MAX),
_ => Ok(HeightInterval::from_height(u16::arbitrary(u)?)), _ => Ok(NumberOfBlocks::from_height(u16::arbitrary(u)?)),
} }
} }
} }
#[cfg(feature = "arbitrary")] #[cfg(feature = "arbitrary")]
impl<'a> Arbitrary<'a> for MtpInterval { impl<'a> Arbitrary<'a> for NumberOf512Seconds {
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> { fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
let choice = u.int_in_range(0..=2)?; let choice = u.int_in_range(0..=2)?;
match choice { match choice {
0 => Ok(MtpInterval::MIN), 0 => Ok(NumberOf512Seconds::MIN),
1 => Ok(MtpInterval::MAX), 1 => Ok(NumberOf512Seconds::MAX),
_ => Ok(MtpInterval::from_512_second_intervals(u16::arbitrary(u)?)), _ => Ok(NumberOf512Seconds::from_512_second_intervals(u16::arbitrary(u)?)),
} }
} }
} }
@ -284,72 +285,76 @@ mod tests {
#[test] #[test]
#[allow(deprecated_in_future)] #[allow(deprecated_in_future)]
fn sanity_check() { fn sanity_check() {
assert_eq!(HeightInterval::MAX.to_consensus_u32(), u32::from(u16::MAX)); assert_eq!(NumberOfBlocks::MAX.to_consensus_u32(), u32::from(u16::MAX));
assert_eq!(MtpInterval::from_512_second_intervals(100).value(), 100u16); assert_eq!(NumberOf512Seconds::from_512_second_intervals(100).value(), 100u16);
assert_eq!(MtpInterval::from_512_second_intervals(100).to_consensus_u32(), 4_194_404u32); // 0x400064 assert_eq!(
NumberOf512Seconds::from_512_second_intervals(100).to_consensus_u32(),
4_194_404u32
); // 0x400064
} }
#[test] #[test]
fn from_seconds_ceil_success() { fn from_seconds_ceil_success() {
let actual = MtpInterval::from_seconds_ceil(100).unwrap(); let actual = NumberOf512Seconds::from_seconds_ceil(100).unwrap();
let expected = MtpInterval(1_u16); let expected = NumberOf512Seconds(1_u16);
assert_eq!(actual, expected); assert_eq!(actual, expected);
} }
#[test] #[test]
fn from_seconds_ceil_with_maximum_encodable_seconds_success() { fn from_seconds_ceil_with_maximum_encodable_seconds_success() {
let actual = MtpInterval::from_seconds_ceil(MAXIMUM_ENCODABLE_SECONDS).unwrap(); let actual = NumberOf512Seconds::from_seconds_ceil(MAXIMUM_ENCODABLE_SECONDS).unwrap();
let expected = MtpInterval(u16::MAX); let expected = NumberOf512Seconds(u16::MAX);
assert_eq!(actual, expected); assert_eq!(actual, expected);
} }
#[test] #[test]
fn from_seconds_ceil_causes_time_overflow_error() { fn from_seconds_ceil_causes_time_overflow_error() {
let result = MtpInterval::from_seconds_ceil(MAXIMUM_ENCODABLE_SECONDS + 1); let result = NumberOf512Seconds::from_seconds_ceil(MAXIMUM_ENCODABLE_SECONDS + 1);
assert!(result.is_err()); assert!(result.is_err());
} }
#[test] #[test]
fn from_seconds_floor_success() { fn from_seconds_floor_success() {
let actual = MtpInterval::from_seconds_floor(100).unwrap(); let actual = NumberOf512Seconds::from_seconds_floor(100).unwrap();
let expected = MtpInterval(0_u16); let expected = NumberOf512Seconds(0_u16);
assert_eq!(actual, expected); assert_eq!(actual, expected);
} }
#[test] #[test]
fn from_seconds_floor_with_exact_interval() { fn from_seconds_floor_with_exact_interval() {
let actual = MtpInterval::from_seconds_floor(512).unwrap(); let actual = NumberOf512Seconds::from_seconds_floor(512).unwrap();
let expected = MtpInterval(1_u16); let expected = NumberOf512Seconds(1_u16);
assert_eq!(actual, expected); assert_eq!(actual, expected);
} }
#[test] #[test]
fn from_seconds_floor_with_maximum_encodable_seconds_success() { fn from_seconds_floor_with_maximum_encodable_seconds_success() {
let actual = MtpInterval::from_seconds_floor(MAXIMUM_ENCODABLE_SECONDS + 511).unwrap(); let actual =
let expected = MtpInterval(u16::MAX); NumberOf512Seconds::from_seconds_floor(MAXIMUM_ENCODABLE_SECONDS + 511).unwrap();
let expected = NumberOf512Seconds(u16::MAX);
assert_eq!(actual, expected); assert_eq!(actual, expected);
} }
#[test] #[test]
fn from_seconds_floor_causes_time_overflow_error() { fn from_seconds_floor_causes_time_overflow_error() {
let result = MtpInterval::from_seconds_floor(MAXIMUM_ENCODABLE_SECONDS + 512); let result = NumberOf512Seconds::from_seconds_floor(MAXIMUM_ENCODABLE_SECONDS + 512);
assert!(result.is_err()); assert!(result.is_err());
} }
#[test] #[test]
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
pub fn encode_decode_height() { pub fn encode_decode_height() {
serde_round_trip!(HeightInterval::ZERO); serde_round_trip!(NumberOfBlocks::ZERO);
serde_round_trip!(HeightInterval::MIN); serde_round_trip!(NumberOfBlocks::MIN);
serde_round_trip!(HeightInterval::MAX); serde_round_trip!(NumberOfBlocks::MAX);
} }
#[test] #[test]
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
pub fn encode_decode_time() { pub fn encode_decode_time() {
serde_round_trip!(MtpInterval::ZERO); serde_round_trip!(NumberOf512Seconds::ZERO);
serde_round_trip!(MtpInterval::MIN); serde_round_trip!(NumberOf512Seconds::MIN);
serde_round_trip!(MtpInterval::MAX); serde_round_trip!(NumberOf512Seconds::MAX);
} }
fn generate_timestamps(start: u32, step: u16) -> [BlockTime; 11] { fn generate_timestamps(start: u32, step: u16) -> [BlockTime; 11] {
@ -375,7 +380,7 @@ mod tests {
// Test case 1: Satisfaction (current_mtp >= utxo_mtp + required_seconds) // Test case 1: Satisfaction (current_mtp >= utxo_mtp + required_seconds)
// 10 intervals × 512 seconds = 5120 seconds // 10 intervals × 512 seconds = 5120 seconds
let time_lock = MtpInterval::from_512_second_intervals(10); let time_lock = NumberOf512Seconds::from_512_second_intervals(10);
let chain_state1 = BlockMtp::new(timestamps); let chain_state1 = BlockMtp::new(timestamps);
let utxo_state1 = BlockMtp::new(utxo_timestamps); let utxo_state1 = BlockMtp::new(utxo_timestamps);
assert!(time_lock.is_satisfied_by(chain_state1, utxo_state1)); assert!(time_lock.is_satisfied_by(chain_state1, utxo_state1));
@ -386,13 +391,13 @@ mod tests {
assert!(!time_lock.is_satisfied_by(chain_state2, utxo_state2)); assert!(!time_lock.is_satisfied_by(chain_state2, utxo_state2));
// Test case 3: Test with a larger value (100 intervals = 51200 seconds) // Test case 3: Test with a larger value (100 intervals = 51200 seconds)
let larger_lock = MtpInterval::from_512_second_intervals(100); let larger_lock = NumberOf512Seconds::from_512_second_intervals(100);
let chain_state3 = BlockMtp::new(timestamps3); let chain_state3 = BlockMtp::new(timestamps3);
let utxo_state3 = BlockMtp::new(utxo_timestamps3); let utxo_state3 = BlockMtp::new(utxo_timestamps3);
assert!(larger_lock.is_satisfied_by(chain_state3, utxo_state3)); assert!(larger_lock.is_satisfied_by(chain_state3, utxo_state3));
// Test case 4: Overflow handling - tests that is_satisfied_by handles overflow gracefully // Test case 4: Overflow handling - tests that is_satisfied_by handles overflow gracefully
let max_time_lock = MtpInterval::MAX; let max_time_lock = NumberOf512Seconds::MAX;
let chain_state4 = BlockMtp::new(timestamps); let chain_state4 = BlockMtp::new(timestamps);
let utxo_state4 = BlockMtp::new(utxo_timestamps); let utxo_state4 = BlockMtp::new(utxo_timestamps);
assert!(!max_time_lock.is_satisfied_by(chain_state4, utxo_state4)); assert!(!max_time_lock.is_satisfied_by(chain_state4, utxo_state4));
@ -402,7 +407,7 @@ mod tests {
fn test_height_chain_state() { fn test_height_chain_state() {
use crate::BlockHeight; use crate::BlockHeight;
let height_lock = HeightInterval(10); let height_lock = NumberOfBlocks(10);
// Test case 1: Satisfaction (current_height >= utxo_height + required) // Test case 1: Satisfaction (current_height >= utxo_height + required)
let chain_state1 = BlockHeight::from_u32(100); let chain_state1 = BlockHeight::from_u32(100);
@ -415,7 +420,7 @@ mod tests {
assert!(!height_lock.is_satisfied_by(chain_state2, utxo_state2)); assert!(!height_lock.is_satisfied_by(chain_state2, utxo_state2));
// Test case 3: Overflow handling - tests that is_satisfied_by handles overflow gracefully // Test case 3: Overflow handling - tests that is_satisfied_by handles overflow gracefully
let max_height_lock = HeightInterval::MAX; let max_height_lock = NumberOfBlocks::MAX;
let chain_state3 = BlockHeight::from_u32(1000); let chain_state3 = BlockHeight::from_u32(1000);
let utxo_state3 = BlockHeight::from_u32(80); let utxo_state3 = BlockHeight::from_u32(80);
assert!(!max_height_lock.is_satisfied_by(chain_state3, utxo_state3)); assert!(!max_height_lock.is_satisfied_by(chain_state3, utxo_state3));

View File

@ -38,7 +38,7 @@ struct Structs {
e: BlockInterval, e: BlockInterval,
f: FeeRate, f: FeeRate,
g: absolute::Height, g: absolute::Height,
h: absolute::Mtp, h: absolute::MedianTimePast,
i: relative::Height, i: relative::Height,
j: relative::Time, j: relative::Time,
k: Weight, k: Weight,
@ -57,7 +57,7 @@ impl Structs {
e: BlockInterval::MAX, e: BlockInterval::MAX,
f: FeeRate::MAX, f: FeeRate::MAX,
g: absolute::Height::MAX, g: absolute::Height::MAX,
h: absolute::Mtp::MAX, h: absolute::MedianTimePast::MAX,
i: relative::Height::MAX, i: relative::Height::MAX,
j: relative::Time::MAX, j: relative::Time::MAX,
k: Weight::MAX, k: Weight::MAX,
@ -89,7 +89,7 @@ struct CommonTraits {
e: BlockInterval, e: BlockInterval,
f: FeeRate, f: FeeRate,
g: absolute::Height, g: absolute::Height,
h: absolute::Mtp, h: absolute::MedianTimePast,
i: relative::Height, i: relative::Height,
j: relative::Time, j: relative::Time,
k: Weight, k: Weight,
@ -135,7 +135,7 @@ struct Errors {
t: amount::PossiblyConfusingDenominationError, t: amount::PossiblyConfusingDenominationError,
u: amount::TooPreciseError, u: amount::TooPreciseError,
v: amount::UnknownDenominationError, v: amount::UnknownDenominationError,
w: block::TooBigForRelativeBlockHeightIntervalError, w: block::TooBigForRelativeHeightError,
x: locktime::absolute::ConversionError, x: locktime::absolute::ConversionError,
y: locktime::absolute::Height, y: locktime::absolute::Height,
z: locktime::absolute::ParseHeightError, z: locktime::absolute::ParseHeightError,
@ -171,9 +171,7 @@ fn api_can_use_all_types_from_module_amount() {
#[test] #[test]
fn api_can_use_all_types_from_module_block() { fn api_can_use_all_types_from_module_block() {
use bitcoin_units::block::{ use bitcoin_units::block::{BlockHeight, BlockHeightInterval, TooBigForRelativeHeightError};
BlockHeight, BlockHeightInterval, TooBigForRelativeBlockHeightIntervalError,
};
} }
#[test] #[test]
@ -184,7 +182,7 @@ fn api_can_use_all_types_from_module_fee_rate() {
#[test] #[test]
fn api_can_use_all_types_from_module_locktime_absolute() { fn api_can_use_all_types_from_module_locktime_absolute() {
use bitcoin_units::locktime::absolute::{ use bitcoin_units::locktime::absolute::{
ConversionError, Height, Mtp, ParseHeightError, ParseTimeError, ConversionError, Height, MedianTimePast, ParseHeightError, ParseTimeError,
}; };
} }
@ -302,7 +300,7 @@ impl<'a> Arbitrary<'a> for Structs {
e: BlockInterval::arbitrary(u)?, e: BlockInterval::arbitrary(u)?,
f: FeeRate::arbitrary(u)?, f: FeeRate::arbitrary(u)?,
g: absolute::Height::arbitrary(u)?, g: absolute::Height::arbitrary(u)?,
h: absolute::Mtp::arbitrary(u)?, h: absolute::MedianTimePast::arbitrary(u)?,
i: relative::Height::arbitrary(u)?, i: relative::Height::arbitrary(u)?,
j: relative::Time::arbitrary(u)?, j: relative::Time::arbitrary(u)?,
k: Weight::arbitrary(u)?, k: Weight::arbitrary(u)?,

View File

@ -47,7 +47,7 @@ struct Serde {
a: BlockHeight, a: BlockHeight,
b: BlockInterval, b: BlockInterval,
c: absolute::Height, c: absolute::Height,
d: absolute::Mtp, d: absolute::MedianTimePast,
e: relative::Height, e: relative::Height,
f: relative::Time, f: relative::Time,
g: Weight, g: Weight,
@ -80,7 +80,7 @@ impl Serde {
a: BlockHeight::MAX, a: BlockHeight::MAX,
b: BlockInterval::MAX, b: BlockInterval::MAX,
c: absolute::Height::MAX, c: absolute::Height::MAX,
d: absolute::Mtp::MAX, d: absolute::MedianTimePast::MAX,
e: relative::Height::MAX, e: relative::Height::MAX,
f: relative::Time::MAX, f: relative::Time::MAX,
g: Weight::MAX, g: Weight::MAX,