1919
2020use std:: { mem, fmt} ;
2121use std:: cmp:: { PartialOrd , Ordering } ;
22- use std:: convert:: TryFrom ;
23- use std:: str:: FromStr ;
2422use std:: io:: { Read , Write } ;
25- use crate :: error:: ParseIntError ;
26- use crate :: parse;
2723
2824use crate :: encode:: { self , Decodable , Encodable } ;
29- use crate :: error:: write_err;
3025use crate :: parse:: impl_parse_str_through_int;
3126
32- /// The Threshold for deciding whether a lock time value is a height or a time (see [Bitcoin Core]).
33- ///
34- /// `LockTime` values _below_ the threshold are interpreted as block heights, values _above_ (or
35- /// equal to) the threshold are interpreted as block times (UNIX timestamp, seconds since epoch).
36- ///
37- /// Elements is able to safely use this value because a block height greater than 500,000,000 would
38- /// never occur because it would represent a height in approximately 950 years. Conversely, block
39- /// times under 500,000,000 will never happen because they would represent times before 1986 which
40- /// are, for obvious reasons, not useful within any Elements network.
41- ///
42- /// [Bitcoin Core]: https://github.com/bitcoin/bitcoin/blob/9ccaee1d5e2e4b79b0a7c29aadb41b97e4741332/src/script/script.h#L39
43- pub const LOCK_TIME_THRESHOLD : u32 = 500_000_000 ;
27+ pub use bitcoin_units:: locktime:: absolute:: { Height , Time } ;
28+ pub use bitcoin_units:: locktime:: absolute:: ConversionError ;
29+ pub use bitcoin_units:: locktime:: absolute:: LOCK_TIME_THRESHOLD ;
4430
4531/// A lock time value, representing either a block height or a UNIX timestamp (seconds since epoch).
4632///
@@ -96,7 +82,7 @@ pub enum LockTime {
9682impl LockTime {
9783 /// If [`crate::Transaction::lock_time`] is set to zero it is ignored, in other words a
9884 /// transaction with nLocktime==0 is able to be included immediately in any block.
99- pub const ZERO : LockTime = LockTime :: Blocks ( Height ( 0 ) ) ;
85+ pub const ZERO : LockTime = LockTime :: Blocks ( Height :: ZERO ) ;
10086
10187 /// Constructs a `LockTime` from an nLockTime value or the argument to `OP_CHEKCLOCKTIMEVERIFY`.
10288 ///
@@ -130,7 +116,7 @@ impl LockTime {
130116 /// assert!(LockTime::from_height(1653195600).is_err());
131117 /// ```
132118 #[ inline]
133- pub fn from_height ( n : u32 ) -> Result < Self , Error > {
119+ pub fn from_height ( n : u32 ) -> Result < Self , ConversionError > {
134120 let height = Height :: from_consensus ( n) ?;
135121 Ok ( LockTime :: Blocks ( height) )
136122 }
@@ -146,7 +132,7 @@ impl LockTime {
146132 /// assert!(LockTime::from_time(741521).is_err());
147133 /// ```
148134 #[ inline]
149- pub fn from_time ( n : u32 ) -> Result < Self , Error > {
135+ pub fn from_time ( n : u32 ) -> Result < Self , ConversionError > {
150136 let time = Time :: from_consensus ( n) ?;
151137 Ok ( LockTime :: Seconds ( time) )
152138 }
@@ -307,300 +293,11 @@ impl Decodable for LockTime {
307293 }
308294}
309295
310- /// An absolute block height, guaranteed to always contain a valid height value.
311- #[ derive( Debug , Clone , Copy , PartialEq , Eq , PartialOrd , Ord , Hash ) ]
312- #[ cfg_attr( feature = "serde" , derive( serde:: Serialize , serde:: Deserialize ) ) ]
313- pub struct Height ( u32 ) ;
314-
315- impl Height {
316- /// Height zero
317- pub const ZERO : Self = Height ( 0 ) ;
318-
319- /// Constructs a new block height.
320- ///
321- /// # Errors
322- ///
323- /// If `n` does not represent a block height value (see documentation on [`LockTime`]).
324- ///
325- /// # Examples
326- /// ```rust
327- /// use elements::locktime::Height;
328- ///
329- /// let h: u32 = 741521;
330- /// let height = Height::from_consensus(h).expect("invalid height value");
331- /// assert_eq!(height.to_consensus_u32(), h);
332- /// ```
333- #[ inline]
334- pub fn from_consensus ( n : u32 ) -> Result < Height , Error > {
335- if is_block_height ( n) {
336- Ok ( Self ( n) )
337- } else {
338- Err ( ConversionError :: invalid_height ( n) . into ( ) )
339- }
340- }
341-
342- /// Converts this `Height` to its inner `u32` value.
343- ///
344- /// # Examples
345- /// ```rust
346- /// use elements::LockTime;
347- ///
348- /// let n_lock_time: u32 = 741521;
349- /// let lock_time = LockTime::from_consensus(n_lock_time);
350- /// assert!(lock_time.is_block_height());
351- /// assert_eq!(lock_time.to_consensus_u32(), n_lock_time);
352- #[ inline]
353- pub fn to_consensus_u32 ( self ) -> u32 {
354- self . 0
355- }
356- }
357-
358- impl fmt:: Display for Height {
359- fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
360- fmt:: Display :: fmt ( & self . 0 , f)
361- }
362- }
363-
364- impl FromStr for Height {
365- type Err = Error ;
366-
367- fn from_str ( s : & str ) -> Result < Self , Self :: Err > {
368- let n = parse:: int ( s) ?;
369- Height :: from_consensus ( n)
370- }
371- }
372-
373- impl TryFrom < & str > for Height {
374- type Error = Error ;
375-
376- fn try_from ( s : & str ) -> Result < Self , Self :: Error > {
377- let n = parse:: int ( s) ?;
378- Height :: from_consensus ( n)
379- }
380- }
381-
382- impl TryFrom < String > for Height {
383- type Error = Error ;
384-
385- fn try_from ( s : String ) -> Result < Self , Self :: Error > {
386- let n = parse:: int ( s) ?;
387- Height :: from_consensus ( n)
388- }
389- }
390-
391- /// A UNIX timestamp, seconds since epoch, guaranteed to always contain a valid time value.
392- ///
393- /// Note that there is no manipulation of the inner value during construction or when using
394- /// `to_consensus_u32()`. Said another way, `Time(x)` means 'x seconds since epoch' _not_ '(x -
395- /// threshold) seconds since epoch'.
396- #[ derive( Debug , Clone , Copy , PartialEq , Eq , PartialOrd , Ord , Hash ) ]
397- #[ cfg_attr( feature = "serde" , derive( serde:: Serialize , serde:: Deserialize ) ) ]
398- pub struct Time ( u32 ) ;
399-
400- impl Time {
401- /// Constructs a new block time.
402- ///
403- /// # Errors
404- ///
405- /// If `n` does not encode a UNIX time stamp (see documentation on [`LockTime`]).
406- ///
407- /// # Examples
408- /// ```rust
409- /// use elements::locktime::Time;
410- ///
411- /// let t: u32 = 1653195600; // May 22nd, 5am UTC.
412- /// let time = Time::from_consensus(t).expect("invalid time value");
413- /// assert_eq!(time.to_consensus_u32(), t);
414- /// ```
415- #[ inline]
416- pub fn from_consensus ( n : u32 ) -> Result < Time , Error > {
417- if is_block_time ( n) {
418- Ok ( Self ( n) )
419- } else {
420- Err ( ConversionError :: invalid_time ( n) . into ( ) )
421- }
422- }
423-
424- /// Converts this `Time` to its inner `u32` value.
425- ///
426- /// # Examples
427- /// ```rust
428- /// use elements::LockTime;
429- ///
430- /// let n_lock_time: u32 = 1653195600; // May 22nd, 5am UTC.
431- /// let lock_time = LockTime::from_consensus(n_lock_time);
432- /// assert_eq!(lock_time.to_consensus_u32(), n_lock_time);
433- /// ```
434- #[ inline]
435- pub fn to_consensus_u32 ( self ) -> u32 {
436- self . 0
437- }
438- }
439-
440- impl fmt:: Display for Time {
441- fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
442- fmt:: Display :: fmt ( & self . 0 , f)
443- }
444- }
445-
446- impl FromStr for Time {
447- type Err = Error ;
448-
449- fn from_str ( s : & str ) -> Result < Self , Self :: Err > {
450- let n = parse:: int ( s) ?;
451- Time :: from_consensus ( n)
452- }
453- }
454-
455- impl TryFrom < & str > for Time {
456- type Error = Error ;
457-
458- fn try_from ( s : & str ) -> Result < Self , Self :: Error > {
459- let n = parse:: int ( s) ?;
460- Time :: from_consensus ( n)
461- }
462- }
463-
464- impl TryFrom < String > for Time {
465- type Error = Error ;
466-
467- fn try_from ( s : String ) -> Result < Self , Self :: Error > {
468- let n = parse:: int ( s) ?;
469- Time :: from_consensus ( n)
470- }
471- }
472-
473296/// Returns true if `n` is a block height i.e., less than 500,000,000.
474297fn is_block_height ( n : u32 ) -> bool {
475298 n < LOCK_TIME_THRESHOLD
476299}
477300
478- /// Returns true if `n` is a UNIX timestamp i.e., greater than or equal to 500,000,000.
479- fn is_block_time ( n : u32 ) -> bool {
480- n >= LOCK_TIME_THRESHOLD
481- }
482-
483- /// Catchall type for errors that relate to time locks.
484- #[ derive( Debug , Clone , PartialEq , Eq ) ]
485- #[ non_exhaustive]
486- pub enum Error {
487- /// An error occurred while converting a `u32` to a lock time variant.
488- Conversion ( ConversionError ) ,
489- /// An error occurred while operating on lock times.
490- Operation ( OperationError ) ,
491- /// An error occurred while parsing a string into an `u32`.
492- Parse ( ParseIntError ) ,
493- }
494-
495- impl fmt:: Display for Error {
496- fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
497- match * self {
498- Self :: Conversion ( ref e) => write_err ! ( f, "error converting lock time value" ; e) ,
499- Self :: Operation ( ref e) => write_err ! ( f, "error during lock time operation" ; e) ,
500- Self :: Parse ( ref e) => write_err ! ( f, "failed to parse lock time from string" ; e) ,
501- }
502- }
503- }
504-
505- impl std:: error:: Error for Error {
506- fn source ( & self ) -> Option < & ( dyn std:: error:: Error + ' static ) > {
507- match * self {
508- Self :: Conversion ( ref e) => Some ( e) ,
509- Self :: Operation ( ref e) => Some ( e) ,
510- Self :: Parse ( ref e) => Some ( e) ,
511- }
512- }
513- }
514-
515- impl From < ConversionError > for Error {
516- fn from ( e : ConversionError ) -> Self {
517- Error :: Conversion ( e)
518- }
519- }
520-
521- impl From < OperationError > for Error {
522- fn from ( e : OperationError ) -> Self {
523- Error :: Operation ( e)
524- }
525- }
526-
527- impl From < ParseIntError > for Error {
528- fn from ( e : ParseIntError ) -> Self {
529- Error :: Parse ( e)
530- }
531- }
532-
533- /// An error that occurs when converting a `u32` to a lock time variant.
534- #[ derive( Debug , Clone , Eq , PartialEq , Hash ) ]
535- pub struct ConversionError {
536- /// The expected timelock unit, height (blocks) or time (seconds).
537- unit : LockTimeUnit ,
538- /// The invalid input value.
539- input : u32 ,
540- }
541-
542- impl ConversionError {
543- /// Constructs a `ConversionError` from an invalid `n` when expecting a height value.
544- fn invalid_height ( n : u32 ) -> Self {
545- Self {
546- unit : LockTimeUnit :: Blocks ,
547- input : n,
548- }
549- }
550-
551- /// Constructs a `ConversionError` from an invalid `n` when expecting a time value.
552- fn invalid_time ( n : u32 ) -> Self {
553- Self {
554- unit : LockTimeUnit :: Seconds ,
555- input : n,
556- }
557- }
558- }
559-
560- impl fmt:: Display for ConversionError {
561- fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
562- write ! ( f, "invalid lock time value {}, {}" , self . input, self . unit)
563- }
564- }
565-
566- impl std:: error:: Error for ConversionError { }
567-
568- /// Describes the two types of locking, lock-by-blockheight and lock-by-blocktime.
569- #[ derive( Debug , Clone , Copy , Eq , PartialEq , Hash ) ]
570- enum LockTimeUnit {
571- /// Lock by blockheight.
572- Blocks ,
573- /// Lock by blocktime.
574- Seconds ,
575- }
576-
577- impl fmt:: Display for LockTimeUnit {
578- fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
579- match * self {
580- Self :: Blocks => write ! ( f, "expected lock-by-blockheight (must be < {})" , LOCK_TIME_THRESHOLD ) ,
581- Self :: Seconds => write ! ( f, "expected lock-by-blocktime (must be >= {})" , LOCK_TIME_THRESHOLD ) ,
582- }
583- }
584- }
585-
586- /// Errors than occur when operating on lock times.
587- #[ derive( Debug , Clone , Copy , PartialEq , Eq , PartialOrd , Ord , Hash ) ]
588- #[ non_exhaustive]
589- pub enum OperationError {
590- /// Cannot compare different lock time units (height vs time).
591- InvalidComparison ,
592- }
593-
594- impl fmt:: Display for OperationError {
595- fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
596- match * self {
597- Self :: InvalidComparison => f. write_str ( "cannot compare different lock units (height vs time)" ) ,
598- }
599- }
600- }
601-
602- impl std:: error:: Error for OperationError { }
603-
604301#[ cfg( test) ]
605302mod tests {
606303 use super :: * ;
0 commit comments