bitcoin_units/locktime/relative/
error.rs1use core::convert::Infallible;
6use core::fmt;
7
8use internals::write_err;
9
10use super::{NumberOf512Seconds, NumberOfBlocks};
11
12#[derive(Debug, Clone, Eq, PartialEq)]
15pub struct DisabledLockTimeError(pub(super) u32);
16
17impl DisabledLockTimeError {
18 #[inline]
21 pub fn disabled_locktime_value(&self) -> u32 { self.0 }
22}
23
24impl From<Infallible> for DisabledLockTimeError {
25 fn from(never: Infallible) -> Self { match never {} }
26}
27
28impl fmt::Display for DisabledLockTimeError {
29 #[inline]
30 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
31 write!(f, "lock time 0x{:08x} has disable flag set", self.0)
32 }
33}
34
35#[cfg(feature = "std")]
36impl std::error::Error for DisabledLockTimeError {
37 #[inline]
38 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
39 let Self(_) = self;
40 None
41 }
42}
43
44#[derive(Debug, Clone, Eq, PartialEq)]
46pub enum IsSatisfiedByError {
47 Blocks(InvalidHeightError),
49 Time(InvalidTimeError),
51}
52
53impl From<Infallible> for IsSatisfiedByError {
54 fn from(never: Infallible) -> Self { match never {} }
55}
56
57impl fmt::Display for IsSatisfiedByError {
58 #[inline]
59 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
60 match *self {
61 Self::Blocks(ref e) => write_err!(f, "blocks"; e),
62 Self::Time(ref e) => write_err!(f, "time"; e),
63 }
64 }
65}
66
67#[cfg(feature = "std")]
68impl std::error::Error for IsSatisfiedByError {
69 #[inline]
70 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
71 match *self {
72 Self::Blocks(ref e) => Some(e),
73 Self::Time(ref e) => Some(e),
74 }
75 }
76}
77
78#[derive(Debug, Clone, PartialEq, Eq)]
80pub enum IsSatisfiedByHeightError {
81 Satisfaction(InvalidHeightError),
83 Incompatible(IncompatibleHeightError),
85}
86
87impl From<Infallible> for IsSatisfiedByHeightError {
88 fn from(never: Infallible) -> Self { match never {} }
89}
90
91impl fmt::Display for IsSatisfiedByHeightError {
92 #[inline]
93 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
94 match *self {
95 Self::Satisfaction(ref e) => write_err!(f, "satisfaction"; e),
96 Self::Incompatible(ref e) => write_err!(f, "incompatible"; e),
97 }
98 }
99}
100
101#[cfg(feature = "std")]
102impl std::error::Error for IsSatisfiedByHeightError {
103 #[inline]
104 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
105 match *self {
106 Self::Satisfaction(ref e) => Some(e),
107 Self::Incompatible(ref e) => Some(e),
108 }
109 }
110}
111
112#[derive(Debug, Clone, PartialEq, Eq)]
114pub struct IncompatibleHeightError(pub(crate) NumberOf512Seconds);
115
116impl From<Infallible> for IncompatibleHeightError {
117 fn from(never: Infallible) -> Self { match never {} }
118}
119
120impl fmt::Display for IncompatibleHeightError {
121 #[inline]
122 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
123 write!(f, "tried to satisfy a lock-by-height locktime using seconds {}", self.0)
124 }
125}
126
127#[cfg(feature = "std")]
128impl std::error::Error for IncompatibleHeightError {
129 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
130 let Self(_) = self;
131 None
132 }
133}
134
135#[derive(Debug, Clone, PartialEq, Eq)]
137pub enum IsSatisfiedByTimeError {
138 Satisfaction(InvalidTimeError),
140 Incompatible(IncompatibleTimeError),
142}
143
144impl From<Infallible> for IsSatisfiedByTimeError {
145 fn from(never: Infallible) -> Self { match never {} }
146}
147
148impl fmt::Display for IsSatisfiedByTimeError {
149 #[inline]
150 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
151 match *self {
152 Self::Satisfaction(ref e) => write_err!(f, "satisfaction"; e),
153 Self::Incompatible(ref e) => write_err!(f, "incompatible"; e),
154 }
155 }
156}
157
158#[cfg(feature = "std")]
159impl std::error::Error for IsSatisfiedByTimeError {
160 #[inline]
161 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
162 match *self {
163 Self::Satisfaction(ref e) => Some(e),
164 Self::Incompatible(ref e) => Some(e),
165 }
166 }
167}
168
169#[derive(Debug, Clone, PartialEq, Eq)]
171pub struct IncompatibleTimeError(pub(crate) NumberOfBlocks);
172
173impl From<Infallible> for IncompatibleTimeError {
174 fn from(never: Infallible) -> Self { match never {} }
175}
176
177impl fmt::Display for IncompatibleTimeError {
178 #[inline]
179 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
180 write!(f, "tried to satisfy a lock-by-time locktime using blocks {}", self.0)
181 }
182}
183
184#[cfg(feature = "std")]
185impl std::error::Error for IncompatibleTimeError {
186 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
187 let Self(_) = self;
188 None
189 }
190}
191
192#[derive(Debug, Clone, PartialEq, Eq)]
194pub struct TimeOverflowError {
195 pub(crate) seconds: u32,
198}
199
200impl From<Infallible> for TimeOverflowError {
201 fn from(never: Infallible) -> Self { match never {} }
202}
203
204impl fmt::Display for TimeOverflowError {
205 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
206 write!(
207 f,
208 "{} seconds is too large to be encoded to a 16 bit 512 second interval",
209 self.seconds
210 )
211 }
212}
213
214#[cfg(feature = "std")]
215impl std::error::Error for TimeOverflowError {
216 #[inline]
217 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
218 let Self { seconds: _ } = self;
219 None
220 }
221}
222
223#[derive(Debug, Clone, PartialEq, Eq)]
225pub struct InvalidHeightError {
226 pub(crate) chain_tip: crate::BlockHeight,
228 pub(crate) utxo_mined_at: crate::BlockHeight,
230}
231
232impl From<Infallible> for InvalidHeightError {
233 fn from(never: Infallible) -> Self { match never {} }
234}
235
236impl fmt::Display for InvalidHeightError {
237 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
238 write!(f, "is_satisfied_by arguments invalid (probably the wrong way around) chain_tip: {} utxo_mined_at: {}", self.chain_tip, self.utxo_mined_at
239 )
240 }
241}
242
243#[cfg(feature = "std")]
244impl std::error::Error for InvalidHeightError {
245 #[inline]
246 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
247 let Self { chain_tip: _, utxo_mined_at: _ } = self;
248 None
249 }
250}
251
252#[derive(Debug, Clone, PartialEq, Eq)]
254pub struct InvalidTimeError {
255 pub(crate) chain_tip: crate::BlockMtp,
257 pub(crate) utxo_mined_at: crate::BlockMtp,
259}
260
261impl From<Infallible> for InvalidTimeError {
262 fn from(never: Infallible) -> Self { match never {} }
263}
264
265impl fmt::Display for InvalidTimeError {
266 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
267 write!(f, "is_satisfied_by arguments invalid (probably the wrong way around) chain_tip: {} utxo_mined_at: {}", self.chain_tip, self.utxo_mined_at
268 )
269 }
270}
271
272#[cfg(feature = "std")]
273impl std::error::Error for InvalidTimeError {
274 #[inline]
275 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
276 let Self { chain_tip: _, utxo_mined_at: _ } = self;
277 None
278 }
279}
280
281#[cfg(test)]
282mod tests {
283 #[cfg(feature = "alloc")]
284 use alloc::string::ToString;
285 #[cfg(feature = "std")]
286 use std::error::Error;
287
288 #[cfg(feature = "alloc")]
289 use crate::{
290 locktime::relative::{LockTime, NumberOf512Seconds, NumberOfBlocks},
291 BlockHeight, BlockMtp, BlockMtpInterval, Sequence,
292 };
293
294 #[test]
295 #[cfg(feature = "alloc")]
296 fn error_display_is_non_empty() {
297 let disabled = Sequence::MAX; let e = LockTime::from_sequence(disabled).unwrap_err();
300 assert!(!e.to_string().is_empty());
301 #[cfg(feature = "std")]
302 assert!(e.source().is_none());
303
304 let too_big = BlockMtpInterval::MAX;
306 let e = too_big.to_relative_mtp_interval_floor().unwrap_err();
307 assert!(!e.to_string().is_empty());
308 #[cfg(feature = "std")]
309 assert!(e.source().is_none());
310
311 let blocks = NumberOfBlocks::from(10u16);
313 let e = blocks
314 .is_satisfied_by(BlockHeight::from_u32(5), BlockHeight::from_u32(10))
315 .unwrap_err();
316 assert!(!e.to_string().is_empty());
317 #[cfg(feature = "std")]
318 assert!(e.source().is_none());
319
320 let time = NumberOf512Seconds::from_512_second_intervals(10);
322 let e = time.is_satisfied_by(BlockMtp::from_u32(5), BlockMtp::from_u32(10)).unwrap_err();
323 assert!(!e.to_string().is_empty());
324 #[cfg(feature = "std")]
325 assert!(e.source().is_none());
326
327 let time_lock = LockTime::from_512_second_intervals(10);
329 let height_lock = LockTime::from_height(10);
330
331 let e = height_lock
335 .is_satisfied_by(
336 BlockHeight::from_u32(5),
337 BlockMtp::ZERO,
338 BlockHeight::from_u32(10),
339 BlockMtp::ZERO,
340 )
341 .unwrap_err();
342 assert!(!e.to_string().is_empty());
343 #[cfg(feature = "std")]
344 assert!(e.source().is_some());
345 let e = time_lock
347 .is_satisfied_by(
348 BlockHeight::ZERO,
349 BlockMtp::from_u32(5),
350 BlockHeight::ZERO,
351 BlockMtp::from_u32(10),
352 )
353 .unwrap_err();
354 assert!(!e.to_string().is_empty());
355 #[cfg(feature = "std")]
356 assert!(e.source().is_some());
357
358 let e = time_lock
361 .is_satisfied_by_height(BlockHeight::from_u32(5), BlockHeight::from_u32(10))
362 .unwrap_err();
363 assert!(!e.to_string().is_empty());
364 #[cfg(feature = "std")]
365 assert!(e.source().is_some());
366 let e = height_lock
368 .is_satisfied_by_height(BlockHeight::from_u32(5), BlockHeight::from_u32(10))
369 .unwrap_err();
370 assert!(!e.to_string().is_empty());
371 #[cfg(feature = "std")]
372 assert!(e.source().is_some());
373
374 let e = height_lock
377 .is_satisfied_by_time(BlockMtp::from_u32(5), BlockMtp::from_u32(10))
378 .unwrap_err();
379 assert!(!e.to_string().is_empty());
380 #[cfg(feature = "std")]
381 assert!(e.source().is_some());
382 let e = time_lock
384 .is_satisfied_by_time(BlockMtp::from_u32(5), BlockMtp::from_u32(10))
385 .unwrap_err();
386 assert!(!e.to_string().is_empty());
387 #[cfg(feature = "std")]
388 assert!(e.source().is_some());
389 }
390}