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)> { None }
39}
40
41#[derive(Debug, Clone, Eq, PartialEq)]
43pub enum IsSatisfiedByError {
44 Blocks(InvalidHeightError),
46 Time(InvalidTimeError),
48}
49
50impl From<Infallible> for IsSatisfiedByError {
51 fn from(never: Infallible) -> Self { match never {} }
52}
53
54impl fmt::Display for IsSatisfiedByError {
55 #[inline]
56 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
57 match *self {
58 Self::Blocks(ref e) => write_err!(f, "blocks"; e),
59 Self::Time(ref e) => write_err!(f, "time"; e),
60 }
61 }
62}
63
64#[cfg(feature = "std")]
65impl std::error::Error for IsSatisfiedByError {
66 #[inline]
67 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
68 match *self {
69 Self::Blocks(ref e) => Some(e),
70 Self::Time(ref e) => Some(e),
71 }
72 }
73}
74
75#[derive(Debug, Clone, PartialEq, Eq)]
77pub enum IsSatisfiedByHeightError {
78 Satisfaction(InvalidHeightError),
80 Incompatible(IncompatibleHeightError),
82}
83
84impl From<Infallible> for IsSatisfiedByHeightError {
85 fn from(never: Infallible) -> Self { match never {} }
86}
87
88impl fmt::Display for IsSatisfiedByHeightError {
89 #[inline]
90 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
91 match *self {
92 Self::Satisfaction(ref e) => write_err!(f, "satisfaction"; e),
93 Self::Incompatible(ref e) => write_err!(f, "incompatible"; e),
94 }
95 }
96}
97
98#[cfg(feature = "std")]
99impl std::error::Error for IsSatisfiedByHeightError {
100 #[inline]
101 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
102 match *self {
103 Self::Satisfaction(ref e) => Some(e),
104 Self::Incompatible(ref e) => Some(e),
105 }
106 }
107}
108
109#[derive(Debug, Clone, PartialEq, Eq)]
111pub struct IncompatibleHeightError(pub(crate) NumberOf512Seconds);
112
113impl From<Infallible> for IncompatibleHeightError {
114 fn from(never: Infallible) -> Self { match never {} }
115}
116
117impl fmt::Display for IncompatibleHeightError {
118 #[inline]
119 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
120 write!(f, "tried to satisfy a lock-by-height locktime using seconds {}", self.0)
121 }
122}
123
124#[cfg(feature = "std")]
125impl std::error::Error for IncompatibleHeightError {
126 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
127}
128
129#[derive(Debug, Clone, PartialEq, Eq)]
131pub enum IsSatisfiedByTimeError {
132 Satisfaction(InvalidTimeError),
134 Incompatible(IncompatibleTimeError),
136}
137
138impl From<Infallible> for IsSatisfiedByTimeError {
139 fn from(never: Infallible) -> Self { match never {} }
140}
141
142impl fmt::Display for IsSatisfiedByTimeError {
143 #[inline]
144 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
145 match *self {
146 Self::Satisfaction(ref e) => write_err!(f, "satisfaction"; e),
147 Self::Incompatible(ref e) => write_err!(f, "incompatible"; e),
148 }
149 }
150}
151
152#[cfg(feature = "std")]
153impl std::error::Error for IsSatisfiedByTimeError {
154 #[inline]
155 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
156 match *self {
157 Self::Satisfaction(ref e) => Some(e),
158 Self::Incompatible(ref e) => Some(e),
159 }
160 }
161}
162
163#[derive(Debug, Clone, PartialEq, Eq)]
165pub struct IncompatibleTimeError(pub(crate) NumberOfBlocks);
166
167impl From<Infallible> for IncompatibleTimeError {
168 fn from(never: Infallible) -> Self { match never {} }
169}
170
171impl fmt::Display for IncompatibleTimeError {
172 #[inline]
173 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
174 write!(f, "tried to satisfy a lock-by-time locktime using blocks {}", self.0)
175 }
176}
177
178#[cfg(feature = "std")]
179impl std::error::Error for IncompatibleTimeError {
180 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
181}
182
183#[derive(Debug, Clone, PartialEq, Eq)]
185pub struct TimeOverflowError {
186 pub(crate) seconds: u32,
189}
190
191impl From<Infallible> for TimeOverflowError {
192 fn from(never: Infallible) -> Self { match never {} }
193}
194
195impl fmt::Display for TimeOverflowError {
196 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
197 write!(
198 f,
199 "{} seconds is too large to be encoded to a 16 bit 512 second interval",
200 self.seconds
201 )
202 }
203}
204
205#[cfg(feature = "std")]
206impl std::error::Error for TimeOverflowError {
207 #[inline]
208 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
209}
210
211#[derive(Debug, Clone, PartialEq, Eq)]
213pub struct InvalidHeightError {
214 pub(crate) chain_tip: crate::BlockHeight,
216 pub(crate) utxo_mined_at: crate::BlockHeight,
218}
219
220impl From<Infallible> for InvalidHeightError {
221 fn from(never: Infallible) -> Self { match never {} }
222}
223
224impl fmt::Display for InvalidHeightError {
225 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
226 write!(f, "is_satisfied_by arguments invalid (probably the wrong way around) chain_tip: {} utxo_mined_at: {}", self.chain_tip, self.utxo_mined_at
227 )
228 }
229}
230
231#[cfg(feature = "std")]
232impl std::error::Error for InvalidHeightError {
233 #[inline]
234 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
235}
236
237#[derive(Debug, Clone, PartialEq, Eq)]
239pub struct InvalidTimeError {
240 pub(crate) chain_tip: crate::BlockMtp,
242 pub(crate) utxo_mined_at: crate::BlockMtp,
244}
245
246impl From<Infallible> for InvalidTimeError {
247 fn from(never: Infallible) -> Self { match never {} }
248}
249
250impl fmt::Display for InvalidTimeError {
251 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
252 write!(f, "is_satisfied_by arguments invalid (probably the wrong way around) chain_tip: {} utxo_mined_at: {}", self.chain_tip, self.utxo_mined_at
253 )
254 }
255}
256
257#[cfg(feature = "std")]
258impl std::error::Error for InvalidTimeError {
259 #[inline]
260 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
261}
262
263#[cfg(test)]
264mod tests {
265 #[cfg(feature = "alloc")]
266 use alloc::string::ToString;
267 #[cfg(feature = "std")]
268 use std::error::Error;
269
270 #[cfg(feature = "alloc")]
271 use crate::{
272 locktime::relative::{LockTime, NumberOf512Seconds, NumberOfBlocks},
273 BlockHeight, BlockMtp, BlockMtpInterval, Sequence,
274 };
275
276 #[test]
277 #[cfg(feature = "alloc")]
278 fn error_display_is_non_empty() {
279 let disabled = Sequence::MAX; let e = LockTime::from_sequence(disabled).unwrap_err();
282 assert!(!e.to_string().is_empty());
283 #[cfg(feature = "std")]
284 assert!(e.source().is_none());
285
286 let too_big = BlockMtpInterval::MAX;
288 let e = too_big.to_relative_mtp_interval_floor().unwrap_err();
289 assert!(!e.to_string().is_empty());
290 #[cfg(feature = "std")]
291 assert!(e.source().is_none());
292
293 let blocks = NumberOfBlocks::from(10u16);
295 let e = blocks
296 .is_satisfied_by(BlockHeight::from_u32(5), BlockHeight::from_u32(10))
297 .unwrap_err();
298 assert!(!e.to_string().is_empty());
299 #[cfg(feature = "std")]
300 assert!(e.source().is_none());
301
302 let time = NumberOf512Seconds::from_512_second_intervals(10);
304 let e = time.is_satisfied_by(BlockMtp::from_u32(5), BlockMtp::from_u32(10)).unwrap_err();
305 assert!(!e.to_string().is_empty());
306 #[cfg(feature = "std")]
307 assert!(e.source().is_none());
308
309 let time_lock = LockTime::from_512_second_intervals(10);
311 let height_lock = LockTime::from_height(10);
312
313 let e = height_lock
317 .is_satisfied_by(
318 BlockHeight::from_u32(5),
319 BlockMtp::ZERO,
320 BlockHeight::from_u32(10),
321 BlockMtp::ZERO,
322 )
323 .unwrap_err();
324 assert!(!e.to_string().is_empty());
325 #[cfg(feature = "std")]
326 assert!(e.source().is_some());
327 let e = time_lock
329 .is_satisfied_by(
330 BlockHeight::ZERO,
331 BlockMtp::from_u32(5),
332 BlockHeight::ZERO,
333 BlockMtp::from_u32(10),
334 )
335 .unwrap_err();
336 assert!(!e.to_string().is_empty());
337 #[cfg(feature = "std")]
338 assert!(e.source().is_some());
339
340 let e = time_lock
343 .is_satisfied_by_height(BlockHeight::from_u32(5), BlockHeight::from_u32(10))
344 .unwrap_err();
345 assert!(!e.to_string().is_empty());
346 #[cfg(feature = "std")]
347 assert!(e.source().is_some());
348 let e = height_lock
350 .is_satisfied_by_height(BlockHeight::from_u32(5), BlockHeight::from_u32(10))
351 .unwrap_err();
352 assert!(!e.to_string().is_empty());
353 #[cfg(feature = "std")]
354 assert!(e.source().is_some());
355
356 let e = height_lock
359 .is_satisfied_by_time(BlockMtp::from_u32(5), BlockMtp::from_u32(10))
360 .unwrap_err();
361 assert!(!e.to_string().is_empty());
362 #[cfg(feature = "std")]
363 assert!(e.source().is_some());
364 let e = time_lock
366 .is_satisfied_by_time(BlockMtp::from_u32(5), BlockMtp::from_u32(10))
367 .unwrap_err();
368 assert!(!e.to_string().is_empty());
369 #[cfg(feature = "std")]
370 assert!(e.source().is_some());
371 }
372}