Split relative locktime error up

The `relative` module has a single general error type, we are moving
away from this style to specific error types.

Split the `relative::Error` up into three error structs.

Note the change of parameter `h` to `height`, and using `h` as the
pattern matched variable - this makes sense because it gives the
variable with large scope the longer name.
This commit is contained in:
Tobin C. Harding 2024-02-02 14:49:25 +11:00
parent f69417f8bc
commit 3c8edae25b
No known key found for this signature in database
GPG Key ID: 40BF9E4C269D6607
2 changed files with 56 additions and 44 deletions

View File

@ -123,12 +123,12 @@ impl LockTime {
/// ``` /// ```
#[inline] #[inline]
#[cfg_attr(all(test, mutate), mutate)] #[cfg_attr(all(test, mutate), mutate)]
pub fn is_satisfied_by_height(&self, h: Height) -> Result<bool, Error> { pub fn is_satisfied_by_height(&self, height: Height) -> Result<bool, IncompatibleHeightError> {
use LockTime::*; use LockTime::*;
match *self { match *self {
Blocks(ref height) => Ok(height.value() <= h.value()), Blocks(ref h) => Ok(h.value() <= height.value()),
Time(ref time) => Err(Error::IncompatibleTime(*self, *time)), Time(time) => Err(IncompatibleHeightError { height, time })
} }
} }
@ -150,12 +150,12 @@ impl LockTime {
/// ``` /// ```
#[inline] #[inline]
#[cfg_attr(all(test, mutate), mutate)] #[cfg_attr(all(test, mutate), mutate)]
pub fn is_satisfied_by_time(&self, t: Time) -> Result<bool, Error> { pub fn is_satisfied_by_time(&self, time: Time) -> Result<bool, IncompatibleTimeError> {
use LockTime::*; use LockTime::*;
match *self { match *self {
Time(ref time) => Ok(time.value() <= t.value()), Time(ref t) => Ok(t.value() <= time.value()),
Blocks(ref height) => Err(Error::IncompatibleHeight(*self, *height)), Blocks(height) => Err(IncompatibleTimeError { time, height })
} }
} }
} }
@ -251,11 +251,11 @@ impl Time {
/// ///
/// 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 fn from_seconds_ceil(seconds: u32) -> Result<Self, Error> { pub fn from_seconds_ceil(seconds: u32) -> Result<Self, TimeOverflowError> {
if let Ok(interval) = u16::try_from((seconds + 511) / 512) { if let Ok(interval) = u16::try_from((seconds + 511) / 512) {
Ok(Time::from_512_second_intervals(interval)) Ok(Time::from_512_second_intervals(interval))
} else { } else {
Err(Error::IntegerOverflow(seconds)) Err(TimeOverflowError { seconds })
} }
} }
@ -270,49 +270,61 @@ impl fmt::Display for Time {
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) }
} }
/// Errors related to relative lock times. /// Input time in seconds was too large to be encoded to a 16 bit 512 second interval.
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive] pub struct TimeOverflowError {
pub enum Error { /// Time value in seconds that overflowed.
/// Input time in seconds was too large to be encoded to a 16 bit 512 second interval. // Private because we maintain an invariant that the `seconds` value does actually overflow.
IntegerOverflow(u32), pub(crate) seconds: u32
/// Tried to satisfy a lock-by-blocktime lock using a height value.
IncompatibleHeight(LockTime, Height),
/// Tried to satisfy a lock-by-blockheight lock using a time value.
IncompatibleTime(LockTime, Time),
} }
internals::impl_from_infallible!(Error); impl fmt::Display for TimeOverflowError {
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use Error::*; write!(f, "{} seconds is too large to be encoded to a 16 bit 512 second interval", self.seconds)
match *self {
IntegerOverflow(val) => write!(
f,
"{} seconds is too large to be encoded to a 16 bit 512 second interval",
val
),
IncompatibleHeight(lock, height) =>
write!(f, "tried to satisfy lock {} with height: {}", lock, height),
IncompatibleTime(lock, time) =>
write!(f, "tried to satisfy lock {} with time: {}", lock, time),
}
} }
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl std::error::Error for Error { impl std::error::Error for TimeOverflowError {}
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use Error::*;
match *self { /// Tried to satisfy a lock-by-blocktime lock using a height value.
IntegerOverflow(_) | IncompatibleHeight(_, _) | IncompatibleTime(_, _) => None, #[derive(Debug, Clone, PartialEq, Eq)]
} #[non_exhaustive]
pub struct IncompatibleHeightError {
/// Attempted to satisfy a lock-by-blocktime lock with this height.
pub height: Height,
/// The inner time value of the lock-by-blocktime lock.
pub time: Time,
}
impl fmt::Display for IncompatibleHeightError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "tried to satisfy a lock-by-blocktime lock {} with height: {}", self.time, self.height)
} }
} }
#[cfg(feature = "std")]
impl std::error::Error for IncompatibleHeightError {}
/// Tried to satisfy a lock-by-blockheight lock using a time value.
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub struct IncompatibleTimeError {
/// Attempted to satisfy a lock-by-blockheight lock with this time.
pub time: Time,
/// The inner height value of the lock-by-blockheight lock.
pub height: Height,
}
impl fmt::Display for IncompatibleTimeError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "tried to satisfy a lock-by-blockheight lock {} with time: {}", self.height, self.time)
}
}
#[cfg(feature = "std")]
impl std::error::Error for IncompatibleTimeError {}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

View File

@ -19,7 +19,7 @@ use io::{BufRead, Write};
use super::Weight; use super::Weight;
use crate::blockdata::locktime::absolute::{self, Height, Time}; use crate::blockdata::locktime::absolute::{self, Height, Time};
use crate::blockdata::locktime::relative; use crate::blockdata::locktime::relative::{self, TimeOverflowError};
use crate::blockdata::script::{Script, ScriptBuf}; use crate::blockdata::script::{Script, ScriptBuf};
use crate::blockdata::witness::Witness; use crate::blockdata::witness::Witness;
use crate::blockdata::FeeRate; use crate::blockdata::FeeRate;
@ -445,11 +445,11 @@ impl Sequence {
/// ///
/// 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 fn from_seconds_floor(seconds: u32) -> Result<Self, relative::Error> { pub fn from_seconds_floor(seconds: u32) -> Result<Self, TimeOverflowError> {
if let Ok(interval) = u16::try_from(seconds / 512) { if let Ok(interval) = u16::try_from(seconds / 512) {
Ok(Sequence::from_512_second_intervals(interval)) Ok(Sequence::from_512_second_intervals(interval))
} else { } else {
Err(relative::Error::IntegerOverflow(seconds)) Err(TimeOverflowError { seconds })
} }
} }
@ -458,11 +458,11 @@ impl Sequence {
/// ///
/// 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 fn from_seconds_ceil(seconds: u32) -> Result<Self, relative::Error> { pub fn from_seconds_ceil(seconds: u32) -> Result<Self, TimeOverflowError> {
if let Ok(interval) = u16::try_from((seconds + 511) / 512) { if let Ok(interval) = u16::try_from((seconds + 511) / 512) {
Ok(Sequence::from_512_second_intervals(interval)) Ok(Sequence::from_512_second_intervals(interval))
} else { } else {
Err(relative::Error::IntegerOverflow(seconds)) Err(TimeOverflowError { seconds })
} }
} }