units: stop using MtpAndHeight in locktime::relative is_satisfied_by methods

Keep using it in primitives; will remove it there in the next commit.
This commit is contained in:
Andrew Poelstra 2025-05-05 19:58:58 +00:00
parent d933c754f5
commit 72d5fbad73
No known key found for this signature in database
GPG Key ID: C588D63CE41B97C1
2 changed files with 52 additions and 42 deletions

View File

@ -255,8 +255,10 @@ impl LockTime {
/// ``` /// ```
pub fn is_satisfied_by(self, chain_tip: MtpAndHeight, utxo_mined_at: MtpAndHeight) -> bool { pub fn is_satisfied_by(self, chain_tip: MtpAndHeight, utxo_mined_at: MtpAndHeight) -> bool {
match self { match self {
LockTime::Blocks(blocks) => blocks.is_satisfied_by(chain_tip, utxo_mined_at), LockTime::Blocks(blocks) =>
LockTime::Time(time) => time.is_satisfied_by(chain_tip, utxo_mined_at), blocks.is_satisfied_by(chain_tip.to_height(), utxo_mined_at.to_height()),
LockTime::Time(time) =>
time.is_satisfied_by(chain_tip.to_mtp(), utxo_mined_at.to_mtp()),
} }
} }

View File

@ -9,8 +9,6 @@ use arbitrary::{Arbitrary, Unstructured};
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::mtp_height::MtpAndHeight;
#[deprecated(since = "TBD", note = "use `HeightIterval` instead")] #[deprecated(since = "TBD", note = "use `HeightIterval` instead")]
#[doc(hidden)] #[doc(hidden)]
pub type Height = HeightInterval; pub type Height = HeightInterval;
@ -59,21 +57,26 @@ impl HeightInterval {
/// Determines whether a relativeheight locktime has matured, taking into account /// Determines whether a relativeheight locktime has matured, taking into account
/// both the chain tip and the height at which the UTXO was confirmed. /// both the chain tip and the height at which the UTXO was confirmed.
/// ///
/// If you have two height intervals `x` and `y`, and want to know whether `x`
/// is satisfied by `y`, use `x >= y`.
///
/// # Parameters /// # Parameters
/// - `self` The relative blockheight delay (`h`) required after confirmation. /// - `self` the relative blockheight delay (`h`) required after confirmation.
/// - `chain_tip` The current chain state (contains the tip height). /// - `chain_tip` the height of the current chain tip
/// - `utxo_mined_at` The chain state at the UTXOs confirmation block (contains that height). /// - `utxo_mined_at` the height of the UTXOs confirmation block
/// ///
/// # Returns /// # Returns
/// - `true` if a UTXO locked by `self` can be spent in a block after `chain_tip`. /// - `true` if a UTXO locked by `self` can be spent in a block after `chain_tip`.
/// - `false` if the UTXO is still locked at `chain_tip`. /// - `false` if the UTXO is still locked at `chain_tip`.
pub fn is_satisfied_by(self, chain_tip: MtpAndHeight, utxo_mined_at: MtpAndHeight) -> bool { pub fn is_satisfied_by(
// let chain_tip_height = BlockHeight::from(chain_tip); self,
// let utxo_mined_at_height = BlockHeight::from(utxo_mined_at); chain_tip: crate::BlockHeight,
match u32::from(self.to_height()).checked_add(utxo_mined_at.to_height().to_u32()) { utxo_mined_at: crate::BlockHeight,
Some(target_height) => chain_tip.to_height().to_u32() >= target_height, ) -> bool {
None => false, chain_tip
} .checked_sub(utxo_mined_at)
.and_then(|diff: crate::BlockHeightInterval| diff.try_into().ok())
.map_or(false, |diff: Self| diff >= self)
} }
} }
@ -180,22 +183,26 @@ impl MtpInterval {
/// Determines whether a relativetime lock has matured, taking into account both /// Determines whether a relativetime lock has matured, taking into account both
/// the UTXOs Median Time Past at confirmation and the required delay. /// the UTXOs Median Time Past at confirmation and the required delay.
/// ///
/// If you have two MTP intervals `x` and `y`, and want to know whether `x`
/// is satisfied by `y`, use `x >= y`.
///
/// # Parameters /// # Parameters
/// - `self` The relative time delay (`t`) in 512second intervals. /// - `self` the relative time delay (`t`) in 512second intervals.
/// - `chain_tip` The current chain state, providing the tips MTP. /// - `chain_tip` the MTP of the current chain tip
/// - `utxo_mined_at` The chain state at the UTXOs confirmation, providing its MTP. /// - `utxo_mined_at` the MTP of the UTXOs confirmation block
/// ///
/// # Returns /// # Returns
/// - `true` if the relativetime lock has expired by the tips MTP /// - `true` if the relativetime lock has expired by the tips MTP
/// - `false` if the lock has not yet expired by the tips MTP /// - `false` if the lock has not yet expired by the tips MTP
pub fn is_satisfied_by(self, chain_tip: MtpAndHeight, utxo_mined_at: MtpAndHeight) -> bool { pub fn is_satisfied_by(
match u32::from(self.to_512_second_intervals()).checked_mul(512) { self,
Some(seconds) => match seconds.checked_add(utxo_mined_at.to_mtp().to_u32()) { chain_tip: crate::BlockMtp,
Some(required_seconds) => chain_tip.to_mtp().to_u32() >= required_seconds, utxo_mined_at: crate::BlockMtp,
None => false, ) -> bool {
}, chain_tip
None => false, .checked_sub(utxo_mined_at)
} .and_then(|diff: crate::BlockMtpInterval| diff.to_relative_mtp_interval_floor().ok())
.map_or(false, |diff: Self| diff >= self)
} }
} }
@ -270,7 +277,7 @@ mod tests {
use internals::serde_round_trip; use internals::serde_round_trip;
use super::*; use super::*;
use crate::{BlockHeight, BlockTime}; use crate::BlockTime;
const MAXIMUM_ENCODABLE_SECONDS: u32 = u16::MAX as u32 * 512; const MAXIMUM_ENCODABLE_SECONDS: u32 = u16::MAX as u32 * 512;
@ -355,6 +362,8 @@ mod tests {
#[test] #[test]
fn test_time_chain_state() { fn test_time_chain_state() {
use crate::BlockMtp;
let timestamps: [BlockTime; 11] = generate_timestamps(1_600_000_000, 200); let timestamps: [BlockTime; 11] = generate_timestamps(1_600_000_000, 200);
let utxo_timestamps: [BlockTime; 11] = generate_timestamps(1_599_000_000, 200); let utxo_timestamps: [BlockTime; 11] = generate_timestamps(1_599_000_000, 200);
@ -367,49 +376,48 @@ 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 = MtpInterval::from_512_second_intervals(10);
let chain_state1 = MtpAndHeight::new(BlockHeight::from_u32(100), timestamps); let chain_state1 = BlockMtp::new(timestamps);
let utxo_state1 = MtpAndHeight::new(BlockHeight::from_u32(80), 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));
// Test case 2: Not satisfied (current_mtp < utxo_mtp + required_seconds) // Test case 2: Not satisfied (current_mtp < utxo_mtp + required_seconds)
let chain_state2 = MtpAndHeight::new(BlockHeight::from_u32(100), timestamps2); let chain_state2 = BlockMtp::new(timestamps2);
let utxo_state2 = MtpAndHeight::new(BlockHeight::from_u32(80), utxo_timestamps2); let utxo_state2 = BlockMtp::new(utxo_timestamps2);
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 = MtpInterval::from_512_second_intervals(100);
let chain_state3 = MtpAndHeight::new(BlockHeight::from_u32(100), timestamps3); let chain_state3 = BlockMtp::new(timestamps3);
let utxo_state3 = MtpAndHeight::new(BlockHeight::from_u32(80), 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 = MtpInterval::MAX;
let chain_state4 = MtpAndHeight::new(BlockHeight::from_u32(100), timestamps); let chain_state4 = BlockMtp::new(timestamps);
let utxo_state4 = MtpAndHeight::new(BlockHeight::from_u32(80), 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));
} }
#[test] #[test]
fn test_height_chain_state() { fn test_height_chain_state() {
let timestamps: [BlockTime; 11] = generate_timestamps(1_600_000_000, 200); use crate::BlockHeight;
let utxo_timestamps: [BlockTime; 11] = generate_timestamps(1_599_000_000, 200);
let height_lock = HeightInterval(10); let height_lock = HeightInterval(10);
// Test case 1: Satisfaction (current_height >= utxo_height + required) // Test case 1: Satisfaction (current_height >= utxo_height + required)
let chain_state1 = MtpAndHeight::new(BlockHeight::from_u32(100), timestamps); let chain_state1 = BlockHeight::from_u32(100);
let utxo_state1 = MtpAndHeight::new(BlockHeight::from_u32(80), utxo_timestamps); let utxo_state1 = BlockHeight::from_u32(80);
assert!(height_lock.is_satisfied_by(chain_state1, utxo_state1)); assert!(height_lock.is_satisfied_by(chain_state1, utxo_state1));
// Test case 2: Not satisfied (current_height < utxo_height + required) // Test case 2: Not satisfied (current_height < utxo_height + required)
let chain_state2 = MtpAndHeight::new(BlockHeight::from_u32(89), timestamps); let chain_state2 = BlockHeight::from_u32(89);
let utxo_state2 = MtpAndHeight::new(BlockHeight::from_u32(80), utxo_timestamps); let utxo_state2 = BlockHeight::from_u32(80);
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 = HeightInterval::MAX;
let chain_state3 = MtpAndHeight::new(BlockHeight::from_u32(1000), timestamps); let chain_state3 = BlockHeight::from_u32(1000);
let utxo_state3 = MtpAndHeight::new(BlockHeight::from_u32(80), utxo_timestamps); 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));
} }
} }