1pub mod error;
10
11use core::{convert, fmt};
12
13#[cfg(feature = "arbitrary")]
14use arbitrary::{Arbitrary, Unstructured};
15use internals::const_casts;
16
17#[cfg(doc)]
18use crate::relative;
19use crate::{parse_int, BlockHeight, BlockMtp, Sequence};
20
21#[rustfmt::skip] #[doc(no_inline)]
23pub use self::error::{
24 DisabledLockTimeError, InvalidHeightError, InvalidTimeError, IsSatisfiedByError,
25 IsSatisfiedByHeightError, IsSatisfiedByTimeError, TimeOverflowError,
26};
27
28#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
44pub enum LockTime {
45 Blocks(NumberOfBlocks),
47 Time(NumberOf512Seconds),
49}
50
51impl LockTime {
52 pub const ZERO: Self = Self::Blocks(NumberOfBlocks::ZERO);
55
56 pub const SIZE: usize = 4; #[inline]
89 pub fn from_consensus(n: u32) -> Result<Self, DisabledLockTimeError> {
90 let sequence = crate::Sequence::from_consensus(n);
91 sequence.to_relative_lock_time().ok_or(DisabledLockTimeError(n))
92 }
93
94 #[inline]
102 pub fn to_consensus_u32(self) -> u32 {
103 match self {
104 Self::Blocks(ref h) => u32::from(h.to_height()),
105 Self::Time(ref t) => Sequence::LOCK_TYPE_MASK | u32::from(t.to_512_second_intervals()),
106 }
107 }
108
109 #[inline]
131 pub fn from_sequence(n: Sequence) -> Result<Self, DisabledLockTimeError> {
132 Self::from_consensus(n.to_consensus_u32())
133 }
134
135 #[inline]
137 pub fn to_sequence(self) -> Sequence { Sequence::from_consensus(self.to_consensus_u32()) }
138
139 #[inline]
141 pub const fn from_height(n: u16) -> Self { Self::Blocks(NumberOfBlocks::from_height(n)) }
142
143 #[inline]
148 pub const fn from_512_second_intervals(intervals: u16) -> Self {
149 Self::Time(NumberOf512Seconds::from_512_second_intervals(intervals))
150 }
151
152 #[inline]
159 pub const fn from_seconds_floor(seconds: u32) -> Result<Self, TimeOverflowError> {
160 match NumberOf512Seconds::from_seconds_floor(seconds) {
161 Ok(time) => Ok(Self::Time(time)),
162 Err(e) => Err(e),
163 }
164 }
165
166 #[inline]
173 pub const fn from_seconds_ceil(seconds: u32) -> Result<Self, TimeOverflowError> {
174 match NumberOf512Seconds::from_seconds_ceil(seconds) {
175 Ok(time) => Ok(Self::Time(time)),
176 Err(e) => Err(e),
177 }
178 }
179
180 #[inline]
182 pub const fn is_same_unit(self, other: Self) -> bool {
183 matches!((self, other), (Self::Blocks(_), Self::Blocks(_)) | (Self::Time(_), Self::Time(_)))
184 }
185
186 #[inline]
188 pub const fn is_block_height(self) -> bool { matches!(self, Self::Blocks(_)) }
189
190 #[inline]
192 pub const fn is_block_time(self) -> bool { !self.is_block_height() }
193
194 pub fn is_satisfied_by(
203 self,
204 chain_tip_height: BlockHeight,
205 chain_tip_mtp: BlockMtp,
206 utxo_mined_at_height: BlockHeight,
207 utxo_mined_at_mtp: BlockMtp,
208 ) -> Result<bool, IsSatisfiedByError> {
209 match self {
210 Self::Blocks(blocks) => blocks
211 .is_satisfied_by(chain_tip_height, utxo_mined_at_height)
212 .map_err(IsSatisfiedByError::Blocks),
213 Self::Time(time) => time
214 .is_satisfied_by(chain_tip_mtp, utxo_mined_at_mtp)
215 .map_err(IsSatisfiedByError::Time),
216 }
217 }
218
219 #[inline]
228 pub fn is_satisfied_by_height(
229 self,
230 chain_tip: BlockHeight,
231 utxo_mined_at: BlockHeight,
232 ) -> Result<bool, IsSatisfiedByHeightError> {
233 match self {
234 Self::Blocks(blocks) => blocks
235 .is_satisfied_by(chain_tip, utxo_mined_at)
236 .map_err(IsSatisfiedByHeightError::Satisfaction),
237 Self::Time(time) => Err(IsSatisfiedByHeightError::Incompatible(time)),
238 }
239 }
240
241 #[inline]
250 pub fn is_satisfied_by_time(
251 self,
252 chain_tip: BlockMtp,
253 utxo_mined_at: BlockMtp,
254 ) -> Result<bool, IsSatisfiedByTimeError> {
255 match self {
256 Self::Time(time) => time
257 .is_satisfied_by(chain_tip, utxo_mined_at)
258 .map_err(IsSatisfiedByTimeError::Satisfaction),
259 Self::Blocks(blocks) => Err(IsSatisfiedByTimeError::Incompatible(blocks)),
260 }
261 }
262
263 #[inline]
293 pub fn is_implied_by(self, other: Self) -> bool {
294 match (self, other) {
295 (Self::Blocks(this), Self::Blocks(other)) => this <= other,
296 (Self::Time(this), Self::Time(other)) => this <= other,
297 _ => false, }
299 }
300
301 #[inline]
322 pub fn is_implied_by_sequence(self, other: Sequence) -> bool {
323 if let Ok(other) = Self::from_sequence(other) {
324 self.is_implied_by(other)
325 } else {
326 false
327 }
328 }
329}
330
331impl From<NumberOfBlocks> for LockTime {
332 #[inline]
333 fn from(h: NumberOfBlocks) -> Self { Self::Blocks(h) }
334}
335
336impl From<NumberOf512Seconds> for LockTime {
337 #[inline]
338 fn from(t: NumberOf512Seconds) -> Self { Self::Time(t) }
339}
340
341impl fmt::Display for LockTime {
342 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
343 if f.alternate() {
344 match *self {
345 Self::Blocks(ref h) => write!(f, "block-height {}", h),
346 Self::Time(ref t) => write!(f, "block-time {} (512 second intervals)", t),
347 }
348 } else {
349 match *self {
350 Self::Blocks(ref h) => fmt::Display::fmt(h, f),
351 Self::Time(ref t) => fmt::Display::fmt(t, f),
352 }
353 }
354 }
355}
356
357impl convert::TryFrom<Sequence> for LockTime {
358 type Error = DisabledLockTimeError;
359 #[inline]
360 fn try_from(seq: Sequence) -> Result<Self, DisabledLockTimeError> { Self::from_sequence(seq) }
361}
362
363impl From<LockTime> for Sequence {
364 #[inline]
365 fn from(lt: LockTime) -> Self { lt.to_sequence() }
366}
367
368#[cfg(feature = "serde")]
369impl serde::Serialize for LockTime {
370 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
371 where
372 S: serde::Serializer,
373 {
374 self.to_consensus_u32().serialize(serializer)
375 }
376}
377
378#[cfg(feature = "serde")]
379impl<'de> serde::Deserialize<'de> for LockTime {
380 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
381 where
382 D: serde::Deserializer<'de>,
383 {
384 u32::deserialize(deserializer)
385 .and_then(|n| Self::from_consensus(n).map_err(serde::de::Error::custom))
386 }
387}
388
389#[deprecated(since = "1.0.0-rc.0", note = "use `NumberOfBlocks` instead")]
390#[doc(hidden)]
391pub type Height = NumberOfBlocks;
392
393#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
395pub struct NumberOfBlocks(u16);
396
397impl NumberOfBlocks {
398 pub const ZERO: Self = Self(0);
400
401 pub const MIN: Self = Self::ZERO;
403
404 pub const MAX: Self = Self(u16::MAX);
406
407 #[inline]
409 pub const fn from_height(blocks: u16) -> Self { Self(blocks) }
410
411 #[inline]
413 #[must_use]
414 pub const fn to_height(self) -> u16 { self.0 }
415
416 #[inline]
418 #[must_use]
419 #[deprecated(since = "1.0.0-rc.0", note = "use `to_height` instead")]
420 #[doc(hidden)]
421 pub const fn value(self) -> u16 { self.0 }
422
423 #[deprecated(
426 since = "1.0.0-rc.0",
427 note = "use `LockTime::from` followed by `to_consensus_u32` instead"
428 )]
429 pub const fn to_consensus_u32(self) -> u32 {
430 self.0 as u32 }
432
433 pub fn is_satisfied_by(
439 self,
440 chain_tip: crate::BlockHeight,
441 utxo_mined_at: crate::BlockHeight,
442 ) -> Result<bool, InvalidHeightError> {
443 match chain_tip.checked_sub(utxo_mined_at) {
444 Some(diff) => {
445 if diff.to_u32() == u32::MAX {
446 return Ok(true);
448 }
449 Ok(u32::from(self.to_height()) <= diff.to_u32() + 1)
451 }
452 None => Err(InvalidHeightError { chain_tip, utxo_mined_at }),
453 }
454 }
455}
456
457crate::internal_macros::impl_fmt_traits_for_u32_wrapper!(NumberOfBlocks);
458
459impl From<u16> for NumberOfBlocks {
460 #[inline]
461 fn from(value: u16) -> Self { Self(value) }
462}
463
464parse_int::impl_parse_str_from_int_infallible!(NumberOfBlocks, u16, from);
465
466impl fmt::Display for NumberOfBlocks {
467 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
468}
469
470#[deprecated(since = "1.0.0-rc.0", note = "use `NumberOf512Seconds` instead")]
471#[doc(hidden)]
472pub type Time = NumberOf512Seconds;
473
474#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
478pub struct NumberOf512Seconds(u16);
479
480impl NumberOf512Seconds {
481 pub const ZERO: Self = Self(0);
483
484 pub const MIN: Self = Self::ZERO;
486
487 pub const MAX: Self = Self(u16::MAX);
489
490 #[inline]
495 pub const fn from_512_second_intervals(intervals: u16) -> Self { Self(intervals) }
496
497 #[inline]
499 #[must_use]
500 pub const fn to_512_second_intervals(self) -> u16 { self.0 }
501
502 #[inline]
509 #[rustfmt::skip] pub const fn from_seconds_floor(seconds: u32) -> Result<Self, TimeOverflowError> {
511 let interval = seconds / 512;
512 if interval <= u16::MAX as u32 { Ok(Self::from_512_second_intervals(interval as u16)) } else {
515 Err(TimeOverflowError { seconds })
516 }
517 }
518
519 #[inline]
526 #[rustfmt::skip] pub const fn from_seconds_ceil(seconds: u32) -> Result<Self, TimeOverflowError> {
528 if seconds <= u16::MAX as u32 * 512 {
529 let interval = seconds.div_ceil(512);
530 Ok(Self::from_512_second_intervals(interval as u16)) } else {
532 Err(TimeOverflowError { seconds })
533 }
534 }
535
536 #[inline]
538 pub const fn to_seconds(self) -> u32 { const_casts::u16_to_u32(self.0) * 512 }
539
540 #[inline]
542 #[must_use]
543 #[deprecated(since = "1.0.0-rc.0", note = "use `to_512_second_intervals` instead")]
544 #[doc(hidden)]
545 pub const fn value(self) -> u16 { self.0 }
546
547 #[deprecated(
550 since = "1.0.0-rc.0",
551 note = "use `LockTime::from` followed by `to_consensus_u32` instead"
552 )]
553 pub const fn to_consensus_u32(self) -> u32 {
554 (1u32 << 22) | self.0 as u32 }
556
557 pub fn is_satisfied_by(
563 self,
564 chain_tip: crate::BlockMtp,
565 utxo_mined_at: crate::BlockMtp,
566 ) -> Result<bool, InvalidTimeError> {
567 match chain_tip.checked_sub(utxo_mined_at) {
568 Some(diff) => {
569 Ok(self.to_seconds() <= diff.to_u32())
572 }
573 None => Err(InvalidTimeError { chain_tip, utxo_mined_at }),
574 }
575 }
576}
577
578crate::internal_macros::impl_fmt_traits_for_u32_wrapper!(NumberOf512Seconds);
579
580parse_int::impl_parse_str_from_int_infallible!(NumberOf512Seconds, u16, from_512_second_intervals);
581
582impl fmt::Display for NumberOf512Seconds {
583 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
584}
585
586#[cfg(feature = "arbitrary")]
587impl<'a> Arbitrary<'a> for LockTime {
588 fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
589 let choice = u.int_in_range(0..=1)?;
590
591 match choice {
592 0 => Ok(Self::Blocks(NumberOfBlocks::arbitrary(u)?)),
593 _ => Ok(Self::Time(NumberOf512Seconds::arbitrary(u)?)),
594 }
595 }
596}
597
598#[cfg(feature = "arbitrary")]
599impl<'a> Arbitrary<'a> for NumberOfBlocks {
600 fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
601 let choice = u.int_in_range(0..=2)?;
602
603 match choice {
604 0 => Ok(Self::MIN),
605 1 => Ok(Self::MAX),
606 _ => Ok(Self::from_height(u16::arbitrary(u)?)),
607 }
608 }
609}
610
611#[cfg(feature = "arbitrary")]
612impl<'a> Arbitrary<'a> for NumberOf512Seconds {
613 fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
614 let choice = u.int_in_range(0..=2)?;
615
616 match choice {
617 0 => Ok(Self::MIN),
618 1 => Ok(Self::MAX),
619 _ => Ok(Self::from_512_second_intervals(u16::arbitrary(u)?)),
620 }
621 }
622}
623
624#[cfg(test)]
625mod tests {
626 #[cfg(feature = "alloc")]
627 use alloc::format;
628
629 use super::*;
630 use crate::{BlockHeight, BlockTime};
631
632 const MAXIMUM_ENCODABLE_SECONDS: u32 = u16::MAX as u32 * 512;
633
634 #[test]
635 #[cfg(feature = "alloc")]
636 fn display_and_alternate() {
637 let lock_by_height = LockTime::from_height(10);
638 let lock_by_time = LockTime::from_512_second_intervals(70);
639
640 assert_eq!(format!("{}", lock_by_height), "10");
641 assert_eq!(format!("{:#}", lock_by_height), "block-height 10");
642 assert!(!format!("{:?}", lock_by_height).is_empty());
643
644 assert_eq!(format!("{}", lock_by_time), "70");
645 assert_eq!(format!("{:#}", lock_by_time), "block-time 70 (512 second intervals)");
646 assert!(!format!("{:?}", lock_by_time).is_empty());
647 }
648
649 #[test]
650 fn from_seconds_ceil_and_floor() {
651 let time = 70 * 512 + 1;
652 let lock_by_time = LockTime::from_seconds_ceil(time).unwrap();
653 assert_eq!(lock_by_time, LockTime::from_512_second_intervals(71));
654
655 let lock_by_time = LockTime::from_seconds_floor(time).unwrap();
656 assert_eq!(lock_by_time, LockTime::from_512_second_intervals(70));
657
658 let mut max_time = 0xffff * 512;
659 assert_eq!(LockTime::from_seconds_ceil(max_time), LockTime::from_seconds_floor(max_time));
660 max_time += 512;
661 assert!(LockTime::from_seconds_ceil(max_time).is_err());
662 assert!(LockTime::from_seconds_floor(max_time).is_err());
663 }
664
665 #[test]
666 fn parses_correctly_to_height_or_time() {
667 let height1 = NumberOfBlocks::from(10);
668 let height2 = NumberOfBlocks::from(11);
669 let time1 = NumberOf512Seconds::from_512_second_intervals(70);
670 let time2 = NumberOf512Seconds::from_512_second_intervals(71);
671
672 let lock_by_height1 = LockTime::from(height1);
673 let lock_by_height2 = LockTime::from(height2);
674 let lock_by_time1 = LockTime::from(time1);
675 let lock_by_time2 = LockTime::from(time2);
676
677 assert!(lock_by_height1.is_block_height());
678 assert!(!lock_by_height1.is_block_time());
679
680 assert!(!lock_by_time1.is_block_height());
681 assert!(lock_by_time1.is_block_time());
682
683 assert!(lock_by_height1.is_same_unit(lock_by_height2));
685 assert!(!lock_by_height1.is_same_unit(lock_by_time1));
686 assert!(lock_by_time1.is_same_unit(lock_by_time2));
687 assert!(!lock_by_time1.is_same_unit(lock_by_height1));
688 }
689
690 #[test]
691 fn height_correctly_implies() {
692 let height = NumberOfBlocks::from(10);
693 let lock_by_height = LockTime::from(height);
694
695 assert!(!lock_by_height.is_implied_by(LockTime::from(NumberOfBlocks::from(9))));
696 assert!(lock_by_height.is_implied_by(LockTime::from(NumberOfBlocks::from(10))));
697 assert!(lock_by_height.is_implied_by(LockTime::from(NumberOfBlocks::from(11))));
698 }
699
700 #[test]
701 fn time_correctly_implies() {
702 let time = NumberOf512Seconds::from_512_second_intervals(70);
703 let lock_by_time = LockTime::from(time);
704
705 assert!(!lock_by_time
706 .is_implied_by(LockTime::from(NumberOf512Seconds::from_512_second_intervals(69))));
707 assert!(lock_by_time
708 .is_implied_by(LockTime::from(NumberOf512Seconds::from_512_second_intervals(70))));
709 assert!(lock_by_time
710 .is_implied_by(LockTime::from(NumberOf512Seconds::from_512_second_intervals(71))));
711 }
712
713 #[test]
714 fn sequence_correctly_implies() {
715 let height = NumberOfBlocks::from(10);
716 let time = NumberOf512Seconds::from_512_second_intervals(70);
717
718 let lock_by_height = LockTime::from(height);
719 let lock_by_time = LockTime::from(time);
720
721 let seq_height = Sequence::from(lock_by_height);
722 let seq_time = Sequence::from(lock_by_time);
723
724 assert!(lock_by_height.is_implied_by_sequence(seq_height));
725 assert!(!lock_by_height.is_implied_by_sequence(seq_time));
726
727 assert!(lock_by_time.is_implied_by_sequence(seq_time));
728 assert!(!lock_by_time.is_implied_by_sequence(seq_height));
729
730 let disabled_sequence = Sequence::from_consensus(1 << 31);
731 assert!(!lock_by_height.is_implied_by_sequence(disabled_sequence));
732 assert!(!lock_by_time.is_implied_by_sequence(disabled_sequence));
733 }
734
735 #[test]
736 fn incorrect_units_do_not_imply() {
737 let time = NumberOf512Seconds::from_512_second_intervals(70);
738 let height = NumberOfBlocks::from(10);
739
740 let lock_by_time = LockTime::from(time);
741 assert!(!lock_by_time.is_implied_by(LockTime::from(height)));
742 }
743
744 #[test]
745 fn consensus_round_trip() {
746 assert!(LockTime::from_consensus(1 << 31).is_err());
747 assert!(LockTime::from_consensus(1 << 30).is_ok());
748 assert_eq!(LockTime::from_consensus(65536), LockTime::from_consensus(0));
750
751 for val in [0u32, 1, 1000, 65535] {
752 let seq = Sequence::from_consensus(val);
753 let lt = LockTime::from_consensus(val).unwrap();
754 assert_eq!(lt.to_consensus_u32(), val);
755 assert_eq!(lt.to_sequence(), seq);
756 assert_eq!(LockTime::from_sequence(seq).unwrap().to_sequence(), seq);
757
758 let seq = Sequence::from_consensus(val + (1 << 22));
759 let lt = LockTime::from_consensus(val + (1 << 22)).unwrap();
760 assert_eq!(lt.to_consensus_u32(), val + (1 << 22));
761 assert_eq!(lt.to_sequence(), seq);
762 assert_eq!(LockTime::from_sequence(seq).unwrap().to_sequence(), seq);
763 }
764 }
765
766 #[test]
767 #[cfg(feature = "alloc")]
768 fn disabled_locktime_error() {
769 let disabled_sequence = Sequence::from_consensus(1 << 31);
770 let err = LockTime::try_from(disabled_sequence).unwrap_err();
771
772 assert_eq!(err.disabled_locktime_value(), 1 << 31);
773 assert!(!format!("{}", err).is_empty());
774 }
775
776 #[test]
777 #[cfg(feature = "alloc")]
778 fn incompatible_height_error() {
779 let mined_at = BlockHeight::from_u32(700_000);
781 let chain_tip = BlockHeight::from_u32(800_000);
782
783 let lock_by_time = LockTime::from_512_second_intervals(70); let err = lock_by_time.is_satisfied_by_height(chain_tip, mined_at).unwrap_err();
785
786 let expected_time = NumberOf512Seconds::from_512_second_intervals(70);
787 assert_eq!(err, IsSatisfiedByHeightError::Incompatible(expected_time));
788 assert!(!format!("{}", err).is_empty());
789 }
790
791 #[test]
792 #[cfg(feature = "alloc")]
793 fn invalid_height_error() {
794 let mined_at = BlockHeight::from_u32(900_000);
796 let chain_tip = BlockHeight::from_u32(800_000);
797
798 let block_count = NumberOfBlocks::from_height(70); let err = block_count.is_satisfied_by(chain_tip, mined_at).unwrap_err();
800
801 assert!(matches!(err, InvalidHeightError { chain_tip: _, utxo_mined_at: _ }));
802 }
803
804 #[test]
805 #[cfg(feature = "alloc")]
806 fn incompatible_time_error() {
807 let mined_at = BlockMtp::from_u32(1_234_567_890);
809 let chain_tip = BlockMtp::from_u32(1_600_000_000);
810
811 let lock_by_height = LockTime::from_height(10); let err = lock_by_height.is_satisfied_by_time(chain_tip, mined_at).unwrap_err();
813
814 let expected_height = NumberOfBlocks::from(10);
815 assert_eq!(err, IsSatisfiedByTimeError::Incompatible(expected_height));
816 assert!(!format!("{}", err).is_empty());
817 }
818
819 #[test]
820 #[cfg(feature = "alloc")]
821 fn invalid_time_error() {
822 let mined_at = BlockMtp::from_u32(1_734_567_890);
824 let chain_tip = BlockMtp::from_u32(1_600_000_000);
825
826 let time_interval = NumberOf512Seconds::from_512_second_intervals(10); let err = time_interval.is_satisfied_by(chain_tip, mined_at).unwrap_err();
828
829 assert!(matches!(err, InvalidTimeError { chain_tip: _, utxo_mined_at: _ }));
830 }
831
832 #[test]
833 fn test_locktime_chain_state() {
834 fn generate_timestamps(start: u32, step: u16) -> [BlockTime; 11] {
835 let mut timestamps = [BlockTime::from_u32(0); 11];
836 for (i, ts) in timestamps.iter_mut().enumerate() {
837 *ts = BlockTime::from_u32(start.saturating_sub((step * i as u16).into()));
838 }
839 timestamps
840 }
841
842 let timestamps: [BlockTime; 11] = generate_timestamps(1_600_000_000, 200);
843 let utxo_timestamps: [BlockTime; 11] = generate_timestamps(1_599_000_000, 200);
844
845 let chain_height = BlockHeight::from_u32(100);
846 let chain_mtp = BlockMtp::new(timestamps);
847 let utxo_height = BlockHeight::from_u32(80);
848 let utxo_mtp = BlockMtp::new(utxo_timestamps);
849
850 let lock1 = LockTime::Blocks(NumberOfBlocks::from(10));
851 assert!(lock1.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp).unwrap());
852
853 let lock2 = LockTime::Blocks(NumberOfBlocks::from(21));
854 assert!(lock2.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp).unwrap());
855
856 let lock3 = LockTime::Time(NumberOf512Seconds::from_512_second_intervals(10));
857 assert!(lock3.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp).unwrap());
858
859 let lock4 = LockTime::Time(NumberOf512Seconds::from_512_second_intervals(20000));
860 assert!(!lock4.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp).unwrap());
861
862 assert!(LockTime::ZERO
863 .is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp)
864 .unwrap());
865 assert!(LockTime::from_512_second_intervals(0)
866 .is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp)
867 .unwrap());
868
869 let lock6 = LockTime::from_seconds_floor(5000).unwrap();
870 assert!(lock6.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp).unwrap());
871
872 let max_height_lock = LockTime::Blocks(NumberOfBlocks::MAX);
873 assert!(!max_height_lock
874 .is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp)
875 .unwrap());
876
877 let max_time_lock = LockTime::Time(NumberOf512Seconds::MAX);
878 assert!(!max_time_lock
879 .is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp)
880 .unwrap());
881
882 let max_chain_height = BlockHeight::from_u32(u32::MAX);
883 let max_chain_mtp = BlockMtp::new(generate_timestamps(u32::MAX, 100));
884 let max_utxo_height = BlockHeight::MAX;
885 let max_utxo_mtp = max_chain_mtp;
886 assert!(!max_height_lock
887 .is_satisfied_by(max_chain_height, max_chain_mtp, max_utxo_height, max_utxo_mtp)
888 .unwrap());
889 assert!(!max_time_lock
890 .is_satisfied_by(max_chain_height, max_chain_mtp, max_utxo_height, max_utxo_mtp)
891 .unwrap());
892 }
893
894 #[test]
895 #[allow(deprecated_in_future)]
896 fn sanity_check() {
897 assert_eq!(LockTime::from(NumberOfBlocks::MAX).to_consensus_u32(), u32::from(u16::MAX));
898 assert_eq!(
899 NumberOf512Seconds::from_512_second_intervals(100).to_512_second_intervals(),
900 100u16
901 );
902 assert_eq!(
903 LockTime::from(NumberOf512Seconds::from_512_second_intervals(100)).to_consensus_u32(),
904 4_194_404u32
905 ); assert_eq!(NumberOf512Seconds::from_512_second_intervals(1).to_seconds(), 512);
907 }
908
909 #[test]
910 fn from_512_second_intervals_roundtrip() {
911 let intervals = 100_u16;
912 let locktime = NumberOf512Seconds::from_512_second_intervals(intervals);
913 assert_eq!(locktime.to_512_second_intervals(), intervals);
914 }
915
916 #[test]
917 fn from_seconds_ceil_success() {
918 let actual = NumberOf512Seconds::from_seconds_ceil(100).unwrap();
919 let expected = NumberOf512Seconds(1_u16);
920 assert_eq!(actual, expected);
921 }
922
923 #[test]
924 fn from_seconds_ceil_with_maximum_encodable_seconds_success() {
925 let actual = NumberOf512Seconds::from_seconds_ceil(MAXIMUM_ENCODABLE_SECONDS).unwrap();
926 let expected = NumberOf512Seconds(u16::MAX);
927 assert_eq!(actual, expected);
928 }
929
930 #[test]
931 fn from_seconds_ceil_causes_time_overflow_error() {
932 let result = NumberOf512Seconds::from_seconds_ceil(MAXIMUM_ENCODABLE_SECONDS + 1);
933 assert!(result.is_err());
934 }
935
936 #[test]
937 fn from_seconds_floor_success() {
938 let actual = NumberOf512Seconds::from_seconds_floor(100).unwrap();
939 let expected = NumberOf512Seconds(0_u16);
940 assert_eq!(actual, expected);
941 }
942
943 #[test]
944 fn from_seconds_floor_with_exact_interval() {
945 let actual = NumberOf512Seconds::from_seconds_floor(512).unwrap();
946 let expected = NumberOf512Seconds(1_u16);
947 assert_eq!(actual, expected);
948 }
949
950 #[test]
951 fn from_seconds_floor_with_maximum_encodable_seconds_success() {
952 let actual =
953 NumberOf512Seconds::from_seconds_floor(MAXIMUM_ENCODABLE_SECONDS + 511).unwrap();
954 let expected = NumberOf512Seconds(u16::MAX);
955 assert_eq!(actual, expected);
956 }
957
958 #[test]
959 fn from_seconds_floor_causes_time_overflow_error() {
960 let result = NumberOf512Seconds::from_seconds_floor(MAXIMUM_ENCODABLE_SECONDS + 512);
961 assert!(result.is_err());
962 }
963
964 fn generate_timestamps(start: u32, step: u16) -> [BlockTime; 11] {
965 let mut timestamps = [BlockTime::from_u32(0); 11];
966 for (i, ts) in timestamps.iter_mut().enumerate() {
967 *ts = BlockTime::from_u32(start.saturating_sub((step * i as u16).into()));
968 }
969 timestamps
970 }
971
972 #[test]
973 fn test_time_chain_state() {
974 use crate::BlockMtp;
975
976 let timestamps: [BlockTime; 11] = generate_timestamps(1_600_000_000, 200);
977 let utxo_timestamps: [BlockTime; 11] = generate_timestamps(1_599_000_000, 200);
978
979 let timestamps2: [BlockTime; 11] = generate_timestamps(1_599_995_119, 200);
980 let utxo_timestamps2: [BlockTime; 11] = generate_timestamps(1_599_990_000, 200);
981
982 let timestamps3: [BlockTime; 11] = generate_timestamps(1_600_050_000, 200);
983 let utxo_timestamps3: [BlockTime; 11] = generate_timestamps(1_599_990_000, 200);
984
985 let time_lock = LockTime::Time(NumberOf512Seconds::from_512_second_intervals(10));
988 let chain_state1 = BlockMtp::new(timestamps);
989 let utxo_state1 = BlockMtp::new(utxo_timestamps);
990 assert!(time_lock.is_satisfied_by_time(chain_state1, utxo_state1).unwrap());
991
992 let chain_state2 = BlockMtp::new(timestamps2);
994 let utxo_state2 = BlockMtp::new(utxo_timestamps2);
995 assert!(!time_lock.is_satisfied_by_time(chain_state2, utxo_state2).unwrap());
996
997 let larger_lock = LockTime::Time(NumberOf512Seconds::from_512_second_intervals(100));
999 let chain_state3 = BlockMtp::new(timestamps3);
1000 let utxo_state3 = BlockMtp::new(utxo_timestamps3);
1001 assert!(larger_lock.is_satisfied_by_time(chain_state3, utxo_state3).unwrap());
1002
1003 let max_time_lock = LockTime::Time(NumberOf512Seconds::MAX);
1005 let chain_state4 = BlockMtp::new(timestamps);
1006 let utxo_state4 = BlockMtp::new(utxo_timestamps);
1007 assert!(!max_time_lock.is_satisfied_by_time(chain_state4, utxo_state4).unwrap());
1008 }
1009
1010 #[test]
1011 fn test_height_chain_state() {
1012 let height_lock = LockTime::Blocks(NumberOfBlocks(10));
1013
1014 let chain_state1 = BlockHeight::from_u32(89);
1016 let utxo_state1 = BlockHeight::from_u32(80);
1017 assert!(height_lock.is_satisfied_by_height(chain_state1, utxo_state1).unwrap());
1018
1019 let chain_state2 = BlockHeight::from_u32(88);
1021 let utxo_state2 = BlockHeight::from_u32(80);
1022 assert!(!height_lock.is_satisfied_by_height(chain_state2, utxo_state2).unwrap());
1023
1024 let max_height_lock = LockTime::Blocks(NumberOfBlocks::MAX);
1026 let chain_state3 = BlockHeight::from_u32(1000);
1027 let utxo_state3 = BlockHeight::from_u32(80);
1028 assert!(!max_height_lock.is_satisfied_by_height(chain_state3, utxo_state3).unwrap());
1029 }
1030
1031 #[test]
1032 fn test_max_height_satisfaction() {
1033 let mined_at = BlockHeight::from_u32(u32::MIN);
1035 let chain_tip = BlockHeight::from_u32(u32::MAX);
1036
1037 let block_height = NumberOfBlocks::from(10); assert!(block_height.is_satisfied_by(chain_tip, mined_at).unwrap());
1039 }
1040}