sapio_base/
timelocks.rs

1// Copyright Judica, Inc 2021
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4//  License, v. 2.0. If a copy of the MPL was not distributed with this
5//  file, You can obtain one at https://mozilla.org/MPL/2.0/.
6
7use super::Clause;
8use schemars::JsonSchema;
9use serde::{Deserialize, Serialize};
10use std::convert::TryFrom;
11use std::convert::TryInto;
12use std::default::Default;
13use std::fmt;
14use std::marker::PhantomData;
15use std::time::Duration;
16/// Error in Creating a LockTime
17#[derive(Debug)]
18pub enum LockTimeError {
19    /// Duration escapes bound of valid timestamps
20    DurationTooLong(Duration),
21    /// Time was too far in the past, would be interpreted as non-timestamp
22    TimeTooFarInPast(Duration),
23    /// height is too high (beyond 500_000_000), interpreted as timestamp
24    HeightTooHigh(u32),
25    /// sequence type is unknown
26    UnknownSeqType(u32),
27}
28
29/// Type Tags used for creating lock time variants. The module lets us keep them
30/// public while not polluting the name space.
31pub mod type_tags {
32    /// If the type is absolute or relative
33    pub trait Absolutivity {
34        /// true if type is absolute
35        const IS_ABSOLUTE: bool;
36    }
37    ///if the type is height or time
38    pub trait TimeType {
39        /// true if type is height
40        const IS_HEIGHT: bool;
41    }
42    use super::*;
43    /// Type Tag for Realtive
44    #[derive(JsonSchema, Serialize, Deserialize, Copy, Clone, PartialOrd, Ord, Eq, PartialEq)]
45    pub struct Rel;
46    /// Type Tag for Absolute
47    #[derive(JsonSchema, Serialize, Deserialize, Copy, Clone, PartialOrd, Ord, Eq, PartialEq)]
48    pub struct Abs;
49    /// Type Tag for Height
50    #[derive(JsonSchema, Serialize, Deserialize, Copy, Clone, PartialOrd, Ord, Eq, PartialEq)]
51    pub struct Height;
52    /// Type Tag for Median Time Passed
53    #[derive(JsonSchema, Serialize, Deserialize, Copy, Clone, PartialOrd, Ord, Eq, PartialEq)]
54    pub struct MTP;
55}
56use type_tags::*;
57
58/// LockTime represents either a nLockTime or a Sequence field.
59/// They are represented generically in the same type
60#[derive(JsonSchema, Serialize, Deserialize, Copy, Clone, PartialOrd, Ord, Eq, PartialEq)]
61#[serde(transparent)]
62pub struct LockTime<RelOrAbs: Absolutivity, HeightOrTime: TimeType>(
63    u32,
64    #[serde(skip)] PhantomData<(RelOrAbs, HeightOrTime)>,
65);
66#[derive(JsonSchema, Serialize, Deserialize, Copy, Clone, PartialOrd, Ord, Eq, PartialEq)]
67/// # Any Relative Time Lock
68/// Represents a type which can be either type of relative lock
69pub enum AnyRelTimeLock {
70    /// # Relative Height
71    /// in number of blocks
72    RH(RelHeight),
73    /// # Relative Time
74    /// in chunks of 512 seconds
75    RT(RelTime),
76}
77
78#[derive(JsonSchema, Serialize, Deserialize, Copy, Clone, PartialOrd, Ord, Eq, PartialEq)]
79/// # Any Absolute Time Lock
80/// Represents a type which can be either type of absolute lock
81pub enum AnyAbsTimeLock {
82    /// # Absolute Height
83    /// in exact block height
84    AH(AbsHeight),
85    /// # Absolute Time
86    /// in unix time stamp since epoch
87    AT(AbsTime),
88}
89#[derive(JsonSchema, Serialize, Deserialize, Copy, Clone)]
90/// # Any Time Lock (Relative, Absolute) x (Height, Time)
91/// Represents a type which can be any type of lock
92pub enum AnyTimeLock {
93    /// # Relative
94    R(AnyRelTimeLock),
95    /// # Absolute
96    A(AnyAbsTimeLock),
97}
98
99/// Helpful Aliases for specific concrete lock times
100mod alias {
101    use super::*;
102    /// LockTime for Relative Height
103    pub type RelHeight = LockTime<Rel, Height>;
104    /// LockTime for Relative MTP
105    pub type RelTime = LockTime<Rel, MTP>;
106    /// LockTime for Absolute Height
107    pub type AbsHeight = LockTime<Abs, Height>;
108    /// LockTime for Absolute MTP
109    pub type AbsTime = LockTime<Abs, MTP>;
110    /// Maximum Date
111    pub const BIG_PAST_DATE: AbsTime = LockTime(1_600_000_000u32, PhantomData);
112    /// Minimum Date
113    pub const START_OF_TIME: AbsTime = LockTime(500_000_000, PhantomData);
114}
115pub use alias::*;
116
117mod trait_impls {
118    use super::*;
119    impl Absolutivity for Rel {
120        const IS_ABSOLUTE: bool = false;
121    }
122    impl Absolutivity for Abs {
123        const IS_ABSOLUTE: bool = true;
124    }
125    impl TimeType for Height {
126        const IS_HEIGHT: bool = true;
127    }
128    impl TimeType for MTP {
129        const IS_HEIGHT: bool = false;
130    }
131
132    impl<A, TT> LockTime<A, TT>
133    where
134        A: Absolutivity,
135        TT: TimeType,
136    {
137        /// get inner representation
138        pub fn get(&self) -> u32 {
139            self.0
140        }
141    }
142    impl AnyRelTimeLock {
143        /// get inner representation
144        pub fn get(&self) -> u32 {
145            match self {
146                AnyRelTimeLock::RH(u) => u.get(),
147                AnyRelTimeLock::RT(u) => u.get(),
148            }
149        }
150    }
151
152    impl AnyAbsTimeLock {
153        /// get inner representation
154        pub fn get(&self) -> u32 {
155            match self {
156                AnyAbsTimeLock::AH(u) => u.get(),
157                AnyAbsTimeLock::AT(u) => u.get(),
158            }
159        }
160    }
161
162    impl AnyTimeLock {
163        /// get inner representation
164        pub fn get(&self) -> u32 {
165            match self {
166                AnyTimeLock::A(u) => u.get(),
167                AnyTimeLock::R(u) => u.get(),
168            }
169        }
170    }
171
172    impl<A, TT> From<LockTime<A, TT>> for Clause
173    where
174        A: Absolutivity,
175        TT: TimeType,
176    {
177        fn from(lt: LockTime<A, TT>) -> Clause {
178            match (A::IS_ABSOLUTE, TT::IS_HEIGHT) {
179                (true, true) => Clause::After(lt.0),
180                (true, false) => Clause::After(lt.0),
181                (false, true) => Clause::Older(lt.0),
182                (false, false) => Clause::Older(lt.0),
183            }
184        }
185    }
186
187    impl fmt::Display for LockTimeError {
188        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
189            write!(f, "{:?}", self)
190        }
191    }
192    impl std::error::Error for LockTimeError {}
193
194    impl TryFrom<u32> for AbsTime {
195        type Error = LockTimeError;
196        fn try_from(t: u32) -> Result<Self, Self::Error> {
197            if t < START_OF_TIME.get() {
198                Err(LockTimeError::TimeTooFarInPast(Duration::from_secs(
199                    t as u64,
200                )))
201            } else {
202                Ok(Self(t, Default::default()))
203            }
204        }
205    }
206    impl TryFrom<u32> for AbsHeight {
207        type Error = LockTimeError;
208        fn try_from(u: u32) -> Result<Self, Self::Error> {
209            if u < START_OF_TIME.get() {
210                Ok(Self(u, Default::default()))
211            } else {
212                Err(LockTimeError::HeightTooHigh(u))
213            }
214        }
215    }
216    impl From<u16> for RelTime {
217        fn from(u: u16) -> Self {
218            // cast to wider type and then set bit 22 to specify relative time
219            Self((u as u32) | (1 << 22), Default::default())
220        }
221    }
222    impl From<u16> for RelHeight {
223        fn from(u: u16) -> Self {
224            // no bit setting required, direct cast to u32
225            Self(u as u32, Default::default())
226        }
227    }
228
229    impl TryFrom<Duration> for RelTime {
230        type Error = LockTimeError;
231        fn try_from(u: Duration) -> Result<Self, Self::Error> {
232            u16::try_from(u.as_secs() / 512)
233                .or(Err(LockTimeError::DurationTooLong(u)))
234                .map(From::from)
235        }
236    }
237
238    impl TryFrom<Duration> for AbsTime {
239        type Error = LockTimeError;
240        fn try_from(u: Duration) -> Result<Self, Self::Error> {
241            u32::try_from(u.as_secs())
242                .or(Err(LockTimeError::DurationTooLong(u)))?
243                .try_into()
244        }
245    }
246
247    impl From<AnyRelTimeLock> for Clause {
248        fn from(lt: AnyRelTimeLock) -> Self {
249            match lt {
250                AnyRelTimeLock::RH(a) => a.into(),
251                AnyRelTimeLock::RT(a) => a.into(),
252            }
253        }
254    }
255    impl From<AnyAbsTimeLock> for Clause {
256        fn from(lt: AnyAbsTimeLock) -> Self {
257            match lt {
258                AnyAbsTimeLock::AH(a) => a.into(),
259                AnyAbsTimeLock::AT(a) => a.into(),
260            }
261        }
262    }
263    impl From<AnyTimeLock> for Clause {
264        fn from(lt: AnyTimeLock) -> Self {
265            match lt {
266                AnyTimeLock::A(a) => a.into(),
267                AnyTimeLock::R(a) => a.into(),
268            }
269        }
270    }
271
272    impl From<RelTime> for AnyRelTimeLock {
273        fn from(lt: RelTime) -> Self {
274            AnyRelTimeLock::RT(lt)
275        }
276    }
277    impl From<AbsHeight> for AnyAbsTimeLock {
278        fn from(lt: AbsHeight) -> Self {
279            AnyAbsTimeLock::AH(lt)
280        }
281    }
282    impl From<AbsTime> for AnyAbsTimeLock {
283        fn from(lt: AbsTime) -> Self {
284            AnyAbsTimeLock::AT(lt)
285        }
286    }
287
288    impl From<RelHeight> for AnyRelTimeLock {
289        fn from(lt: RelHeight) -> Self {
290            AnyRelTimeLock::RH(lt)
291        }
292    }
293
294    impl From<AnyAbsTimeLock> for AnyTimeLock {
295        fn from(lt: AnyAbsTimeLock) -> Self {
296            AnyTimeLock::A(lt)
297        }
298    }
299    impl From<AnyRelTimeLock> for AnyTimeLock {
300        fn from(lt: AnyRelTimeLock) -> Self {
301            AnyTimeLock::R(lt)
302        }
303    }
304}