#[cfg(feature = "encoding")]
use core::convert::Infallible;
use core::fmt;
#[cfg(feature = "arbitrary")]
use arbitrary::{Arbitrary, Unstructured};
#[cfg(feature = "encoding")]
use internals::write_err;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use crate::locktime::relative::error::TimeOverflowError;
use crate::locktime::relative::{self, NumberOf512Seconds};
use crate::parse_int::{self, PrefixedHexError, UnprefixedHexError};
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Sequence(pub u32);
impl Sequence {
pub const MAX: Self = Self(0xFFFF_FFFF);
pub const ZERO: Self = Self(0);
pub const FINAL: Self = Self::MAX;
pub const ENABLE_LOCKTIME_NO_RBF: Self = Self::MIN_NO_RBF;
#[deprecated(since = "1.0.0-rc.0", note = "use `ENABLE_LOCKTIME_AND_RBF` instead")]
pub const ENABLE_RBF_NO_LOCKTIME: Self = Self(0xFFFF_FFFD);
pub const ENABLE_LOCKTIME_AND_RBF: Self = Self(0xFFFF_FFFD);
pub const SIZE: usize = 4;
const MIN_NO_RBF: Self = Self(0xFFFF_FFFE);
const LOCK_TIME_DISABLE_FLAG_MASK: u32 = 0x8000_0000;
pub(super) const LOCK_TYPE_MASK: u32 = 0x0040_0000;
#[inline]
pub fn enables_absolute_lock_time(self) -> bool { self != Self::MAX }
#[inline]
pub fn is_final(self) -> bool { !self.enables_absolute_lock_time() }
#[inline]
pub fn is_rbf(self) -> bool { self < Self::MIN_NO_RBF }
#[inline]
pub fn is_relative_lock_time(self) -> bool { self.0 & Self::LOCK_TIME_DISABLE_FLAG_MASK == 0 }
#[inline]
pub fn is_height_locked(self) -> bool {
self.is_relative_lock_time() && (self.0 & Self::LOCK_TYPE_MASK == 0)
}
#[inline]
pub fn is_time_locked(self) -> bool {
self.is_relative_lock_time() && (self.0 & Self::LOCK_TYPE_MASK > 0)
}
#[inline]
pub fn from_hex(s: &str) -> Result<Self, PrefixedHexError> {
let lock_time = parse_int::hex_u32_prefixed(s)?;
Ok(Self::from_consensus(lock_time))
}
#[inline]
pub fn from_unprefixed_hex(s: &str) -> Result<Self, UnprefixedHexError> {
let lock_time = parse_int::hex_u32_unprefixed(s)?;
Ok(Self::from_consensus(lock_time))
}
#[inline]
pub fn from_height(height: u16) -> Self { Self(u32::from(height)) }
#[inline]
pub fn from_512_second_intervals(intervals: u16) -> Self {
Self(u32::from(intervals) | Self::LOCK_TYPE_MASK)
}
#[inline]
pub fn from_seconds_floor(seconds: u32) -> Result<Self, TimeOverflowError> {
let intervals = NumberOf512Seconds::from_seconds_floor(seconds)?;
Ok(Self::from_512_second_intervals(intervals.to_512_second_intervals()))
}
#[inline]
pub fn from_seconds_ceil(seconds: u32) -> Result<Self, TimeOverflowError> {
let intervals = NumberOf512Seconds::from_seconds_ceil(seconds)?;
Ok(Self::from_512_second_intervals(intervals.to_512_second_intervals()))
}
#[inline]
pub fn from_consensus(n: u32) -> Self { Self(n) }
#[inline]
pub const fn to_consensus_u32(self) -> u32 { self.0 }
#[cfg(feature = "alloc")]
#[inline]
#[deprecated(since = "1.0.0-rc.0", note = "use `format!(\"{var:x}\")` instead")]
pub fn to_hex(self) -> alloc::string::String { alloc::format!("{:x}", self) }
#[inline]
pub fn to_relative_lock_time(self) -> Option<relative::LockTime> {
use crate::locktime::relative::{LockTime, NumberOfBlocks};
if !self.is_relative_lock_time() {
return None;
}
let lock_value = self.low_u16();
if self.is_time_locked() {
Some(LockTime::from(NumberOf512Seconds::from_512_second_intervals(lock_value)))
} else {
Some(LockTime::from(NumberOfBlocks::from(lock_value)))
}
}
#[inline]
const fn low_u16(self) -> u16 { self.0 as u16 }
}
crate::internal_macros::impl_fmt_traits_for_u32_wrapper!(Sequence);
impl Default for Sequence {
#[inline]
fn default() -> Self { Self::MAX }
}
impl From<Sequence> for u32 {
#[inline]
fn from(sequence: Sequence) -> Self { sequence.0 }
}
impl fmt::Display for Sequence {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
}
impl fmt::Debug for Sequence {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Sequence({:#010x})", self.0)
}
}
#[cfg(feature = "alloc")]
parse_int::impl_parse_str_from_int_infallible!(Sequence, u32, from_consensus);
#[cfg(feature = "encoding")]
encoding::encoder_newtype_exact! {
pub struct SequenceEncoder<'e>(encoding::ArrayEncoder<4>);
}
#[cfg(feature = "encoding")]
impl encoding::Encodable for Sequence {
type Encoder<'e> = SequenceEncoder<'e>;
fn encoder(&self) -> Self::Encoder<'_> {
SequenceEncoder::new(encoding::ArrayEncoder::without_length_prefix(
self.to_consensus_u32().to_le_bytes(),
))
}
}
#[cfg(feature = "encoding")]
pub struct SequenceDecoder(encoding::ArrayDecoder<4>);
#[cfg(feature = "encoding")]
impl Default for SequenceDecoder {
fn default() -> Self { Self::new() }
}
#[cfg(feature = "encoding")]
impl SequenceDecoder {
pub const fn new() -> Self { Self(encoding::ArrayDecoder::new()) }
}
#[cfg(feature = "encoding")]
impl encoding::Decoder for SequenceDecoder {
type Output = Sequence;
type Error = SequenceDecoderError;
#[inline]
fn push_bytes(&mut self, bytes: &mut &[u8]) -> Result<bool, Self::Error> {
self.0.push_bytes(bytes).map_err(SequenceDecoderError)
}
#[inline]
fn end(self) -> Result<Self::Output, Self::Error> {
let n = u32::from_le_bytes(self.0.end().map_err(SequenceDecoderError)?);
Ok(Sequence::from_consensus(n))
}
#[inline]
fn read_limit(&self) -> usize { self.0.read_limit() }
}
#[cfg(feature = "encoding")]
impl encoding::Decodable for Sequence {
type Decoder = SequenceDecoder;
fn decoder() -> Self::Decoder { SequenceDecoder(encoding::ArrayDecoder::<4>::new()) }
}
#[cfg(feature = "encoding")]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SequenceDecoderError(encoding::UnexpectedEofError);
#[cfg(feature = "encoding")]
impl From<Infallible> for SequenceDecoderError {
fn from(never: Infallible) -> Self { match never {} }
}
#[cfg(feature = "encoding")]
impl fmt::Display for SequenceDecoderError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write_err!(f, "sequence decoder error"; self.0)
}
}
#[cfg(all(feature = "std", feature = "encoding"))]
impl std::error::Error for SequenceDecoderError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { Some(&self.0) }
}
#[cfg(feature = "arbitrary")]
#[cfg(feature = "alloc")]
impl<'a> Arbitrary<'a> for Sequence {
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
let choice = u.int_in_range(0..=8)?;
match choice {
0 => Ok(Self::MAX),
1 => Ok(Self::ZERO),
2 => Ok(Self::MIN_NO_RBF),
3 => Ok(Self::ENABLE_LOCKTIME_AND_RBF),
4 => Ok(Self::from_consensus(u32::from(relative::NumberOfBlocks::MIN.to_height()))),
5 => Ok(Self::from_consensus(u32::from(relative::NumberOfBlocks::MAX.to_height()))),
6 => Ok(Self::from_consensus(
Self::LOCK_TYPE_MASK
| u32::from(relative::NumberOf512Seconds::MIN.to_512_second_intervals()),
)),
7 => Ok(Self::from_consensus(
Self::LOCK_TYPE_MASK
| u32::from(relative::NumberOf512Seconds::MAX.to_512_second_intervals()),
)),
_ => Ok(Self(u.arbitrary()?)),
}
}
}
#[cfg(feature = "arbitrary")]
#[cfg(not(feature = "alloc"))]
impl<'a> Arbitrary<'a> for Sequence {
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
let choice = u.int_in_range(0..=4)?;
match choice {
0 => Ok(Sequence::MAX),
1 => Ok(Sequence::ZERO),
2 => Ok(Sequence::MIN_NO_RBF),
3 => Ok(Sequence::ENABLE_LOCKTIME_AND_RBF),
_ => Ok(Sequence(u.arbitrary()?)),
}
}
}
#[cfg(test)]
mod tests {
#[cfg(feature = "alloc")]
use alloc::format;
#[cfg(feature = "encoding")]
use encoding::Decoder as _;
#[cfg(all(feature = "encoding", feature = "alloc"))]
use encoding::UnexpectedEofError;
use super::*;
const MAXIMUM_ENCODABLE_SECONDS: u32 = u16::MAX as u32 * 512;
#[test]
fn from_seconds_floor_success() {
let expected = Sequence::from_hex("0x0040ffff").unwrap();
let actual = Sequence::from_seconds_floor(MAXIMUM_ENCODABLE_SECONDS + 511).unwrap();
assert_eq!(actual, expected);
}
#[test]
fn from_seconds_floor_causes_overflow_error() {
assert!(Sequence::from_seconds_floor(MAXIMUM_ENCODABLE_SECONDS + 512).is_err());
}
#[test]
fn from_seconds_ceil_success() {
let expected = Sequence::from_hex("0x0040ffff").unwrap();
let actual = Sequence::from_seconds_ceil(MAXIMUM_ENCODABLE_SECONDS - 511).unwrap();
assert_eq!(actual, expected);
}
#[test]
fn from_seconds_ceil_causes_overflow_error() {
assert!(Sequence::from_seconds_ceil(MAXIMUM_ENCODABLE_SECONDS + 1).is_err());
}
#[test]
fn sequence_properties() {
let seq_max = Sequence(0xFFFF_FFFF);
let seq_no_rbf = Sequence(0xFFFF_FFFE);
let seq_rbf = Sequence(0xFFFF_FFFD);
assert!(seq_max.is_final());
assert!(!seq_no_rbf.is_final());
assert!(seq_no_rbf.enables_absolute_lock_time());
assert!(!seq_max.enables_absolute_lock_time());
assert!(seq_rbf.is_rbf());
assert!(!seq_no_rbf.is_rbf());
let seq_relative = Sequence(0x7FFF_FFFF);
assert!(seq_relative.is_relative_lock_time());
assert!(!seq_max.is_relative_lock_time());
let seq_height_locked = Sequence(0x0039_9999);
let seq_time_locked = Sequence(0x0040_0000);
assert!(seq_height_locked.is_height_locked());
assert!(seq_time_locked.is_time_locked());
assert!(!seq_time_locked.is_height_locked());
assert!(!seq_height_locked.is_time_locked());
}
#[test]
#[cfg(feature = "alloc")]
fn sequence_formatting() {
let sequence = Sequence(0x7FFF_FFFF);
assert_eq!(format!("{:x}", sequence), "7fffffff");
assert_eq!(format!("{:X}", sequence), "7FFFFFFF");
let sequence_u32: u32 = sequence.into();
assert_eq!(sequence_u32, 0x7FFF_FFFF);
}
#[test]
#[cfg(feature = "alloc")]
fn sequence_display() {
use alloc::string::ToString;
let sequence = Sequence(0x7FFF_FFFF);
let want: u32 = 0x7FFF_FFFF;
assert_eq!(format!("{}", sequence), want.to_string());
}
#[test]
#[cfg(feature = "alloc")]
fn sequence_unprefixed_hex_roundtrip() {
let sequence = Sequence(0x7FFF_FFFF);
let hex_str = format!("{:x}", sequence);
assert_eq!(hex_str, "7fffffff");
let roundtrip = Sequence::from_unprefixed_hex(&hex_str).unwrap();
assert_eq!(sequence, roundtrip);
}
#[test]
fn sequence_from_height() {
assert_eq!(Sequence::from_height(0), Sequence(0));
assert_eq!(Sequence::from_height(1), Sequence(1));
assert_eq!(Sequence::from_height(0x7FFF), Sequence(0x7FFF));
assert_eq!(Sequence::from_height(0xFFFF), Sequence(0xFFFF));
let step = 512;
for v in (0..=u16::MAX).step_by(step) {
assert_eq!(Sequence::from_height(v), Sequence(v.into()));
}
}
#[test]
#[cfg(all(feature = "encoding", feature = "alloc"))]
fn sequence_decoding_error() {
let bytes = [0xff, 0xff, 0xff];
let mut decoder = SequenceDecoder::default();
assert!(decoder.push_bytes(&mut bytes.as_slice()).unwrap());
let error = decoder.end().unwrap_err();
assert!(matches!(error, SequenceDecoderError(UnexpectedEofError { .. })));
}
}