use core::convert::Infallible;
use core::fmt;
use internals::write_err;
use super::{NumberOf512Seconds, NumberOfBlocks};
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct DisabledLockTimeError(pub(super) u32);
impl DisabledLockTimeError {
#[inline]
pub fn disabled_locktime_value(&self) -> u32 { self.0 }
}
impl From<Infallible> for DisabledLockTimeError {
fn from(never: Infallible) -> Self { match never {} }
}
impl fmt::Display for DisabledLockTimeError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "lock time 0x{:08x} has disable flag set", self.0)
}
}
#[cfg(feature = "std")]
impl std::error::Error for DisabledLockTimeError {
#[inline]
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum IsSatisfiedByError {
Blocks(InvalidHeightError),
Time(InvalidTimeError),
}
impl From<Infallible> for IsSatisfiedByError {
fn from(never: Infallible) -> Self { match never {} }
}
impl fmt::Display for IsSatisfiedByError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Self::Blocks(ref e) => write_err!(f, "blocks"; e),
Self::Time(ref e) => write_err!(f, "time"; e),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for IsSatisfiedByError {
#[inline]
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match *self {
Self::Blocks(ref e) => Some(e),
Self::Time(ref e) => Some(e),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum IsSatisfiedByHeightError {
Satisfaction(InvalidHeightError),
Incompatible(IncompatibleHeightError),
}
impl From<Infallible> for IsSatisfiedByHeightError {
fn from(never: Infallible) -> Self { match never {} }
}
impl fmt::Display for IsSatisfiedByHeightError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Self::Satisfaction(ref e) => write_err!(f, "satisfaction"; e),
Self::Incompatible(ref e) => write_err!(f, "incompatible"; e),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for IsSatisfiedByHeightError {
#[inline]
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match *self {
Self::Satisfaction(ref e) => Some(e),
Self::Incompatible(ref e) => Some(e),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct IncompatibleHeightError(pub(crate) NumberOf512Seconds);
impl From<Infallible> for IncompatibleHeightError {
fn from(never: Infallible) -> Self { match never {} }
}
impl fmt::Display for IncompatibleHeightError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "tried to satisfy a lock-by-height locktime using seconds {}", self.0)
}
}
#[cfg(feature = "std")]
impl std::error::Error for IncompatibleHeightError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum IsSatisfiedByTimeError {
Satisfaction(InvalidTimeError),
Incompatible(IncompatibleTimeError),
}
impl From<Infallible> for IsSatisfiedByTimeError {
fn from(never: Infallible) -> Self { match never {} }
}
impl fmt::Display for IsSatisfiedByTimeError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Self::Satisfaction(ref e) => write_err!(f, "satisfaction"; e),
Self::Incompatible(ref e) => write_err!(f, "incompatible"; e),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for IsSatisfiedByTimeError {
#[inline]
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match *self {
Self::Satisfaction(ref e) => Some(e),
Self::Incompatible(ref e) => Some(e),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct IncompatibleTimeError(pub(crate) NumberOfBlocks);
impl From<Infallible> for IncompatibleTimeError {
fn from(never: Infallible) -> Self { match never {} }
}
impl fmt::Display for IncompatibleTimeError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "tried to satisfy a lock-by-time locktime using blocks {}", self.0)
}
}
#[cfg(feature = "std")]
impl std::error::Error for IncompatibleTimeError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TimeOverflowError {
pub(crate) seconds: u32,
}
impl From<Infallible> for TimeOverflowError {
fn from(never: Infallible) -> Self { match never {} }
}
impl fmt::Display for TimeOverflowError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{} seconds is too large to be encoded to a 16 bit 512 second interval",
self.seconds
)
}
}
#[cfg(feature = "std")]
impl std::error::Error for TimeOverflowError {
#[inline]
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct InvalidHeightError {
pub(crate) chain_tip: crate::BlockHeight,
pub(crate) utxo_mined_at: crate::BlockHeight,
}
impl From<Infallible> for InvalidHeightError {
fn from(never: Infallible) -> Self { match never {} }
}
impl fmt::Display for InvalidHeightError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "is_satisfied_by arguments invalid (probably the wrong way around) chain_tip: {} utxo_mined_at: {}", self.chain_tip, self.utxo_mined_at
)
}
}
#[cfg(feature = "std")]
impl std::error::Error for InvalidHeightError {
#[inline]
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct InvalidTimeError {
pub(crate) chain_tip: crate::BlockMtp,
pub(crate) utxo_mined_at: crate::BlockMtp,
}
impl From<Infallible> for InvalidTimeError {
fn from(never: Infallible) -> Self { match never {} }
}
impl fmt::Display for InvalidTimeError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "is_satisfied_by arguments invalid (probably the wrong way around) chain_tip: {} utxo_mined_at: {}", self.chain_tip, self.utxo_mined_at
)
}
}
#[cfg(feature = "std")]
impl std::error::Error for InvalidTimeError {
#[inline]
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
}
#[cfg(test)]
mod tests {
#[cfg(feature = "alloc")]
use alloc::string::ToString;
#[cfg(feature = "std")]
use std::error::Error;
#[cfg(feature = "alloc")]
use crate::{
locktime::relative::{LockTime, NumberOf512Seconds, NumberOfBlocks},
BlockHeight, BlockMtp, BlockMtpInterval, Sequence,
};
#[test]
#[cfg(feature = "alloc")]
fn error_display_is_non_empty() {
let disabled = Sequence::MAX; let e = LockTime::from_sequence(disabled).unwrap_err();
assert!(!e.to_string().is_empty());
#[cfg(feature = "std")]
assert!(e.source().is_none());
let too_big = BlockMtpInterval::MAX;
let e = too_big.to_relative_mtp_interval_floor().unwrap_err();
assert!(!e.to_string().is_empty());
#[cfg(feature = "std")]
assert!(e.source().is_none());
let blocks = NumberOfBlocks::from(10u16);
let e = blocks
.is_satisfied_by(BlockHeight::from_u32(5), BlockHeight::from_u32(10))
.unwrap_err();
assert!(!e.to_string().is_empty());
#[cfg(feature = "std")]
assert!(e.source().is_none());
let time = NumberOf512Seconds::from_512_second_intervals(10);
let e = time.is_satisfied_by(BlockMtp::from_u32(5), BlockMtp::from_u32(10)).unwrap_err();
assert!(!e.to_string().is_empty());
#[cfg(feature = "std")]
assert!(e.source().is_none());
let time_lock = LockTime::from_512_second_intervals(10);
let height_lock = LockTime::from_height(10);
let e = height_lock
.is_satisfied_by(
BlockHeight::from_u32(5),
BlockMtp::ZERO,
BlockHeight::from_u32(10),
BlockMtp::ZERO,
)
.unwrap_err();
assert!(!e.to_string().is_empty());
#[cfg(feature = "std")]
assert!(e.source().is_some());
let e = time_lock
.is_satisfied_by(
BlockHeight::ZERO,
BlockMtp::from_u32(5),
BlockHeight::ZERO,
BlockMtp::from_u32(10),
)
.unwrap_err();
assert!(!e.to_string().is_empty());
#[cfg(feature = "std")]
assert!(e.source().is_some());
let e = time_lock
.is_satisfied_by_height(BlockHeight::from_u32(5), BlockHeight::from_u32(10))
.unwrap_err();
assert!(!e.to_string().is_empty());
#[cfg(feature = "std")]
assert!(e.source().is_some());
let e = height_lock
.is_satisfied_by_height(BlockHeight::from_u32(5), BlockHeight::from_u32(10))
.unwrap_err();
assert!(!e.to_string().is_empty());
#[cfg(feature = "std")]
assert!(e.source().is_some());
let e = height_lock
.is_satisfied_by_time(BlockMtp::from_u32(5), BlockMtp::from_u32(10))
.unwrap_err();
assert!(!e.to_string().is_empty());
#[cfg(feature = "std")]
assert!(e.source().is_some());
let e = time_lock
.is_satisfied_by_time(BlockMtp::from_u32(5), BlockMtp::from_u32(10))
.unwrap_err();
assert!(!e.to_string().is_empty());
#[cfg(feature = "std")]
assert!(e.source().is_some());
}
}