bitcoin_primitives/
sequence.rs1use core::fmt;
18
19#[cfg(feature = "arbitrary")]
20use arbitrary::{Arbitrary, Unstructured};
21#[cfg(feature = "serde")]
22use serde::{Deserialize, Serialize};
23#[cfg(feature = "alloc")]
24use units::locktime::relative::TimeOverflowError;
25#[cfg(feature = "alloc")]
26use units::parse::{self, PrefixedHexError, UnprefixedHexError};
27
28#[cfg(feature = "alloc")]
29use crate::locktime::relative;
30#[cfg(all(doc, feature = "alloc"))]
31use crate::transaction::Transaction;
32
33#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
35#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
36pub struct Sequence(pub u32);
37
38impl Sequence {
39 pub const MAX: Self = Sequence(0xFFFFFFFF);
43 pub const ZERO: Self = Sequence(0);
47 pub const FINAL: Self = Sequence::MAX;
49 pub const ENABLE_LOCKTIME_NO_RBF: Self = Sequence::MIN_NO_RBF;
52 #[deprecated(since = "TBD", note = "use `ENABLE_LOCKTIME_AND_RBF` instead")]
55 pub const ENABLE_RBF_NO_LOCKTIME: Self = Sequence(0xFFFFFFFD);
56 pub const ENABLE_LOCKTIME_AND_RBF: Self = Sequence(0xFFFFFFFD);
61
62 pub const SIZE: usize = 4; const MIN_NO_RBF: Self = Sequence(0xFFFFFFFE);
73 const LOCK_TIME_DISABLE_FLAG_MASK: u32 = 0x80000000;
75 const LOCK_TYPE_MASK: u32 = 0x00400000;
77
78 #[inline]
80 pub fn enables_absolute_lock_time(&self) -> bool { *self != Sequence::MAX }
81
82 #[inline]
102 pub fn is_final(&self) -> bool { !self.enables_absolute_lock_time() }
103
104 #[inline]
109 pub fn is_rbf(&self) -> bool { *self < Sequence::MIN_NO_RBF }
110
111 #[inline]
113 pub fn is_relative_lock_time(&self) -> bool {
114 self.0 & Sequence::LOCK_TIME_DISABLE_FLAG_MASK == 0
115 }
116
117 #[inline]
119 pub fn is_height_locked(&self) -> bool {
120 self.is_relative_lock_time() & (self.0 & Sequence::LOCK_TYPE_MASK == 0)
121 }
122
123 #[inline]
125 pub fn is_time_locked(&self) -> bool {
126 self.is_relative_lock_time() & (self.0 & Sequence::LOCK_TYPE_MASK > 0)
127 }
128
129 #[cfg(feature = "alloc")]
131 pub fn from_hex(s: &str) -> Result<Self, PrefixedHexError> {
132 let lock_time = parse::hex_u32_prefixed(s)?;
133 Ok(Self::from_consensus(lock_time))
134 }
135
136 #[cfg(feature = "alloc")]
138 pub fn from_unprefixed_hex(s: &str) -> Result<Self, UnprefixedHexError> {
139 let lock_time = parse::hex_u32_unprefixed(s)?;
140 Ok(Self::from_consensus(lock_time))
141 }
142
143 #[inline]
145 pub fn from_height(height: u16) -> Self { Sequence(u32::from(height)) }
146
147 #[inline]
152 pub fn from_512_second_intervals(intervals: u16) -> Self {
153 Sequence(u32::from(intervals) | Sequence::LOCK_TYPE_MASK)
154 }
155
156 #[inline]
161 #[cfg(feature = "alloc")]
162 pub fn from_seconds_floor(seconds: u32) -> Result<Self, TimeOverflowError> {
163 if let Ok(interval) = u16::try_from(seconds / 512) {
164 Ok(Sequence::from_512_second_intervals(interval))
165 } else {
166 Err(TimeOverflowError::new(seconds))
167 }
168 }
169
170 #[inline]
175 #[cfg(feature = "alloc")]
176 pub fn from_seconds_ceil(seconds: u32) -> Result<Self, TimeOverflowError> {
177 if let Ok(interval) = u16::try_from((seconds + 511) / 512) {
178 Ok(Sequence::from_512_second_intervals(interval))
179 } else {
180 Err(TimeOverflowError::new(seconds))
181 }
182 }
183
184 #[inline]
186 pub fn from_consensus(n: u32) -> Self { Sequence(n) }
187
188 #[inline]
190 pub fn to_consensus_u32(self) -> u32 { self.0 }
191
192 #[inline]
194 #[cfg(feature = "alloc")]
195 pub fn to_relative_lock_time(&self) -> Option<relative::LockTime> {
196 use crate::locktime::relative::{Height, LockTime, Time};
197
198 if !self.is_relative_lock_time() {
199 return None;
200 }
201
202 let lock_value = self.low_u16();
203
204 if self.is_time_locked() {
205 Some(LockTime::from(Time::from_512_second_intervals(lock_value)))
206 } else {
207 Some(LockTime::from(Height::from(lock_value)))
208 }
209 }
210
211 #[cfg(feature = "alloc")]
215 fn low_u16(&self) -> u16 { self.0 as u16 }
216}
217
218impl Default for Sequence {
219 fn default() -> Self { Sequence::MAX }
221}
222
223impl From<Sequence> for u32 {
224 fn from(sequence: Sequence) -> u32 { sequence.0 }
225}
226
227impl fmt::Display for Sequence {
228 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
229}
230
231impl fmt::LowerHex for Sequence {
232 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(&self.0, f) }
233}
234#[cfg(feature = "alloc")]
235internals::impl_to_hex_from_lower_hex!(Sequence, |sequence: &Sequence| {
236 8 - sequence.0.leading_zeros() as usize / 4
237});
238
239impl fmt::UpperHex for Sequence {
240 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::UpperHex::fmt(&self.0, f) }
241}
242
243impl fmt::Debug for Sequence {
244 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
245 write!(f, "Sequence({:#010x})", self.0)
247 }
248}
249
250#[cfg(feature = "alloc")]
251units::impl_parse_str_from_int_infallible!(Sequence, u32, from_consensus);
252
253#[cfg(feature = "arbitrary")]
254#[cfg(feature = "alloc")]
255impl<'a> Arbitrary<'a> for Sequence {
256 fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
257 let choice = u.int_in_range(0..=8)?;
259 match choice {
260 0 => Ok(Sequence::MAX),
261 1 => Ok(Sequence::ZERO),
262 2 => Ok(Sequence::MIN_NO_RBF),
263 3 => Ok(Sequence::ENABLE_LOCKTIME_AND_RBF),
264 4 => Ok(Sequence::from_consensus(relative::Height::MIN.to_consensus_u32())),
265 5 => Ok(Sequence::from_consensus(relative::Height::MAX.to_consensus_u32())),
266 6 => Ok(Sequence::from_consensus(relative::Time::MIN.to_consensus_u32())),
267 7 => Ok(Sequence::from_consensus(relative::Time::MAX.to_consensus_u32())),
268 _ => Ok(Sequence(u.arbitrary()?)),
269 }
270 }
271}
272
273#[cfg(feature = "arbitrary")]
274#[cfg(not(feature = "alloc"))]
275impl<'a> Arbitrary<'a> for Sequence {
276 fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
277 let choice = u.int_in_range(0..=4)?;
279 match choice {
280 0 => Ok(Sequence::MAX),
281 1 => Ok(Sequence::ZERO),
282 2 => Ok(Sequence::MIN_NO_RBF),
283 3 => Ok(Sequence::ENABLE_LOCKTIME_AND_RBF),
284 _ => Ok(Sequence(u.arbitrary()?)),
285 }
286 }
287}
288
289#[cfg(test)]
290#[cfg(feature = "alloc")]
291mod tests {
292 use super::*;
293
294 const MAXIMUM_ENCODABLE_SECONDS: u32 = u16::MAX as u32 * 512;
295
296 #[test]
297 fn from_seconds_floor_success() {
298 let expected = Sequence::from_hex("0x0040ffff").unwrap();
299 let actual = Sequence::from_seconds_floor(MAXIMUM_ENCODABLE_SECONDS + 511).unwrap();
300 assert_eq!(actual, expected);
301 }
302
303 #[test]
304 fn from_seconds_floor_causes_overflow_error() {
305 assert!(Sequence::from_seconds_floor(MAXIMUM_ENCODABLE_SECONDS + 512).is_err());
306 }
307
308 #[test]
309 fn from_seconds_ceil_success() {
310 let expected = Sequence::from_hex("0x0040ffff").unwrap();
311 let actual = Sequence::from_seconds_ceil(MAXIMUM_ENCODABLE_SECONDS - 511).unwrap();
312 assert_eq!(actual, expected);
313 }
314
315 #[test]
316 fn from_seconds_ceil_causes_overflow_error() {
317 assert!(Sequence::from_seconds_ceil(MAXIMUM_ENCODABLE_SECONDS + 1).is_err());
318 }
319}