Repository: rust-bitcoin/rust-bitcoin
Pull request #4431 (2025-05-02 18:07:58)

units: rename relative locktime types, absolute::Time, and constructors
This PR does a whole bunch of renames to the `units` locktime modules. These modules contain the underlying units for locktime types and hopefully aren't used directly too often, which should minimize the disruption from these renames.

This fixes a number of issues:

* Confusion between blocktimes and MTPs (which in fairness, *are* blocktimes, but they're not the one that users are likely to reach for)
* Constructor and conversion names that imply there is a "consensus encoding" for these bare units, which corresponded to the consensus encoding of the corresponding locktimes/sequence numbers
* `from_*` methods without `to_*` methods and vice-versa (overlaps with the above)
* the horribly named `value` method on relative heights and times (but not absolute ones)

This PR does **not** remove the `MtpAndHeight` type, nor does it add constructors for `Mtp` from lists of blocktimes. This is because the PR was too big already and I felt I should split it up.

Alternate to #4427




Patch:
diff --git a/bitcoin/src/blockdata/block.rs b/bitcoin/src/blockdata/block.rs
index b88f2a19..5fd59aa3 100644
--- a/bitcoin/src/blockdata/block.rs
+++ b/bitcoin/src/blockdata/block.rs
@@ -30,7 +30,7 @@
 #[doc(inline)]
 pub use primitives::block::{Block, Checked, Unchecked, Validation, Version, BlockHash, Header, WitnessCommitment};
 #[doc(inline)]
-pub use units::block::{BlockHeight, BlockInterval, TooBigForRelativeBlockHeightError};
+pub use units::block::{BlockHeight, BlockInterval, TooBigForRelativeBlockHeightIntervalError};
 
 impl_hashencode!(BlockHash);
 
diff --git a/bitcoin/src/blockdata/mod.rs b/bitcoin/src/blockdata/mod.rs
index ab3b6746..8255e3cc 100644
--- a/bitcoin/src/blockdata/mod.rs
+++ b/bitcoin/src/blockdata/mod.rs
@@ -41,7 +41,11 @@ pub mod absolute {
 
         /// Re-export everything from the `primitives::locktime::absolute` module.
         #[rustfmt::skip]        // Keep public re-exports separate.
-        pub use primitives::locktime::absolute::{ConversionError, Height, LockTime, ParseHeightError, ParseTimeError, Time};
+        pub use primitives::locktime::absolute::{ConversionError, Height, LockTime, ParseHeightError, ParseTimeError, Mtp};
+
+        #[deprecated(since = "TBD", note = "use `Mtp` instead")]
+        #[doc(hidden)]
+        pub type Time = Mtp;
 
         impl Encodable for LockTime {
             #[inline]
@@ -67,9 +71,17 @@ pub mod relative {
 
         /// Re-export everything from the `primitives::locktime::relative` module.
         pub use primitives::locktime::relative::{
-            DisabledLockTimeError, Height, IncompatibleHeightError, IncompatibleTimeError,
-            LockTime, Time, TimeOverflowError,
+            DisabledLockTimeError, HeightInterval, IncompatibleHeightError, IncompatibleTimeError,
+            LockTime, MtpInterval, TimeOverflowError,
         };
+
+        #[deprecated(since = "TBD", note = "use `Mtp` instead")]
+        #[doc(hidden)]
+        pub type Height = HeightInterval;
+
+        #[deprecated(since = "TBD", note = "use `Mtp` instead")]
+        #[doc(hidden)]
+        pub type Time = MtpInterval;
     }
 }
 
diff --git a/bitcoin/src/blockdata/transaction.rs b/bitcoin/src/blockdata/transaction.rs
index 25859724..ff2d7d19 100644
--- a/bitcoin/src/blockdata/transaction.rs
+++ b/bitcoin/src/blockdata/transaction.rs
@@ -20,7 +20,7 @@
 use super::Weight;
 use crate::consensus::{self, encode, Decodable, Encodable};
 use crate::internal_macros::{impl_consensus_encoding, impl_hashencode};
-use crate::locktime::absolute::{self, Height, Time};
+use crate::locktime::absolute::{self, Height, Mtp};
 use crate::prelude::{Borrow, Vec};
 use crate::script::{Script, ScriptBuf, ScriptExt as _, ScriptExtPriv as _};
 #[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
     /// considered to be satisfied i.e., there are no timelock constraints restricting this
     /// transaction from being mined immediately.
-    fn is_absolute_timelock_satisfied(&self, height: Height, time: Time) -> bool;
+    fn is_absolute_timelock_satisfied(&self, height: Height, time: Mtp) -> bool;
 
     /// Returns `true` if this transactions nLockTime is enabled ([BIP-65]).
     ///
@@ -393,7 +393,7 @@ fn is_coinbase(&self) -> bool {
 
     fn is_explicitly_rbf(&self) -> bool { self.input.iter().any(|input| input.sequence.is_rbf()) }
 
-    fn is_absolute_timelock_satisfied(&self, height: Height, time: Time) -> bool {
+    fn is_absolute_timelock_satisfied(&self, height: Height, time: Mtp) -> bool {
         if !self.is_lock_time_enabled() {
             return true;
         }
diff --git a/githooks/post-merge b/githooks/post-merge
index 2d78934d..0ca51829 100755
--- a/githooks/post-merge
+++ b/githooks/post-merge
@@ -22,7 +22,7 @@ do
 			>&2 cat <<- EOF
 			==================================================
 			Project githooks have changed. Please inspect the
-			changes and re-run \`just githooks-install\` if
+			changes and re-reun \`just githooks-install\` if
 			they are legitimate.
 
 			Remove $HOOKS_DIR/post-merge to skip this warning
diff --git a/primitives/src/locktime/absolute.rs b/primitives/src/locktime/absolute.rs
index 3d5205ac..9ce1b64e 100644
--- a/primitives/src/locktime/absolute.rs
+++ b/primitives/src/locktime/absolute.rs
@@ -16,7 +16,11 @@
 
 #[rustfmt::skip]                // Keep public re-exports separate.
 #[doc(inline)]
-pub use units::locktime::absolute::{ConversionError, Height, ParseHeightError, ParseTimeError, Time, LOCK_TIME_THRESHOLD};
+pub use units::locktime::absolute::{ConversionError, Height, ParseHeightError, ParseTimeError, Mtp, LOCK_TIME_THRESHOLD};
+
+#[deprecated(since = "TBD", note = "use `Mtp` instead")]
+#[doc(hidden)]
+pub type Time = Mtp;
 
 /// An absolute lock time value, representing either a block height or a UNIX timestamp (seconds
 /// since epoch).
@@ -79,7 +83,7 @@ pub enum LockTime {
     /// assert!(n.is_block_time());
     /// assert_eq!(n.to_consensus_u32(), seconds);
     /// ```
-    Seconds(Time),
+    Seconds(Mtp),
 }
 
 impl LockTime {
@@ -141,9 +145,9 @@ pub fn from_unprefixed_hex(s: &str) -> Result<Self, UnprefixedHexError> {
     #[allow(clippy::missing_panics_doc)]
     pub fn from_consensus(n: u32) -> Self {
         if units::locktime::absolute::is_block_height(n) {
-            Self::Blocks(Height::from_consensus(n).expect("n is valid"))
+            Self::Blocks(Height::from_u32(n).expect("n is valid"))
         } else {
-            Self::Seconds(Time::from_consensus(n).expect("n is valid"))
+            Self::Seconds(Mtp::from_u32(n).expect("n is valid"))
         }
     }
 
@@ -166,17 +170,23 @@ pub fn from_consensus(n: u32) -> Self {
     /// ```
     #[inline]
     pub fn from_height(n: u32) -> Result<Self, ConversionError> {
-        let height = Height::from_consensus(n)?;
+        let height = Height::from_u32(n)?;
         Ok(LockTime::Blocks(height))
     }
 
-    /// Constructs a new `LockTime` from `n`, expecting `n` to be a valid block time.
+    #[inline]
+    #[deprecated(since = "TBD", note = "use `from_mtp` instead")]
+    #[doc(hidden)]
+    pub fn from_time(n: u32) -> Result<Self, ConversionError> { Self::from_mtp(n) }
+
+    /// Constructs a new `LockTime` from `n`, expecting `n` to be a median-time-past (MTP)
+    /// which is in range for a locktime.
     ///
     /// # Note
     ///
-    /// If the locktime is set to a timestamp `T`,
-    /// the transaction can be included in a block only if the median time past (MTP) of the
-    /// last 11 blocks is greater than `T`.
+    /// If the locktime is set to an MTP `T`, the transaction can be included in a block only if
+    /// the MTP of last recent 11 blocks is greater than `T`.
+    ///
     /// It is possible to broadcast the transaction once the MTP is greater than `T`.[see BIP-113]
     ///
     /// [BIP-113 Median time-past as endpoint for lock-time calculations](https://github.com/bitcoin/bips/blob/master/bip-0113.mediawiki)
@@ -191,8 +201,8 @@ pub fn from_height(n: u32) -> Result<Self, ConversionError> {
     /// assert!(absolute::LockTime::from_time(741521).is_err());
     /// ```
     #[inline]
-    pub fn from_time(n: u32) -> Result<Self, ConversionError> {
-        let time = Time::from_consensus(n)?;
+    pub fn from_mtp(n: u32) -> Result<Self, ConversionError> {
+        let time = Mtp::from_u32(n)?;
         Ok(LockTime::Seconds(time))
     }
 
@@ -229,7 +239,7 @@ pub const fn is_block_time(self) -> bool { !self.is_block_height() }
     /// # use bitcoin_primitives::absolute;
     /// // Can be implemented if block chain data is available.
     /// fn get_height() -> absolute::Height { todo!("return the current block height") }
-    /// fn get_time() -> absolute::Time { todo!("return the current block time") }
+    /// fn get_time() -> absolute::Mtp { todo!("return the current block time") }
     ///
     /// let n = absolute::LockTime::from_consensus(741521); // `n OP_CHEKCLOCKTIMEVERIFY`.
     /// if n.is_satisfied_by(get_height(), get_time()) {
@@ -237,7 +247,7 @@ pub const fn is_block_time(self) -> bool { !self.is_block_height() }
     /// }
     /// ````
     #[inline]
-    pub fn is_satisfied_by(self, height: Height, time: Time) -> bool {
+    pub fn is_satisfied_by(self, height: Height, time: Mtp) -> bool {
         use LockTime as L;
 
         match self {
@@ -253,15 +263,9 @@ pub fn is_satisfied_by(self, height: Height, time: Time) -> bool {
     /// two lock times (same unit) then the larger lock time being satisfied implies (in a
     /// mathematical sense) the smaller one being satisfied.
     ///
-    /// This function serves multiple purposes:
-    ///
-    /// * When evaluating `OP_CHECKLOCKTIMEVERIFY` the argument must be less than or equal to the
-    ///   transactions nLockTime. If using this function to validate a script `self` is the argument
-    ///   to `CLTV` and `other` is the transaction nLockTime.
-    ///
-    /// * 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.
+    /// 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
     ///
@@ -310,8 +314,8 @@ pub fn is_implied_by(self, other: LockTime) -> bool {
     #[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(),
+            LockTime::Blocks(ref h) => h.to_u32(),
+            LockTime::Seconds(ref t) => t.to_u32(),
         }
     }
 }
@@ -323,9 +327,9 @@ impl From<Height> for LockTime {
     fn from(h: Height) -> Self { LockTime::Blocks(h) }
 }
 
-impl From<Time> for LockTime {
+impl From<Mtp> for LockTime {
     #[inline]
-    fn from(t: Time) -> Self { LockTime::Seconds(t) }
+    fn from(t: Mtp) -> Self { LockTime::Seconds(t) }
 }
 
 impl fmt::Debug for LockTime {
@@ -412,7 +416,7 @@ mod tests {
     #[test]
     fn display_and_alternate() {
         let lock_by_height = LockTime::from_height(741_521).unwrap();
-        let lock_by_time = LockTime::from_time(1_653_195_600).unwrap(); // May 22nd 2022, 5am UTC.
+        let lock_by_time = LockTime::from_mtp(1_653_195_600).unwrap(); // May 22nd 2022, 5am UTC.
 
         assert_eq!(format!("{}", lock_by_height), "741521");
         assert_eq!(format!("{:#}", lock_by_height), "block-height 741521");
@@ -468,9 +472,9 @@ fn invalid_locktime_type() {
         assert!(LockTime::from_height(500_000_000).is_err()); // The threshold.
         assert!(LockTime::from_height(500_000_001).is_err()); // Above the threshold.
 
-        assert!(LockTime::from_time(499_999_999).is_err()); // Below the threshold.
-        assert!(LockTime::from_time(500_000_000).is_ok()); // The threshold.
-        assert!(LockTime::from_time(500_000_001).is_ok()); // Above the threshold.
+        assert!(LockTime::from_mtp(499_999_999).is_err()); // Below the threshold.
+        assert!(LockTime::from_mtp(500_000_000).is_ok()); // The threshold.
+        assert!(LockTime::from_mtp(500_000_001).is_ok()); // Above the threshold.
     }
 
     #[test]
@@ -495,14 +499,14 @@ fn parses_correctly_to_height_or_time() {
 
     #[test]
     fn satisfied_by_height() {
-        let height_below = Height::from_consensus(700_000).unwrap();
-        let height = Height::from_consensus(750_000).unwrap();
-        let height_above = Height::from_consensus(800_000).unwrap();
+        let height_below = Height::from_u32(700_000).unwrap();
+        let height = Height::from_u32(750_000).unwrap();
+        let height_above = Height::from_u32(800_000).unwrap();
 
         let lock_by_height = LockTime::from(height);
 
         let t: u32 = 1_653_195_600; // May 22nd, 5am UTC.
-        let time = Time::from_consensus(t).unwrap();
+        let time = Mtp::from_u32(t).unwrap();
 
         assert!(!lock_by_height.is_satisfied_by(height_below, time));
         assert!(lock_by_height.is_satisfied_by(height, time));
@@ -511,13 +515,13 @@ fn satisfied_by_height() {
 
     #[test]
     fn satisfied_by_time() {
-        let time_before = Time::from_consensus(1_653_109_200).unwrap(); // "May 21th 2022, 5am UTC.
-        let time = Time::from_consensus(1_653_195_600).unwrap(); // "May 22nd 2022, 5am UTC.
-        let time_after = Time::from_consensus(1_653_282_000).unwrap(); // "May 23rd 2022, 5am UTC.
+        let time_before = Mtp::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_after = Mtp::from_u32(1_653_282_000).unwrap(); // "May 23rd 2022, 5am UTC.
 
         let lock_by_time = LockTime::from(time);
 
-        let height = Height::from_consensus(800_000).unwrap();
+        let height = Height::from_u32(800_000).unwrap();
 
         assert!(!lock_by_time.is_satisfied_by(height, time_before));
         assert!(lock_by_time.is_satisfied_by(height, time));
diff --git a/primitives/src/locktime/relative.rs b/primitives/src/locktime/relative.rs
index 3493e37f..053e883c 100644
--- a/primitives/src/locktime/relative.rs
+++ b/primitives/src/locktime/relative.rs
@@ -13,9 +13,17 @@
 
 #[rustfmt::skip]                // Keep public re-exports separate.
 #[doc(inline)]
-pub use units::locktime::relative::{Height, Time, TimeOverflowError};
+pub use units::locktime::relative::{HeightInterval, MtpInterval, TimeOverflowError};
 use units::mtp_height::MtpAndHeight;
 
+#[deprecated(since = "TBD", note = "use `Mtp` instead")]
+#[doc(hidden)]
+pub type Height = HeightInterval;
+
+#[deprecated(since = "TBD", note = "use `Mtp` instead")]
+#[doc(hidden)]
+pub type Time = MtpInterval;
+
 /// A relative lock time value, representing either a block height or time (512 second intervals).
 ///
 /// Used for sequence numbers (`nSequence` in Bitcoin Core and [`TxIn::sequence`]
@@ -61,7 +69,7 @@
 ///
 /// let chain_tip = MtpAndHeight::new(current_height, timestamps);
 /// let utxo_mined_at = MtpAndHeight::new(utxo_height, utxo_timestamps);
-/// let locktime = relative::LockTime::Time(relative::Time::from_512_second_intervals(10));
+/// let locktime = relative::LockTime::Time(relative::MtpInterval::from_512_second_intervals(10));
 ///
 /// // Check if locktime is satisfied
 /// assert!(locktime.is_satisfied_by(chain_tip, utxo_mined_at));
@@ -70,15 +78,15 @@
 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
 pub enum LockTime {
     /// A block height lock time value.
-    Blocks(Height),
+    Blocks(HeightInterval),
     /// A 512 second time interval value.
-    Time(Time),
+    Time(MtpInterval),
 }
 
 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);
+    pub const ZERO: LockTime = LockTime::Blocks(HeightInterval::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.
@@ -124,8 +132,9 @@ pub fn from_consensus(n: u32) -> Result<Self, DisabledLockTimeError> {
     #[inline]
     pub fn to_consensus_u32(self) -> u32 {
         match self {
-            LockTime::Blocks(ref h) => h.to_consensus_u32(),
-            LockTime::Time(ref t) => t.to_consensus_u32(),
+            LockTime::Blocks(ref h) => u32::from(h.to_height()),
+            LockTime::Time(ref t) =>
+                Sequence::LOCK_TYPE_MASK | u32::from(t.to_512_second_intervals()),
         }
     }
 
@@ -156,7 +165,7 @@ pub fn to_sequence(self) -> Sequence { Sequence::from_consensus(self.to_consensu
 
     /// Constructs a new `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)) }
+    pub const fn from_height(n: u16) -> Self { LockTime::Blocks(HeightInterval::from_height(n)) }
 
     /// Constructs a new `LockTime` from `n`, expecting `n` to be a count of 512-second intervals.
     ///
@@ -164,7 +173,7 @@ pub const fn from_height(n: u16) -> Self { LockTime::Blocks(Height::from_height(
     /// [`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))
+        LockTime::Time(MtpInterval::from_512_second_intervals(intervals))
     }
 
     /// Construct a new [`LockTime`] from seconds, converting the seconds into 512 second interval
@@ -175,7 +184,7 @@ pub const fn from_512_second_intervals(intervals: u16) -> Self {
     /// Will return an error if the input cannot be encoded in 16 bits.
     #[inline]
     pub const fn from_seconds_floor(seconds: u32) -> Result<Self, TimeOverflowError> {
-        match Time::from_seconds_floor(seconds) {
+        match MtpInterval::from_seconds_floor(seconds) {
             Ok(time) => Ok(LockTime::Time(time)),
             Err(e) => Err(e),
         }
@@ -189,7 +198,7 @@ pub const fn from_seconds_floor(seconds: u32) -> Result<Self, TimeOverflowError>
     /// Will return an error if the input cannot be encoded in 16 bits.
     #[inline]
     pub const fn from_seconds_ceil(seconds: u32) -> Result<Self, TimeOverflowError> {
-        match Time::from_seconds_ceil(seconds) {
+        match MtpInterval::from_seconds_ceil(seconds) {
             Ok(time) => Ok(LockTime::Time(time)),
             Err(e) => Err(e),
         }
@@ -216,7 +225,7 @@ pub const fn is_block_time(self) -> bool { !self.is_block_height() }
     /// # Examples
     ///
     /// ```rust
-    /// # use bitcoin_primitives::locktime::relative::Height;
+    /// # use bitcoin_primitives::locktime::relative::HeightInterval;
     /// # use bitcoin_primitives::relative::Time;
     /// # use units::mtp_height::MtpAndHeight;
     /// # use bitcoin_primitives::BlockHeight;
@@ -285,8 +294,8 @@ pub fn is_implied_by(self, other: LockTime) -> bool {
         use LockTime as L;
 
         match (self, other) {
-            (L::Blocks(this), L::Blocks(other)) => this.value() <= other.value(),
-            (L::Time(this), L::Time(other)) => this.value() <= other.value(),
+            (L::Blocks(this), L::Blocks(other)) => this <= other,
+            (L::Time(this), L::Time(other)) => this <= other,
             _ => false, // Not the same units.
         }
     }
@@ -320,7 +329,7 @@ pub fn is_implied_by_sequence(self, other: Sequence) -> bool {
         }
     }
 
-    /// Returns true if this [`relative::LockTime`] is satisfied by [`Height`].
+    /// Returns true if this [`relative::LockTime`] is satisfied by [`HeightInterval`].
     ///
     /// # Errors
     ///
@@ -334,14 +343,17 @@ pub fn is_implied_by_sequence(self, other: Sequence) -> bool {
     ///
     /// let required_height: u16 = 100;
     /// let lock = Sequence::from_height(required_height).to_relative_lock_time().expect("valid height");
-    /// assert!(lock.is_satisfied_by_height(relative::Height::from(required_height + 1)).expect("a height"));
+    /// assert!(lock.is_satisfied_by_height(relative::HeightInterval::from(required_height + 1)).expect("a height"));
     /// ```
     #[inline]
-    pub fn is_satisfied_by_height(self, height: Height) -> Result<bool, IncompatibleHeightError> {
+    pub fn is_satisfied_by_height(
+        self,
+        height: HeightInterval,
+    ) -> Result<bool, IncompatibleHeightError> {
         use LockTime as L;
 
         match self {
-            L::Blocks(ref required_height) => Ok(required_height.value() <= height.value()),
+            L::Blocks(required_height) => Ok(required_height <= height),
             L::Time(time) => Err(IncompatibleHeightError { height, time }),
         }
     }
@@ -363,24 +375,24 @@ pub fn is_satisfied_by_height(self, height: Height) -> Result<bool, Incompatible
     /// assert!(lock.is_satisfied_by_time(relative::Time::from_512_second_intervals(intervals + 10)).expect("a time"));
     /// ```
     #[inline]
-    pub fn is_satisfied_by_time(self, time: Time) -> Result<bool, IncompatibleTimeError> {
+    pub fn is_satisfied_by_time(self, time: MtpInterval) -> Result<bool, IncompatibleTimeError> {
         use LockTime as L;
 
         match self {
-            L::Time(ref t) => Ok(t.value() <= time.value()),
+            L::Time(ref t) => Ok(t.to_512_second_intervals() <= time.to_512_second_intervals()),
             L::Blocks(height) => Err(IncompatibleTimeError { time, height }),
         }
     }
 }
 
-impl From<Height> for LockTime {
+impl From<HeightInterval> for LockTime {
     #[inline]
-    fn from(h: Height) -> Self { LockTime::Blocks(h) }
+    fn from(h: HeightInterval) -> Self { LockTime::Blocks(h) }
 }
 
-impl From<Time> for LockTime {
+impl From<MtpInterval> for LockTime {
     #[inline]
-    fn from(t: Time) -> Self { LockTime::Time(t) }
+    fn from(t: MtpInterval) -> Self { LockTime::Time(t) }
 }
 
 impl fmt::Display for LockTime {
@@ -440,17 +452,17 @@ impl std::error::Error for DisabledLockTimeError {}
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub struct IncompatibleHeightError {
     /// Attempted to satisfy a lock-by-blocktime lock with this height.
-    height: Height,
+    height: HeightInterval,
     /// The inner time value of the lock-by-blocktime lock.
-    time: Time,
+    time: MtpInterval,
 }
 
 impl IncompatibleHeightError {
     /// Returns the height that was erroneously used to try and satisfy a lock-by-blocktime lock.
-    pub fn incompatible(&self) -> Height { self.height }
+    pub fn incompatible(&self) -> HeightInterval { self.height }
 
     /// Returns the time value of the lock-by-blocktime lock.
-    pub fn expected(&self) -> Time { self.time }
+    pub fn expected(&self) -> MtpInterval { self.time }
 }
 
 impl fmt::Display for IncompatibleHeightError {
@@ -471,17 +483,17 @@ impl std::error::Error for IncompatibleHeightError {}
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub struct IncompatibleTimeError {
     /// Attempted to satisfy a lock-by-blockheight lock with this time.
-    time: Time,
+    time: MtpInterval,
     /// The inner height value of the lock-by-blockheight lock.
-    height: Height,
+    height: HeightInterval,
 }
 
 impl IncompatibleTimeError {
     /// Returns the time that was erroneously used to try and satisfy a lock-by-blockheight lock.
-    pub fn incompatible(&self) -> Time { self.time }
+    pub fn incompatible(&self) -> MtpInterval { self.time }
 
     /// Returns the height value of the lock-by-blockheight lock.
-    pub fn expected(&self) -> Height { self.height }
+    pub fn expected(&self) -> HeightInterval { self.height }
 }
 
 impl fmt::Display for IncompatibleTimeError {
@@ -536,10 +548,10 @@ fn from_seconds_ceil_and_floor() {
 
     #[test]
     fn parses_correctly_to_height_or_time() {
-        let height1 = Height::from(10);
-        let height2 = Height::from(11);
-        let time1 = Time::from_512_second_intervals(70);
-        let time2 = Time::from_512_second_intervals(71);
+        let height1 = HeightInterval::from(10);
+        let height2 = HeightInterval::from(11);
+        let time1 = MtpInterval::from_512_second_intervals(70);
+        let time2 = MtpInterval::from_512_second_intervals(71);
 
         let lock_by_height1 = LockTime::from(height1);
         let lock_by_height2 = LockTime::from(height2);
@@ -561,28 +573,34 @@ fn parses_correctly_to_height_or_time() {
 
     #[test]
     fn height_correctly_implies() {
-        let height = Height::from(10);
+        let height = HeightInterval::from(10);
         let lock_by_height = LockTime::from(height);
 
-        assert!(!lock_by_height.is_implied_by(LockTime::from(Height::from(9))));
-        assert!(lock_by_height.is_implied_by(LockTime::from(Height::from(10))));
-        assert!(lock_by_height.is_implied_by(LockTime::from(Height::from(11))));
+        assert!(!lock_by_height.is_implied_by(LockTime::from(HeightInterval::from(9))));
+        assert!(lock_by_height.is_implied_by(LockTime::from(HeightInterval::from(10))));
+        assert!(lock_by_height.is_implied_by(LockTime::from(HeightInterval::from(11))));
     }
 
     #[test]
     fn time_correctly_implies() {
-        let time = Time::from_512_second_intervals(70);
+        let time = MtpInterval::from_512_second_intervals(70);
         let lock_by_time = LockTime::from(time);
 
-        assert!(!lock_by_time.is_implied_by(LockTime::from(Time::from_512_second_intervals(69))));
-        assert!(lock_by_time.is_implied_by(LockTime::from(Time::from_512_second_intervals(70))));
-        assert!(lock_by_time.is_implied_by(LockTime::from(Time::from_512_second_intervals(71))));
+        assert!(
+            !lock_by_time.is_implied_by(LockTime::from(MtpInterval::from_512_second_intervals(69)))
+        );
+        assert!(
+            lock_by_time.is_implied_by(LockTime::from(MtpInterval::from_512_second_intervals(70)))
+        );
+        assert!(
+            lock_by_time.is_implied_by(LockTime::from(MtpInterval::from_512_second_intervals(71)))
+        );
     }
 
     #[test]
     fn sequence_correctly_implies() {
-        let height = Height::from(10);
-        let time = Time::from_512_second_intervals(70);
+        let height = HeightInterval::from(10);
+        let time = MtpInterval::from_512_second_intervals(70);
 
         let lock_by_height = LockTime::from(height);
         let lock_by_time = LockTime::from(time);
@@ -603,8 +621,8 @@ fn sequence_correctly_implies() {
 
     #[test]
     fn incorrect_units_do_not_imply() {
-        let time = Time::from_512_second_intervals(70);
-        let height = Height::from(10);
+        let time = MtpInterval::from_512_second_intervals(70);
+        let height = HeightInterval::from(10);
 
         let lock_by_time = LockTime::from(time);
         assert!(!lock_by_time.is_implied_by(LockTime::from(height)));
@@ -643,8 +661,8 @@ fn disabled_locktime_error() {
 
     #[test]
     fn incompatible_height_error() {
-        let height = Height::from(10);
-        let time = Time::from_512_second_intervals(70);
+        let height = HeightInterval::from(10);
+        let time = MtpInterval::from_512_second_intervals(70);
         let lock_by_time = LockTime::from(time);
         let err = lock_by_time.is_satisfied_by_height(height).unwrap_err();
 
@@ -655,8 +673,8 @@ fn incompatible_height_error() {
 
     #[test]
     fn incompatible_time_error() {
-        let height = Height::from(10);
-        let time = Time::from_512_second_intervals(70);
+        let height = HeightInterval::from(10);
+        let time = MtpInterval::from_512_second_intervals(70);
         let lock_by_height = LockTime::from(height);
         let err = lock_by_height.is_satisfied_by_time(time).unwrap_err();
 
@@ -681,16 +699,16 @@ fn test_locktime_chain_state() {
         let chain_tip = MtpAndHeight::new(BlockHeight::from_u32(100), timestamps);
         let utxo_mined_at = MtpAndHeight::new(BlockHeight::from_u32(80), utxo_timestamps);
 
-        let lock1 = LockTime::Blocks(Height::from(10));
+        let lock1 = LockTime::Blocks(HeightInterval::from(10));
         assert!(lock1.is_satisfied_by(chain_tip, utxo_mined_at));
 
-        let lock2 = LockTime::Blocks(Height::from(21));
+        let lock2 = LockTime::Blocks(HeightInterval::from(21));
         assert!(!lock2.is_satisfied_by(chain_tip, utxo_mined_at));
 
-        let lock3 = LockTime::Time(Time::from_512_second_intervals(10));
+        let lock3 = LockTime::Time(MtpInterval::from_512_second_intervals(10));
         assert!(lock3.is_satisfied_by(chain_tip, utxo_mined_at));
 
-        let lock4 = LockTime::Time(Time::from_512_second_intervals(20000));
+        let lock4 = LockTime::Time(MtpInterval::from_512_second_intervals(20000));
         assert!(!lock4.is_satisfied_by(chain_tip, utxo_mined_at));
 
         assert!(LockTime::ZERO.is_satisfied_by(chain_tip, utxo_mined_at));
@@ -699,10 +717,10 @@ fn test_locktime_chain_state() {
         let lock6 = LockTime::from_seconds_floor(5000).unwrap();
         assert!(lock6.is_satisfied_by(chain_tip, utxo_mined_at));
 
-        let max_height_lock = LockTime::Blocks(Height::MAX);
+        let max_height_lock = LockTime::Blocks(HeightInterval::MAX);
         assert!(!max_height_lock.is_satisfied_by(chain_tip, utxo_mined_at));
 
-        let max_time_lock = LockTime::Time(Time::MAX);
+        let max_time_lock = LockTime::Time(MtpInterval::MAX);
         assert!(!max_time_lock.is_satisfied_by(chain_tip, utxo_mined_at));
 
         let max_chain_tip =
diff --git a/primitives/src/sequence.rs b/primitives/src/sequence.rs
index 6078846c..b659c98e 100644
--- a/primitives/src/sequence.rs
+++ b/primitives/src/sequence.rs
@@ -70,7 +70,7 @@ impl Sequence {
     /// BIP-68 relative lock time disable flag mask.
     const LOCK_TIME_DISABLE_FLAG_MASK: u32 = 0x8000_0000;
     /// BIP-68 relative lock time type flag mask.
-    const LOCK_TYPE_MASK: u32 = 0x0040_0000;
+    pub(super) const LOCK_TYPE_MASK: u32 = 0x0040_0000;
 
     /// Returns `true` if the sequence number enables absolute lock-time ([`Transaction::lock_time`]).
     #[inline]
@@ -187,7 +187,7 @@ pub fn to_consensus_u32(self) -> u32 { self.0 }
     /// Constructs a new [`relative::LockTime`] from this [`Sequence`] number.
     #[inline]
     pub fn to_relative_lock_time(self) -> Option<relative::LockTime> {
-        use crate::locktime::relative::{Height, LockTime, Time};
+        use crate::locktime::relative::{HeightInterval, LockTime, MtpInterval};
 
         if !self.is_relative_lock_time() {
             return None;
@@ -196,9 +196,9 @@ pub fn to_relative_lock_time(self) -> Option<relative::LockTime> {
         let lock_value = self.low_u16();
 
         if self.is_time_locked() {
-            Some(LockTime::from(Time::from_512_second_intervals(lock_value)))
+            Some(LockTime::from(MtpInterval::from_512_second_intervals(lock_value)))
         } else {
-            Some(LockTime::from(Height::from(lock_value)))
+            Some(LockTime::from(HeightInterval::from(lock_value)))
         }
     }
 
@@ -261,10 +261,16 @@ fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
             1 => Ok(Sequence::ZERO),
             2 => Ok(Sequence::MIN_NO_RBF),
             3 => Ok(Sequence::ENABLE_LOCKTIME_AND_RBF),
-            4 => Ok(Sequence::from_consensus(relative::Height::MIN.to_consensus_u32())),
-            5 => Ok(Sequence::from_consensus(relative::Height::MAX.to_consensus_u32())),
-            6 => Ok(Sequence::from_consensus(relative::Time::MIN.to_consensus_u32())),
-            7 => Ok(Sequence::from_consensus(relative::Time::MAX.to_consensus_u32())),
+            4 => Ok(Sequence::from_consensus(u32::from(relative::HeightInterval::MIN.to_height()))),
+            5 => Ok(Sequence::from_consensus(u32::from(relative::HeightInterval::MAX.to_height()))),
+            6 => Ok(Sequence::from_consensus(
+                Sequence::LOCK_TYPE_MASK
+                    | u32::from(relative::MtpInterval::MIN.to_512_second_intervals()),
+            )),
+            7 => Ok(Sequence::from_consensus(
+                Sequence::LOCK_TYPE_MASK
+                    | u32::from(relative::MtpInterval::MAX.to_512_second_intervals()),
+            )),
             _ => Ok(Sequence(u.arbitrary()?)),
         }
     }
diff --git a/units/src/block.rs b/units/src/block.rs
index 5d0dc90b..000f0995 100644
--- a/units/src/block.rs
+++ b/units/src/block.rs
@@ -70,7 +70,7 @@ impl From<absolute::Height> for BlockHeight {
     /// An absolute locktime block height has a maximum value of [`absolute::LOCK_TIME_THRESHOLD`]
     /// (500,000,000) where as a [`BlockHeight`] is a thin wrapper around a `u32`, the two types are
     /// not interchangeable.
-    fn from(h: absolute::Height) -> Self { Self::from_u32(h.to_consensus_u32()) }
+    fn from(h: absolute::Height) -> Self { Self::from_u32(h.to_u32()) }
 }
 
 impl TryFrom<BlockHeight> for absolute::Height {
@@ -82,7 +82,7 @@ impl TryFrom<BlockHeight> for absolute::Height {
     /// (500,000,000) where as a [`BlockHeight`] is a thin wrapper around a `u32`, the two types are
     /// not interchangeable.
     fn try_from(h: BlockHeight) -> Result<Self, Self::Error> {
-        absolute::Height::from_consensus(h.to_u32())
+        absolute::Height::from_u32(h.to_u32())
     }
 }
 
@@ -129,47 +129,48 @@ impl From<BlockInterval> for u32 {
     fn from(height: BlockInterval) -> Self { height.to_u32() }
 }
 
-impl From<relative::Height> for BlockInterval {
-    /// Converts a [`locktime::relative::Height`] to a [`BlockInterval`].
+impl From<relative::HeightInterval> for BlockInterval {
+    /// Converts a [`locktime::relative::HeightInterval`] to a [`BlockInterval`].
     ///
     /// A relative locktime block height has a maximum value of `u16::MAX` where as a
     /// [`BlockInterval`] is a thin wrapper around a `u32`, the two types are not interchangeable.
-    fn from(h: relative::Height) -> Self { Self::from_u32(h.value().into()) }
+    fn from(h: relative::HeightInterval) -> Self { Self::from_u32(h.to_height().into()) }
 }
 
-impl TryFrom<BlockInterval> for relative::Height {
-    type Error = TooBigForRelativeBlockHeightError;
+impl TryFrom<BlockInterval> for relative::HeightInterval {
+    type Error = TooBigForRelativeBlockHeightIntervalError;
 
-    /// Converts a [`BlockInterval`] to a [`locktime::relative::Height`].
+    /// Converts a [`BlockInterval`] to a [`locktime::relative::HeightInterval`].
     ///
     /// A relative locktime block height has a maximum value of `u16::MAX` where as a
     /// [`BlockInterval`] is a thin wrapper around a `u32`, the two types are not interchangeable.
     fn try_from(h: BlockInterval) -> Result<Self, Self::Error> {
         let h = h.to_u32();
+
         if h > u32::from(u16::MAX) {
-            return Err(TooBigForRelativeBlockHeightError(h));
+            return Err(TooBigForRelativeBlockHeightIntervalError(h));
         }
-        Ok(relative::Height::from(h as u16)) // Cast ok, value checked above.
+        Ok(relative::HeightInterval::from(h as u16)) // Cast ok, value checked above.
     }
 }
 
 /// Error returned when the block interval is too big to be used as a relative lock time.
 #[derive(Debug, Clone, PartialEq, Eq)]
-pub struct TooBigForRelativeBlockHeightError(u32);
+pub struct TooBigForRelativeBlockHeightIntervalError(u32);
 
-impl fmt::Display for TooBigForRelativeBlockHeightError {
+impl fmt::Display for TooBigForRelativeBlockHeightIntervalError {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(
             f,
             "block interval is too big to be used as a relative lock time: {} (max: {})",
             self.0,
-            relative::Height::MAX
+            relative::HeightInterval::MAX
         )
     }
 }
 
 #[cfg(feature = "std")]
-impl std::error::Error for TooBigForRelativeBlockHeightError {}
+impl std::error::Error for TooBigForRelativeBlockHeightIntervalError {}
 
 crate::internal_macros::impl_op_for_references! {
     // height - height = interval
@@ -279,14 +280,14 @@ fn sanity_check() {
         let interval: u32 = BlockInterval(100).into();
         assert_eq!(interval, 100);
 
-        let interval_from_height: BlockInterval = relative::Height::from(10u16).into();
+        let interval_from_height: BlockInterval = relative::HeightInterval::from(10u16).into();
         assert_eq!(interval_from_height.to_u32(), 10u32);
 
         let invalid_height_greater =
-            relative::Height::try_from(BlockInterval(u32::from(u16::MAX) + 1));
+            relative::HeightInterval::try_from(BlockInterval(u32::from(u16::MAX) + 1));
         assert!(invalid_height_greater.is_err());
 
-        let valid_height = relative::Height::try_from(BlockInterval(u32::from(u16::MAX)));
+        let valid_height = relative::HeightInterval::try_from(BlockInterval(u32::from(u16::MAX)));
         assert!(valid_height.is_ok());
     }
 
diff --git a/units/src/locktime/absolute.rs b/units/src/locktime/absolute.rs
index 71f301e5..1df4b04c 100644
--- a/units/src/locktime/absolute.rs
+++ b/units/src/locktime/absolute.rs
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: CC0-1.0
 
-//! Provides [`Height`] and [`Time`] types used by the `rust-bitcoin` `absolute::LockTime` type.
+//! Provides [`Height`] and [`Mtp`] types used by the `rust-bitcoin` `absolute::LockTime` type.
 
 use core::convert::Infallible;
 use core::fmt;
@@ -45,15 +45,22 @@ impl Height {
     /// # Errors
     ///
     /// If the input string is not a valid hex representation of a block height.
-    pub fn from_hex(s: &str) -> Result<Self, ParseHeightError> {
-        parse_hex(s, Self::from_consensus)
-    }
+    pub fn from_hex(s: &str) -> Result<Self, ParseHeightError> { parse_hex(s, Self::from_u32) }
+
+    #[deprecated(since = "TBD", note = "use `from_u32` instead")]
+    #[doc(hidden)]
+    pub const fn from_consensus(n: u32) -> Result<Self, ConversionError> { Self::from_u32(n) }
 
-    /// Constructs a new block height.
+    #[deprecated(since = "TBD", note = "use `to_u32` instead")]
+    #[doc(hidden)]
+    pub const fn to_consensus_u32(self) -> u32 { self.to_u32() }
+
+    /// Constructs a new block height directly from a `u32` value.
     ///
     /// # Errors
     ///
-    /// If `n` does not represent a valid block height value.
+    /// If `n` does not represent a block height within the valid range for a locktime:
+    /// `[0, 499_999_999]`.
     ///
     /// # Examples
     ///
@@ -61,11 +68,11 @@ pub fn from_hex(s: &str) -> Result<Self, ParseHeightError> {
     /// use bitcoin_units::locktime::absolute::Height;
     ///
     /// let h: u32 = 741521;
-    /// let height = Height::from_consensus(h).expect("invalid height value");
+    /// let height = Height::from_u32(h).expect("invalid height value");
     /// assert_eq!(height.to_consensus_u32(), h);
     /// ```
     #[inline]
-    pub const fn from_consensus(n: u32) -> Result<Height, ConversionError> {
+    pub const fn from_u32(n: u32) -> Result<Height, ConversionError> {
         if is_block_height(n) {
             Ok(Self(n))
         } else {
@@ -73,16 +80,16 @@ pub const fn from_consensus(n: u32) -> Result<Height, ConversionError> {
         }
     }
 
-    /// Converts this [`Height`] to its inner `u32` value.
+    /// Converts this [`Height`] to a raw `u32` value.
     #[inline]
-    pub const fn to_consensus_u32(self) -> u32 { self.0 }
+    pub const fn to_u32(self) -> u32 { self.0 }
 }
 
 impl fmt::Display for Height {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
 }
 
-crate::impl_parse_str!(Height, ParseHeightError, parser(Height::from_consensus));
+crate::impl_parse_str!(Height, ParseHeightError, parser(Height::from_u32));
 
 /// Error returned when parsing block height fails.
 #[derive(Debug, Clone, Eq, PartialEq)]
@@ -111,7 +118,7 @@ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
         D: serde::Deserializer<'de>,
     {
         let u = u32::deserialize(deserializer)?;
-        Height::from_consensus(u).map_err(serde::de::Error::custom)
+        Height::from_u32(u).map_err(serde::de::Error::custom)
     }
 }
 
@@ -121,51 +128,69 @@ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
     where
         S: serde::Serializer,
     {
-        self.to_consensus_u32().serialize(serializer)
+        self.to_u32().serialize(serializer)
     }
 }
 
-/// A UNIX timestamp, seconds since epoch, guaranteed to always contain a valid time value.
+#[deprecated(since = "TBD", note = "use `Mtp` instead")]
+#[doc(hidden)]
+pub type Time = Mtp;
+
+/// The median timestamp of 11 consecutive blocks, representing "the timestamp" of the
+/// final block for locktime-checking purposes.
 ///
-/// Note that there is no manipulation of the inner value during construction or when using
-/// `to_consensus_u32()`. Said another way, `Time(x)` means 'x seconds since epoch' _not_ '(x -
-/// threshold) seconds since epoch'.
+/// Time-based locktimes are not measured against the timestamps in individual block
+/// headers, since these are not monotone and may be subject to miner manipulation.
+/// Instead, locktimes use the "median-time-past" (MTP) of the most recent 11 blocks,
+/// a quantity which is required by consensus to be monotone and which is difficult
+/// for any individual miner to manipulate.
 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub struct Time(u32);
+pub struct Mtp(u32);
 
-impl Time {
-    /// The minimum absolute block time (Tue Nov 05 1985 00:53:20 GMT+0000).
-    pub const MIN: Self = Time(LOCK_TIME_THRESHOLD);
+impl Mtp {
+    /// The minimum MTP allowable in a locktime (Tue Nov 05 1985 00:53:20 GMT+0000).
+    pub const MIN: Self = Mtp(LOCK_TIME_THRESHOLD);
 
-    /// The maximum absolute block time (Sun Feb 07 2106 06:28:15 GMT+0000).
-    pub const MAX: Self = Time(u32::MAX);
+    /// The maximum MTP allowable in a locktime (Sun Feb 07 2106 06:28:15 GMT+0000).
+    pub const MAX: Self = Mtp(u32::MAX);
 
-    /// Constructs a new [`Time`] from a hex string.
+    /// Constructs a new [`Mtp`] from a big-endian hex-encoded `u32`.
     ///
     /// The input string may or may not contain a typical hex prefix e.g., `0x`.
     ///
     /// # Errors
     ///
     /// If the input string is not a valid hex representation of a block time.
-    pub fn from_hex(s: &str) -> Result<Self, ParseTimeError> { parse_hex(s, Self::from_consensus) }
+    pub fn from_hex(s: &str) -> Result<Self, ParseTimeError> { parse_hex(s, Self::from_u32) }
 
-    /// Constructs a new block time.
+    #[deprecated(since = "TBD", note = "use `from_u32` instead")]
+    #[doc(hidden)]
+    pub const fn from_consensus(n: u32) -> Result<Self, ConversionError> { Self::from_u32(n) }
+
+    #[deprecated(since = "TBD", note = "use `to_u32` instead")]
+    #[doc(hidden)]
+    pub const fn to_consensus_u32(self) -> u32 { self.to_u32() }
+
+    /// 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
+    /// **not** used to convert to or from a block timestamp, which is not a MTP.
     ///
     /// # Errors
     ///
-    /// If `n` does not encode a valid UNIX time stamp.
+    /// If `n` is not in the allowable range of MTPs in a locktime: `[500_000_000, 2^32 - 1]`.
     ///
     /// # Examples
     ///
     /// ```rust
-    /// use bitcoin_units::locktime::absolute::Time;
+    /// use bitcoin_units::locktime::absolute::Mtp;
     ///
     /// let t: u32 = 1653195600; // May 22nd, 5am UTC.
-    /// let time = Time::from_consensus(t).expect("invalid time value");
+    /// let time = Mtp::from_u32(t).expect("invalid time value");
     /// assert_eq!(time.to_consensus_u32(), t);
     /// ```
     #[inline]
-    pub const fn from_consensus(n: u32) -> Result<Time, ConversionError> {
+    pub const fn from_u32(n: u32) -> Result<Self, ConversionError> {
         if is_block_time(n) {
             Ok(Self(n))
         } else {
@@ -173,35 +198,35 @@ pub const fn from_consensus(n: u32) -> Result<Time, ConversionError> {
         }
     }
 
-    /// Converts this [`Time`] to its inner `u32` value.
+    /// Converts this [`Mtp`] to a raw `u32` value.
     #[inline]
-    pub const fn to_consensus_u32(self) -> u32 { self.0 }
+    pub const fn to_u32(self) -> u32 { self.0 }
 }
 
-impl fmt::Display for Time {
+impl fmt::Display for Mtp {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
 }
 
-crate::impl_parse_str!(Time, ParseTimeError, parser(Time::from_consensus));
+crate::impl_parse_str!(Mtp, ParseTimeError, parser(Mtp::from_u32));
 
 #[cfg(feature = "serde")]
-impl<'de> serde::Deserialize<'de> for Time {
+impl<'de> serde::Deserialize<'de> for Mtp {
     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
     where
         D: serde::Deserializer<'de>,
     {
         let u = u32::deserialize(deserializer)?;
-        Time::from_consensus(u).map_err(serde::de::Error::custom)
+        Mtp::from_u32(u).map_err(serde::de::Error::custom)
     }
 }
 
 #[cfg(feature = "serde")]
-impl serde::Serialize for Time {
+impl serde::Serialize for Mtp {
     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
     where
         S: serde::Serializer,
     {
-        self.to_consensus_u32().serialize(serializer)
+        self.to_u32().serialize(serializer)
     }
 }
 
@@ -342,11 +367,11 @@ fn display(
             E::ParseInt(ParseIntError { input, bits: _, is_signed: _, source })
                 if *source.kind() == IntErrorKind::PosOverflow =>
             {
-                // Outputs "failed to parse <input_string> as absolute Height/Time (<subject> is above limit <upper_bound>)"
+                // Outputs "failed to parse <input_string> as absolute Height/Mtp (<subject> is above limit <upper_bound>)"
                 write!(
                     f,
                     "{} ({} is above limit {})",
-                    input.display_cannot_parse("absolute Height/Time"),
+                    input.display_cannot_parse("absolute Height/Mtp"),
                     subject,
                     upper_bound
                 )
@@ -354,17 +379,17 @@ fn display(
             E::ParseInt(ParseIntError { input, bits: _, is_signed: _, source })
                 if *source.kind() == IntErrorKind::NegOverflow =>
             {
-                // Outputs "failed to parse <input_string> as absolute Height/Time (<subject> is below limit <lower_bound>)"
+                // Outputs "failed to parse <input_string> as absolute Height/Mtp (<subject> is below limit <lower_bound>)"
                 write!(
                     f,
                     "{} ({} is below limit {})",
-                    input.display_cannot_parse("absolute Height/Time"),
+                    input.display_cannot_parse("absolute Height/Mtp"),
                     subject,
                     lower_bound
                 )
             }
             E::ParseInt(ParseIntError { input, bits: _, is_signed: _, source: _ }) => {
-                write!(f, "{} ({})", input.display_cannot_parse("absolute Height/Time"), subject)
+                write!(f, "{} ({})", input.display_cannot_parse("absolute Height/Mtp"), subject)
             }
             E::Conversion(value) if *value < i64::from(lower_bound) => {
                 write!(f, "{} {} is below limit {}", subject, value, lower_bound)
@@ -407,27 +432,27 @@ fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
             0 => Ok(Height::MIN),
             1 => Ok(Height::MAX),
             _ => {
-                let min = Height::MIN.to_consensus_u32();
-                let max = Height::MAX.to_consensus_u32();
+                let min = Height::MIN.to_u32();
+                let max = Height::MAX.to_u32();
                 let h = u.int_in_range(min..=max)?;
-                Ok(Height::from_consensus(h).unwrap())
+                Ok(Height::from_u32(h).unwrap())
             }
         }
     }
 }
 
 #[cfg(feature = "arbitrary")]
-impl<'a> Arbitrary<'a> for Time {
+impl<'a> Arbitrary<'a> for Mtp {
     fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
         let choice = u.int_in_range(0..=2)?;
         match choice {
-            0 => Ok(Time::MIN),
-            1 => Ok(Time::MAX),
+            0 => Ok(Mtp::MIN),
+            1 => Ok(Mtp::MAX),
             _ => {
-                let min = Time::MIN.to_consensus_u32();
-                let max = Time::MAX.to_consensus_u32();
+                let min = Mtp::MIN.to_u32();
+                let max = Mtp::MAX.to_u32();
                 let t = u.int_in_range(min..=max)?;
-                Ok(Time::from_consensus(t).unwrap())
+                Ok(Mtp::from_u32(t).unwrap())
             }
         }
     }
@@ -442,21 +467,21 @@ mod tests {
 
     #[test]
     fn time_from_str_hex_happy_path() {
-        let actual = Time::from_hex("0x6289C350").unwrap();
-        let expected = Time::from_consensus(0x6289_C350).unwrap();
+        let actual = Mtp::from_hex("0x6289C350").unwrap();
+        let expected = Mtp::from_u32(0x6289_C350).unwrap();
         assert_eq!(actual, expected);
     }
 
     #[test]
     fn time_from_str_hex_no_prefix_happy_path() {
-        let time = Time::from_hex("6289C350").unwrap();
-        assert_eq!(time, Time(0x6289_C350));
+        let time = Mtp::from_hex("6289C350").unwrap();
+        assert_eq!(time, Mtp(0x6289_C350));
     }
 
     #[test]
     fn time_from_str_hex_invalid_hex_should_err() {
         let hex = "0xzb93";
-        let result = Time::from_hex(hex);
+        let result = Mtp::from_hex(hex);
         assert!(result.is_err());
     }
 
@@ -500,8 +525,8 @@ pub fn encode_decode_height() {
     #[test]
     #[cfg(feature = "serde")]
     pub fn encode_decode_time() {
-        serde_round_trip!(Time::MIN);
-        serde_round_trip!(Time::MAX);
+        serde_round_trip!(Mtp::MIN);
+        serde_round_trip!(Mtp::MAX);
     }
 
     #[test]
diff --git a/units/src/locktime/relative.rs b/units/src/locktime/relative.rs
index 5736e59e..47dde70a 100644
--- a/units/src/locktime/relative.rs
+++ b/units/src/locktime/relative.rs
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: CC0-1.0
 
-//! Provides [`Height`] and [`Time`] types used by the `rust-bitcoin` `relative::LockTime` type.
+//! Provides [`Height`] and [`MtpInterval`] types used by the `rust-bitcoin` `relative::LockTime` type.
 
 use core::fmt;
 
@@ -11,33 +11,47 @@
 
 use crate::mtp_height::MtpAndHeight;
 
+#[deprecated(since = "TBD", note = "use `HeightIterval` instead")]
+#[doc(hidden)]
+pub type Height = HeightInterval;
+
 /// A relative lock time lock-by-blockheight value.
 #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
-pub struct Height(u16);
+pub struct HeightInterval(u16);
 
-impl Height {
+impl HeightInterval {
     /// Relative block height 0, can be included in any block.
-    pub const ZERO: Self = Height(0);
+    pub const ZERO: Self = Self(0);
 
     /// The minimum relative block height (0), can be included in any block.
     pub const MIN: Self = Self::ZERO;
 
     /// The maximum relative block height.
-    pub const MAX: Self = Height(u16::MAX);
+    pub const MAX: Self = Self(u16::MAX);
 
-    /// Constructs a new [`Height`] using a count of blocks.
+    /// Constructs a new [`HeightInterval`] using a count of blocks.
     #[inline]
-    pub const fn from_height(blocks: u16) -> Self { Height(blocks) }
+    pub const fn from_height(blocks: u16) -> Self { Self(blocks) }
+
+    /// Express the [`Height`] as a count of blocks.
+    #[inline]
+    #[must_use]
+    pub const fn to_height(self) -> u16 { self.0 }
 
     /// Returns the inner `u16` value.
     #[inline]
     #[must_use]
+    #[deprecated(since = "TBD", note = "use `to_height` instead")]
+    #[doc(hidden)]
     pub const fn value(self) -> u16 { self.0 }
 
     /// Returns the `u32` value used to encode this locktime in an nSequence field or
     /// argument to `OP_CHECKSEQUENCEVERIFY`.
-    #[inline]
+    #[deprecated(
+        since = "TBD",
+        note = "use `LockTime::from` followed by `to_consensus_u32` instead"
+    )]
     pub const fn to_consensus_u32(self) -> u32 {
         self.0 as u32 // cast safety: u32 is wider than u16 on all architectures
     }
@@ -56,48 +70,57 @@ pub const fn to_consensus_u32(self) -> u32 {
     pub fn is_satisfied_by(self, chain_tip: MtpAndHeight, utxo_mined_at: MtpAndHeight) -> bool {
         // let chain_tip_height = BlockHeight::from(chain_tip);
         // let utxo_mined_at_height = BlockHeight::from(utxo_mined_at);
-        match self.to_consensus_u32().checked_add(utxo_mined_at.to_height().to_u32()) {
+        match u32::from(self.to_height()).checked_add(utxo_mined_at.to_height().to_u32()) {
             Some(target_height) => chain_tip.to_height().to_u32() >= target_height,
             None => false,
         }
     }
 }
 
-impl From<u16> for Height {
+impl From<u16> for HeightInterval {
     #[inline]
-    fn from(value: u16) -> Self { Height(value) }
+    fn from(value: u16) -> Self { HeightInterval(value) }
 }
 
-crate::impl_parse_str_from_int_infallible!(Height, u16, from);
+crate::impl_parse_str_from_int_infallible!(HeightInterval, u16, from);
 
-impl fmt::Display for Height {
+impl fmt::Display for HeightInterval {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
 }
 
+#[deprecated(since = "TBD", note = "use `Mtp` instead")]
+#[doc(hidden)]
+pub type Time = MtpInterval;
+
 /// A relative lock time lock-by-blocktime value.
 ///
 /// 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)]
 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
-pub struct Time(u16);
+pub struct MtpInterval(u16);
 
-impl Time {
+impl MtpInterval {
     /// Relative block time 0, can be included in any block.
-    pub const ZERO: Self = Time(0);
+    pub const ZERO: Self = MtpInterval(0);
 
     /// The minimum relative block time (0), can be included in any block.
-    pub const MIN: Self = Time::ZERO;
+    pub const MIN: Self = MtpInterval::ZERO;
 
     /// The maximum relative block time (33,554,432 seconds or approx 388 days).
-    pub const MAX: Self = Time(u16::MAX);
+    pub const MAX: Self = MtpInterval(u16::MAX);
 
-    /// Constructs a new [`Time`] using time intervals where each interval is equivalent to 512 seconds.
+    /// Constructs a new [`MtpInterval`] 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.
     #[inline]
-    pub const fn from_512_second_intervals(intervals: u16) -> Self { Time(intervals) }
+    pub const fn from_512_second_intervals(intervals: u16) -> Self { MtpInterval(intervals) }
 
-    /// Constructs a new [`Time`] from seconds, converting the seconds into 512 second interval with
+    /// Express the [`MtpInterval`] as an integer number of 512-second intervals.
+    #[inline]
+    #[must_use]
+    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
     /// truncating division.
     ///
     /// # Errors
@@ -108,13 +131,13 @@ pub const fn from_512_second_intervals(intervals: u16) -> Self { Time(intervals)
     pub const fn from_seconds_floor(seconds: u32) -> Result<Self, TimeOverflowError> {
         let interval = seconds / 512;
         if interval <= u16::MAX as u32 { // infallible cast, needed by const code
-            Ok(Time::from_512_second_intervals(interval as u16)) // Cast checked above, needed by const code.
+            Ok(MtpInterval::from_512_second_intervals(interval as u16)) // Cast checked above, needed by const code.
         } else {
             Err(TimeOverflowError { seconds })
         }
     }
 
-    /// Constructs a new [`Time`] from seconds, converting the seconds into 512 second intervals with
+    /// Constructs a new [`MtpInterval`] from seconds, converting the seconds into 512 second intervals with
     /// ceiling division.
     ///
     /// # Errors
@@ -125,7 +148,7 @@ pub const fn from_seconds_floor(seconds: u32) -> Result<Self, TimeOverflowError>
     pub const fn from_seconds_ceil(seconds: u32) -> Result<Self, TimeOverflowError> {
         if seconds <= u16::MAX as u32 * 512 {
             let interval = (seconds + 511) / 512;
-            Ok(Time::from_512_second_intervals(interval as u16)) // Cast checked above, needed by const code.
+            Ok(MtpInterval::from_512_second_intervals(interval as u16)) // Cast checked above, needed by const code.
         } else {
             Err(TimeOverflowError { seconds })
         }
@@ -134,11 +157,16 @@ pub const fn from_seconds_ceil(seconds: u32) -> Result<Self, TimeOverflowError>
     /// Returns the inner `u16` value.
     #[inline]
     #[must_use]
+    #[deprecated(since = "TBD", note = "use `to_512_second_intervals` instead")]
+    #[doc(hidden)]
     pub const fn value(self) -> u16 { self.0 }
 
     /// Returns the `u32` value used to encode this locktime in an nSequence field or
     /// argument to `OP_CHECKSEQUENCEVERIFY`.
-    #[inline]
+    #[deprecated(
+        since = "TBD",
+        note = "use `LockTime::from` followed by `to_consensus_u32` instead"
+    )]
     pub const fn to_consensus_u32(self) -> u32 {
         (1u32 << 22) | self.0 as u32 // cast safety: u32 is wider than u16 on all architectures
     }
@@ -155,7 +183,7 @@ pub const fn to_consensus_u32(self) -> u32 {
     /// - `true` if the relative‐time lock has expired by the tip’s MTP
     /// - `false` if the lock has not yet expired by the tip’s MTP
     pub fn is_satisfied_by(self, chain_tip: MtpAndHeight, utxo_mined_at: MtpAndHeight) -> bool {
-        match u32::from(self.value()).checked_mul(512) {
+        match u32::from(self.to_512_second_intervals()).checked_mul(512) {
             Some(seconds) => match seconds.checked_add(utxo_mined_at.to_mtp().to_u32()) {
                 Some(required_seconds) => chain_tip.to_mtp().to_u32() >= required_seconds,
                 None => false,
@@ -165,16 +193,16 @@ pub fn is_satisfied_by(self, chain_tip: MtpAndHeight, utxo_mined_at: MtpAndHeigh
     }
 }
 
-crate::impl_parse_str_from_int_infallible!(Time, u16, from_512_second_intervals);
+crate::impl_parse_str_from_int_infallible!(MtpInterval, u16, from_512_second_intervals);
 
-impl fmt::Display for Time {
+impl fmt::Display for MtpInterval {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
 }
 
 /// Error returned when the input time in seconds was too large to be encoded to a 16 bit 512 second interval.
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub struct TimeOverflowError {
-    /// Time value in seconds that overflowed.
+    /// Time interval value in seconds that overflowed.
     // Private because we maintain an invariant that the `seconds` value does actually overflow.
     pub(crate) seconds: u32,
 }
@@ -205,27 +233,27 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 impl std::error::Error for TimeOverflowError {}
 
 #[cfg(feature = "arbitrary")]
-impl<'a> Arbitrary<'a> for Height {
+impl<'a> Arbitrary<'a> for HeightInterval {
     fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
         let choice = u.int_in_range(0..=2)?;
 
         match choice {
-            0 => Ok(Height::MIN),
-            1 => Ok(Height::MAX),
-            _ => Ok(Height::from_height(u16::arbitrary(u)?)),
+            0 => Ok(HeightInterval::MIN),
+            1 => Ok(HeightInterval::MAX),
+            _ => Ok(HeightInterval::from_height(u16::arbitrary(u)?)),
         }
     }
 }
 
 #[cfg(feature = "arbitrary")]
-impl<'a> Arbitrary<'a> for Time {
+impl<'a> Arbitrary<'a> for MtpInterval {
     fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
         let choice = u.int_in_range(0..=2)?;
 
         match choice {
-            0 => Ok(Time::MIN),
-            1 => Ok(Time::MAX),
-            _ => Ok(Time::from_512_second_intervals(u16::arbitrary(u)?)),
+            0 => Ok(MtpInterval::MIN),
+            1 => Ok(MtpInterval::MAX),
+            _ => Ok(MtpInterval::from_512_second_intervals(u16::arbitrary(u)?)),
         }
     }
 }
@@ -241,73 +269,74 @@ mod tests {
     const MAXIMUM_ENCODABLE_SECONDS: u32 = u16::MAX as u32 * 512;
 
     #[test]
+    #[allow(deprecated_in_future)]
     fn sanity_check() {
-        assert_eq!(Height::MAX.to_consensus_u32(), u32::from(u16::MAX));
-        assert_eq!(Time::from_512_second_intervals(100).value(), 100u16);
-        assert_eq!(Time::from_512_second_intervals(100).to_consensus_u32(), 4_194_404u32); // 0x400064
+        assert_eq!(HeightInterval::MAX.to_consensus_u32(), u32::from(u16::MAX));
+        assert_eq!(MtpInterval::from_512_second_intervals(100).value(), 100u16);
+        assert_eq!(MtpInterval::from_512_second_intervals(100).to_consensus_u32(), 4_194_404u32); // 0x400064
     }
 
     #[test]
     fn from_seconds_ceil_success() {
-        let actual = Time::from_seconds_ceil(100).unwrap();
-        let expected = Time(1_u16);
+        let actual = MtpInterval::from_seconds_ceil(100).unwrap();
+        let expected = MtpInterval(1_u16);
         assert_eq!(actual, expected);
     }
 
     #[test]
     fn from_seconds_ceil_with_maximum_encodable_seconds_success() {
-        let actual = Time::from_seconds_ceil(MAXIMUM_ENCODABLE_SECONDS).unwrap();
-        let expected = Time(u16::MAX);
+        let actual = MtpInterval::from_seconds_ceil(MAXIMUM_ENCODABLE_SECONDS).unwrap();
+        let expected = MtpInterval(u16::MAX);
         assert_eq!(actual, expected);
     }
 
     #[test]
     fn from_seconds_ceil_causes_time_overflow_error() {
-        let result = Time::from_seconds_ceil(MAXIMUM_ENCODABLE_SECONDS + 1);
+        let result = MtpInterval::from_seconds_ceil(MAXIMUM_ENCODABLE_SECONDS + 1);
         assert!(result.is_err());
     }
 
     #[test]
     fn from_seconds_floor_success() {
-        let actual = Time::from_seconds_floor(100).unwrap();
-        let expected = Time(0_u16);
+        let actual = MtpInterval::from_seconds_floor(100).unwrap();
+        let expected = MtpInterval(0_u16);
         assert_eq!(actual, expected);
     }
 
     #[test]
     fn from_seconds_floor_with_exact_interval() {
-        let actual = Time::from_seconds_floor(512).unwrap();
-        let expected = Time(1_u16);
+        let actual = MtpInterval::from_seconds_floor(512).unwrap();
+        let expected = MtpInterval(1_u16);
         assert_eq!(actual, expected);
     }
 
     #[test]
     fn from_seconds_floor_with_maximum_encodable_seconds_success() {
-        let actual = Time::from_seconds_floor(MAXIMUM_ENCODABLE_SECONDS + 511).unwrap();
-        let expected = Time(u16::MAX);
+        let actual = MtpInterval::from_seconds_floor(MAXIMUM_ENCODABLE_SECONDS + 511).unwrap();
+        let expected = MtpInterval(u16::MAX);
         assert_eq!(actual, expected);
     }
 
     #[test]
     fn from_seconds_floor_causes_time_overflow_error() {
-        let result = Time::from_seconds_floor(MAXIMUM_ENCODABLE_SECONDS + 512);
+        let result = MtpInterval::from_seconds_floor(MAXIMUM_ENCODABLE_SECONDS + 512);
         assert!(result.is_err());
     }
 
     #[test]
     #[cfg(feature = "serde")]
     pub fn encode_decode_height() {
-        serde_round_trip!(Height::ZERO);
-        serde_round_trip!(Height::MIN);
-        serde_round_trip!(Height::MAX);
+        serde_round_trip!(HeightInterval::ZERO);
+        serde_round_trip!(HeightInterval::MIN);
+        serde_round_trip!(HeightInterval::MAX);
     }
 
     #[test]
     #[cfg(feature = "serde")]
     pub fn encode_decode_time() {
-        serde_round_trip!(Time::ZERO);
-        serde_round_trip!(Time::MIN);
-        serde_round_trip!(Time::MAX);
+        serde_round_trip!(MtpInterval::ZERO);
+        serde_round_trip!(MtpInterval::MIN);
+        serde_round_trip!(MtpInterval::MAX);
     }
 
     fn generate_timestamps(start: u32, step: u16) -> [BlockTime; 11] {
@@ -331,7 +360,7 @@ fn test_time_chain_state() {
 
         // Test case 1: Satisfaction (current_mtp >= utxo_mtp + required_seconds)
         // 10 intervals × 512 seconds = 5120 seconds
-        let time_lock = Time::from_512_second_intervals(10);
+        let time_lock = MtpInterval::from_512_second_intervals(10);
         let chain_state1 = MtpAndHeight::new(BlockHeight::from_u32(100), timestamps);
         let utxo_state1 = MtpAndHeight::new(BlockHeight::from_u32(80), utxo_timestamps);
         assert!(time_lock.is_satisfied_by(chain_state1, utxo_state1));
@@ -342,13 +371,13 @@ fn test_time_chain_state() {
         assert!(!time_lock.is_satisfied_by(chain_state2, utxo_state2));
 
         // Test case 3: Test with a larger value (100 intervals = 51200 seconds)
-        let larger_lock = Time::from_512_second_intervals(100);
+        let larger_lock = MtpInterval::from_512_second_intervals(100);
         let chain_state3 = MtpAndHeight::new(BlockHeight::from_u32(100), timestamps3);
         let utxo_state3 = MtpAndHeight::new(BlockHeight::from_u32(80), utxo_timestamps3);
         assert!(larger_lock.is_satisfied_by(chain_state3, utxo_state3));
 
         // Test case 4: Overflow handling - tests that is_satisfied_by handles overflow gracefully
-        let max_time_lock = Time::MAX;
+        let max_time_lock = MtpInterval::MAX;
         let chain_state4 = MtpAndHeight::new(BlockHeight::from_u32(100), timestamps);
         let utxo_state4 = MtpAndHeight::new(BlockHeight::from_u32(80), utxo_timestamps);
         assert!(!max_time_lock.is_satisfied_by(chain_state4, utxo_state4));
@@ -359,7 +388,7 @@ fn test_height_chain_state() {
         let timestamps: [BlockTime; 11] = generate_timestamps(1_600_000_000, 200);
         let utxo_timestamps: [BlockTime; 11] = generate_timestamps(1_599_000_000, 200);
 
-        let height_lock = Height(10);
+        let height_lock = HeightInterval(10);
 
         // Test case 1: Satisfaction (current_height >= utxo_height + required)
         let chain_state1 = MtpAndHeight::new(BlockHeight::from_u32(100), timestamps);
@@ -372,7 +401,7 @@ fn test_height_chain_state() {
         assert!(!height_lock.is_satisfied_by(chain_state2, utxo_state2));
 
         // Test case 3: Overflow handling - tests that is_satisfied_by handles overflow gracefully
-        let max_height_lock = Height::MAX;
+        let max_height_lock = HeightInterval::MAX;
         let chain_state3 = MtpAndHeight::new(BlockHeight::from_u32(1000), timestamps);
         let utxo_state3 = MtpAndHeight::new(BlockHeight::from_u32(80), utxo_timestamps);
         assert!(!max_height_lock.is_satisfied_by(chain_state3, utxo_state3));


Test patch:
diff --git a/units/tests/api.rs b/units/tests/api.rs
index 46a16e42..41b39bb4 100644
--- a/units/tests/api.rs
+++ b/units/tests/api.rs
@@ -38,7 +38,7 @@ struct Structs {
     e: BlockInterval,
     f: FeeRate,
     g: absolute::Height,
-    h: absolute::Time,
+    h: absolute::Mtp,
     i: relative::Height,
     j: relative::Time,
     k: Weight,
@@ -55,7 +55,7 @@ fn max() -> Self {
             e: BlockInterval::MAX,
             f: FeeRate::MAX,
             g: absolute::Height::MAX,
-            h: absolute::Time::MAX,
+            h: absolute::Mtp::MAX,
             i: relative::Height::MAX,
             j: relative::Time::MAX,
             k: Weight::MAX,
@@ -85,7 +85,7 @@ struct CommonTraits {
     e: BlockInterval,
     f: FeeRate,
     g: absolute::Height,
-    h: absolute::Time,
+    h: absolute::Mtp,
     i: relative::Height,
     j: relative::Time,
     k: Weight,
@@ -128,7 +128,7 @@ struct Errors {
     t: amount::PossiblyConfusingDenominationError,
     u: amount::TooPreciseError,
     v: amount::UnknownDenominationError,
-    w: block::TooBigForRelativeBlockHeightError,
+    w: block::TooBigForRelativeBlockHeightIntervalError,
     x: locktime::absolute::ConversionError,
     y: locktime::absolute::Height,
     z: locktime::absolute::ParseHeightError,
@@ -163,7 +163,9 @@ fn api_can_use_all_types_from_module_amount() {
 
 #[test]
 fn api_can_use_all_types_from_module_block() {
-    use bitcoin_units::block::{BlockHeight, BlockInterval, TooBigForRelativeBlockHeightError};
+    use bitcoin_units::block::{
+        BlockHeight, BlockInterval, TooBigForRelativeBlockHeightIntervalError,
+    };
 }
 
 #[test]
@@ -174,7 +176,7 @@ fn api_can_use_all_types_from_module_fee_rate() {
 #[test]
 fn api_can_use_all_types_from_module_locktime_absolute() {
     use bitcoin_units::locktime::absolute::{
-        ConversionError, Height, ParseHeightError, ParseTimeError, Time,
+        ConversionError, Height, Mtp, ParseHeightError, ParseTimeError,
     };
 }
 
@@ -291,7 +293,7 @@ fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
             e: BlockInterval::arbitrary(u)?,
             f: FeeRate::arbitrary(u)?,
             g: absolute::Height::arbitrary(u)?,
-            h: absolute::Time::arbitrary(u)?,
+            h: absolute::Mtp::arbitrary(u)?,
             i: relative::Height::arbitrary(u)?,
             j: relative::Time::arbitrary(u)?,
             k: Weight::arbitrary(u)?,
diff --git a/units/tests/serde.rs b/units/tests/serde.rs
index d807bcc7..24cf9b04 100644
--- a/units/tests/serde.rs
+++ b/units/tests/serde.rs
@@ -47,7 +47,7 @@ struct Serde {
     a: BlockHeight,
     b: BlockInterval,
     c: absolute::Height,
-    d: absolute::Time,
+    d: absolute::Mtp,
     e: relative::Height,
     f: relative::Time,
     g: Weight,
@@ -80,7 +80,7 @@ fn new() -> Self {
             a: BlockHeight::MAX,
             b: BlockInterval::MAX,
             c: absolute::Height::MAX,
-            d: absolute::Time::MAX,
+            d: absolute::Mtp::MAX,
             e: relative::Height::MAX,
             f: relative::Time::MAX,
             g: Weight::MAX,