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 #[inline]
26 fn from(never: Infallible) -> Self { match never {} }
27}
28
29impl fmt::Display for DisabledLockTimeError {
30 #[inline]
31 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
32 write!(f, "lock time 0x{:08x} has disable flag set", self.0)
33 }
34}
35
36#[cfg(feature = "std")]
37impl std::error::Error for DisabledLockTimeError {
38 #[inline]
39 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
40 let Self(_) = self;
41 None
42 }
43}
44
45#[derive(Debug, Clone, Eq, PartialEq)]
49pub enum IsSatisfiedByError {
50 Blocks(InvalidHeightError),
52 Time(InvalidTimeError),
54}
55
56impl From<Infallible> for IsSatisfiedByError {
57 #[inline]
58 fn from(never: Infallible) -> Self { match never {} }
59}
60
61impl fmt::Display for IsSatisfiedByError {
62 #[inline]
63 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
64 match *self {
65 Self::Blocks(ref e) => write_err!(f, "blocks"; e),
66 Self::Time(ref e) => write_err!(f, "time"; e),
67 }
68 }
69}
70
71#[cfg(feature = "std")]
72impl std::error::Error for IsSatisfiedByError {
73 #[inline]
74 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
75 match *self {
76 Self::Blocks(ref e) => Some(e),
77 Self::Time(ref e) => Some(e),
78 }
79 }
80}
81
82#[derive(Debug, Clone, PartialEq, Eq)]
86pub enum IsSatisfiedByHeightError {
87 Satisfaction(InvalidHeightError),
89 Incompatible(IncompatibleHeightError),
91}
92
93impl From<Infallible> for IsSatisfiedByHeightError {
94 #[inline]
95 fn from(never: Infallible) -> Self { match never {} }
96}
97
98impl fmt::Display for IsSatisfiedByHeightError {
99 #[inline]
100 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
101 match *self {
102 Self::Satisfaction(ref e) => write_err!(f, "satisfaction"; e),
103 Self::Incompatible(ref e) => write_err!(f, "incompatible"; e),
104 }
105 }
106}
107
108#[cfg(feature = "std")]
109impl std::error::Error for IsSatisfiedByHeightError {
110 #[inline]
111 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
112 match *self {
113 Self::Satisfaction(ref e) => Some(e),
114 Self::Incompatible(ref e) => Some(e),
115 }
116 }
117}
118
119#[derive(Debug, Clone, PartialEq, Eq)]
123pub struct IncompatibleHeightError(pub(crate) NumberOf512Seconds);
124
125impl From<Infallible> for IncompatibleHeightError {
126 #[inline]
127 fn from(never: Infallible) -> Self { match never {} }
128}
129
130impl fmt::Display for IncompatibleHeightError {
131 #[inline]
132 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
133 write!(
134 f,
135 "tried to satisfy a lock-by-time locktime ({} 512-second intervals) using a block height",
136 self.0
137 )
138 }
139}
140
141#[cfg(feature = "std")]
142impl std::error::Error for IncompatibleHeightError {
143 #[inline]
144 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
145 let Self(_) = self;
146 None
147 }
148}
149
150#[derive(Debug, Clone, PartialEq, Eq)]
154pub enum IsSatisfiedByTimeError {
155 Satisfaction(InvalidTimeError),
157 Incompatible(IncompatibleTimeError),
159}
160
161impl From<Infallible> for IsSatisfiedByTimeError {
162 #[inline]
163 fn from(never: Infallible) -> Self { match never {} }
164}
165
166impl fmt::Display for IsSatisfiedByTimeError {
167 #[inline]
168 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
169 match *self {
170 Self::Satisfaction(ref e) => write_err!(f, "satisfaction"; e),
171 Self::Incompatible(ref e) => write_err!(f, "incompatible"; e),
172 }
173 }
174}
175
176#[cfg(feature = "std")]
177impl std::error::Error for IsSatisfiedByTimeError {
178 #[inline]
179 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
180 match *self {
181 Self::Satisfaction(ref e) => Some(e),
182 Self::Incompatible(ref e) => Some(e),
183 }
184 }
185}
186
187#[derive(Debug, Clone, PartialEq, Eq)]
191pub struct IncompatibleTimeError(pub(crate) NumberOfBlocks);
192
193impl From<Infallible> for IncompatibleTimeError {
194 #[inline]
195 fn from(never: Infallible) -> Self { match never {} }
196}
197
198impl fmt::Display for IncompatibleTimeError {
199 #[inline]
200 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
201 write!(f, "tried to satisfy a lock-by-height locktime ({} blocks) using an MTP", self.0)
202 }
203}
204
205#[cfg(feature = "std")]
206impl std::error::Error for IncompatibleTimeError {
207 #[inline]
208 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
209 let Self(_) = self;
210 None
211 }
212}
213
214#[derive(Debug, Clone, PartialEq, Eq)]
216pub struct TimeOverflowError {
217 pub(crate) seconds: u32,
220}
221
222impl From<Infallible> for TimeOverflowError {
223 #[inline]
224 fn from(never: Infallible) -> Self { match never {} }
225}
226
227impl fmt::Display for TimeOverflowError {
228 #[inline]
229 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
230 write!(
231 f,
232 "{} seconds is too large to be encoded to a 16 bit 512 second interval",
233 self.seconds
234 )
235 }
236}
237
238#[cfg(feature = "std")]
239impl std::error::Error for TimeOverflowError {
240 #[inline]
241 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
242 let Self { seconds: _ } = self;
243 None
244 }
245}
246
247#[derive(Debug, Clone, PartialEq, Eq)]
251pub struct InvalidHeightError {
252 pub(crate) chain_tip: crate::BlockHeight,
254 pub(crate) utxo_mined_at: crate::BlockHeight,
256}
257
258impl From<Infallible> for InvalidHeightError {
259 #[inline]
260 fn from(never: Infallible) -> Self { match never {} }
261}
262
263impl fmt::Display for InvalidHeightError {
264 #[inline]
265 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
266 write!(f, "is_satisfied_by arguments invalid (probably the wrong way around) chain_tip: {} utxo_mined_at: {}", self.chain_tip, self.utxo_mined_at
267 )
268 }
269}
270
271#[cfg(feature = "std")]
272impl std::error::Error for InvalidHeightError {
273 #[inline]
274 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
275 let Self { chain_tip: _, utxo_mined_at: _ } = self;
276 None
277 }
278}
279
280#[derive(Debug, Clone, PartialEq, Eq)]
284pub struct InvalidTimeError {
285 pub(crate) chain_tip: crate::BlockMtp,
287 pub(crate) utxo_mined_at: crate::BlockMtp,
289}
290
291impl From<Infallible> for InvalidTimeError {
292 #[inline]
293 fn from(never: Infallible) -> Self { match never {} }
294}
295
296impl fmt::Display for InvalidTimeError {
297 #[inline]
298 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
299 write!(f, "is_satisfied_by arguments invalid (probably the wrong way around) chain_tip: {} utxo_mined_at: {}", self.chain_tip, self.utxo_mined_at
300 )
301 }
302}
303
304#[cfg(feature = "std")]
305impl std::error::Error for InvalidTimeError {
306 #[inline]
307 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
308 let Self { chain_tip: _, utxo_mined_at: _ } = self;
309 None
310 }
311}
312
313#[cfg(test)]
314mod tests {
315 #[cfg(feature = "alloc")]
316 use alloc::string::ToString;
317 #[cfg(feature = "std")]
318 use std::error::Error;
319
320 #[cfg(feature = "alloc")]
321 use crate::{
322 locktime::relative::{LockTime, NumberOf512Seconds, NumberOfBlocks},
323 BlockHeight, BlockMtp, BlockMtpInterval, Sequence,
324 };
325
326 #[test]
327 #[cfg(feature = "alloc")]
328 fn error_display_is_non_empty() {
329 let disabled = Sequence::MAX; let e = LockTime::from_sequence(disabled).unwrap_err();
332 assert!(!e.to_string().is_empty());
333 #[cfg(feature = "std")]
334 assert!(e.source().is_none());
335
336 let too_big = BlockMtpInterval::MAX;
338 let e = too_big.to_relative_mtp_interval_floor().unwrap_err();
339 assert!(!e.to_string().is_empty());
340 #[cfg(feature = "std")]
341 assert!(e.source().is_none());
342
343 let blocks = NumberOfBlocks::from_count(10);
345 let e = blocks
346 .is_satisfied_by(BlockHeight::from_u32(5), Some(BlockHeight::from_u32(10)))
347 .unwrap_err();
348 assert!(!e.to_string().is_empty());
349 #[cfg(feature = "std")]
350 assert!(e.source().is_none());
351
352 let time = NumberOf512Seconds::from_512_second_intervals(10);
354 let e =
355 time.is_satisfied_by(BlockMtp::from_u32(5), Some(BlockMtp::from_u32(10))).unwrap_err();
356 assert!(!e.to_string().is_empty());
357 #[cfg(feature = "std")]
358 assert!(e.source().is_none());
359
360 let time_lock = LockTime::from_512_second_intervals(10);
362 let height_lock = LockTime::from_block_count(10);
363
364 let e = height_lock
368 .is_satisfied_by(
369 BlockHeight::from_u32(5),
370 BlockMtp::ZERO,
371 Some(BlockHeight::from_u32(10)),
372 Some(BlockMtp::ZERO),
373 )
374 .unwrap_err();
375 assert!(!e.to_string().is_empty());
376 #[cfg(feature = "std")]
377 assert!(e.source().is_some());
378 let e = time_lock
380 .is_satisfied_by(
381 BlockHeight::ZERO,
382 BlockMtp::from_u32(5),
383 Some(BlockHeight::ZERO),
384 Some(BlockMtp::from_u32(10)),
385 )
386 .unwrap_err();
387 assert!(!e.to_string().is_empty());
388 #[cfg(feature = "std")]
389 assert!(e.source().is_some());
390
391 let e = time_lock
394 .is_satisfied_by_height(BlockHeight::from_u32(5), Some(BlockHeight::from_u32(10)))
395 .unwrap_err();
396 assert!(!e.to_string().is_empty());
397 #[cfg(feature = "std")]
398 assert!(e.source().is_some());
399 let e = height_lock
401 .is_satisfied_by_height(BlockHeight::from_u32(5), Some(BlockHeight::from_u32(10)))
402 .unwrap_err();
403 assert!(!e.to_string().is_empty());
404 #[cfg(feature = "std")]
405 assert!(e.source().is_some());
406
407 let e = height_lock
410 .is_satisfied_by_time(BlockMtp::from_u32(5), Some(BlockMtp::from_u32(10)))
411 .unwrap_err();
412 assert!(!e.to_string().is_empty());
413 #[cfg(feature = "std")]
414 assert!(e.source().is_some());
415 let e = time_lock
417 .is_satisfied_by_time(BlockMtp::from_u32(5), Some(BlockMtp::from_u32(10)))
418 .unwrap_err();
419 assert!(!e.to_string().is_empty());
420 #[cfg(feature = "std")]
421 assert!(e.source().is_some());
422 }
423}