Improve relative::LockTime is_satisfied_by_{height, time}
We recently improved the relative locktime function `is_satisfied_by` by adding mined at and chain tip. We can now do the same for the height/time satisfaction functions. Note I believe these functions should still be provided because a user may for some reason have either blocktime data or height data and not have the other. Requires some work to the errors, elect to just remove the original field that held the function argument. For now remove the examples in rustdocs, we can circle back to these once the dust settles.
This commit is contained in:
parent
e43c574146
commit
a2ff8ddbbb
|
@ -332,61 +332,41 @@ impl LockTime {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if this [`relative::LockTime`] is satisfied by [`NumberOfBlocks`].
|
/// Returns true if an output with this locktime can be spent in the next block.
|
||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// Returns an error if this lock is not lock-by-height.
|
/// Returns an error if this lock is not lock-by-height.
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # use bitcoin_primitives::Sequence;
|
|
||||||
/// # use bitcoin_primitives::relative;
|
|
||||||
///
|
|
||||||
/// 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::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: NumberOfBlocks,
|
chain_tip: BlockHeight,
|
||||||
|
utxo_mined_at: BlockHeight,
|
||||||
) -> Result<bool, IncompatibleHeightError> {
|
) -> Result<bool, IncompatibleHeightError> {
|
||||||
use LockTime as L;
|
use LockTime as L;
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
L::Blocks(required_height) => Ok(required_height <= height),
|
L::Blocks(blocks) => Ok(blocks.is_satisfied_by(chain_tip, utxo_mined_at)),
|
||||||
L::Time(time) => Err(IncompatibleHeightError { height, time }),
|
L::Time(time) => Err(IncompatibleHeightError { time }),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if this [`relative::LockTime`] is satisfied by [`Time`].
|
/// Returns true if an output with this locktime can be spent in the next block.
|
||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// Returns an error if this lock is not lock-by-time.
|
/// Returns an error if this lock is not lock-by-time.
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # use bitcoin_primitives::Sequence;
|
|
||||||
/// # use bitcoin_primitives::relative;
|
|
||||||
///
|
|
||||||
/// let intervals: u16 = 70; // approx 10 hours;
|
|
||||||
/// let lock = Sequence::from_512_second_intervals(intervals).to_relative_lock_time().expect("valid 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(
|
pub fn is_satisfied_by_time(
|
||||||
self,
|
self,
|
||||||
time: NumberOf512Seconds,
|
chain_tip: BlockMtp,
|
||||||
|
utxo_mined_at: BlockMtp,
|
||||||
) -> Result<bool, IncompatibleTimeError> {
|
) -> Result<bool, IncompatibleTimeError> {
|
||||||
use LockTime as L;
|
use LockTime as L;
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
L::Time(ref t) => Ok(t.to_512_second_intervals() <= time.to_512_second_intervals()),
|
L::Time(time) => Ok(time.is_satisfied_by(chain_tip, utxo_mined_at)),
|
||||||
L::Blocks(height) => Err(IncompatibleTimeError { time, height }),
|
L::Blocks(blocks) => Err(IncompatibleTimeError { blocks }),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -457,16 +437,11 @@ impl std::error::Error for DisabledLockTimeError {}
|
||||||
/// Tried to satisfy a lock-by-blocktime lock using a height value.
|
/// Tried to satisfy a lock-by-blocktime lock using a height value.
|
||||||
#[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.
|
|
||||||
height: NumberOfBlocks,
|
|
||||||
/// The inner time value of the lock-by-blocktime lock.
|
/// The inner time value of the lock-by-blocktime lock.
|
||||||
time: NumberOf512Seconds,
|
time: NumberOf512Seconds,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IncompatibleHeightError {
|
impl IncompatibleHeightError {
|
||||||
/// Returns the height that was erroneously used to try and satisfy a lock-by-blocktime lock.
|
|
||||||
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) -> NumberOf512Seconds { self.time }
|
pub fn expected(&self) -> NumberOf512Seconds { self.time }
|
||||||
}
|
}
|
||||||
|
@ -474,11 +449,7 @@ impl IncompatibleHeightError {
|
||||||
impl fmt::Display for IncompatibleHeightError {
|
impl fmt::Display for IncompatibleHeightError {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(
|
write!(f, "tried to satisfy a lock-by-blocktime lock {} by height", self.time,)
|
||||||
f,
|
|
||||||
"tried to satisfy a lock-by-blocktime lock {} with height: {}",
|
|
||||||
self.time, self.height
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -488,28 +459,19 @@ impl std::error::Error for IncompatibleHeightError {}
|
||||||
/// Tried to satisfy a lock-by-blockheight lock using a time value.
|
/// Tried to satisfy a lock-by-blockheight lock using a time value.
|
||||||
#[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.
|
/// The inner value of the lock-by-blockheight lock.
|
||||||
time: NumberOf512Seconds,
|
blocks: NumberOfBlocks,
|
||||||
/// The inner height value of the lock-by-blockheight lock.
|
|
||||||
height: NumberOfBlocks,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IncompatibleTimeError {
|
impl IncompatibleTimeError {
|
||||||
/// Returns the time that was erroneously used to try and satisfy a lock-by-blockheight lock.
|
|
||||||
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) -> NumberOfBlocks { self.height }
|
pub fn expected(&self) -> NumberOfBlocks { self.blocks }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for IncompatibleTimeError {
|
impl fmt::Display for IncompatibleTimeError {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(
|
write!(f, "tried to satisfy a lock-by-blockheight lock {} by time", self.blocks,)
|
||||||
f,
|
|
||||||
"tried to satisfy a lock-by-blockheight lock {} with time: {}",
|
|
||||||
self.height, self.time
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -664,25 +626,29 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn incompatible_height_error() {
|
fn incompatible_height_error() {
|
||||||
let height = NumberOfBlocks::from(10);
|
// This is an error test these values are not used in the error path.
|
||||||
let time = NumberOf512Seconds::from_512_second_intervals(70);
|
let mined_at = BlockHeight::from_u32(700_000);
|
||||||
let lock_by_time = LockTime::from(time);
|
let chain_tip = BlockHeight::from_u32(800_000);
|
||||||
let err = lock_by_time.is_satisfied_by_height(height).unwrap_err();
|
|
||||||
|
|
||||||
assert_eq!(err.incompatible(), height);
|
let lock_by_time = LockTime::from_512_second_intervals(70); // Arbitrary value.
|
||||||
assert_eq!(err.expected(), time);
|
let err = lock_by_time.is_satisfied_by_height(chain_tip, mined_at).unwrap_err();
|
||||||
|
|
||||||
|
let expected_time = NumberOf512Seconds::from_512_second_intervals(70);
|
||||||
|
assert_eq!(err.expected(), expected_time);
|
||||||
assert!(!format!("{}", err).is_empty());
|
assert!(!format!("{}", err).is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn incompatible_time_error() {
|
fn incompatible_time_error() {
|
||||||
let height = NumberOfBlocks::from(10);
|
// This is an error test these values are not used in the error path.
|
||||||
let time = NumberOf512Seconds::from_512_second_intervals(70);
|
let mined_at = BlockMtp::from_u32(1_234_567_890);
|
||||||
let lock_by_height = LockTime::from(height);
|
let chain_tip = BlockMtp::from_u32(1_600_000_000);
|
||||||
let err = lock_by_height.is_satisfied_by_time(time).unwrap_err();
|
|
||||||
|
|
||||||
assert_eq!(err.incompatible(), time);
|
let lock_by_height = LockTime::from_height(10); // Arbitrary value.
|
||||||
assert_eq!(err.expected(), height);
|
let err = lock_by_height.is_satisfied_by_time(chain_tip, mined_at).unwrap_err();
|
||||||
|
|
||||||
|
let expected_height = NumberOfBlocks::from(10);
|
||||||
|
assert_eq!(err.expected(), expected_height);
|
||||||
assert!(!format!("{}", err).is_empty());
|
assert!(!format!("{}", err).is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue