1use crate::constants::LOCKTIME_THRESHOLD;
7use crate::types::*;
8#[cfg(feature = "spec-lock")]
9use blvm_spec_lock::spec_locked;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub enum LocktimeType {
14 BlockHeight,
16 Timestamp,
18}
19
20#[inline]
28#[cfg_attr(feature = "spec-lock", spec_locked("5.4.7", "GetLocktimeType"))]
29#[cfg_attr(feature = "spec-lock", blvm_spec_lock::requires(locktime < LOCKTIME_THRESHOLD))]
30#[cfg_attr(feature = "spec-lock", blvm_spec_lock::ensures(result == LocktimeType::BlockHeight))]
31pub fn get_locktime_type(locktime: u32) -> LocktimeType {
32 if locktime < LOCKTIME_THRESHOLD {
33 LocktimeType::BlockHeight
34 } else {
35 LocktimeType::Timestamp
36 }
37}
38
39#[inline]
44#[cfg_attr(feature = "spec-lock", spec_locked("5.4.7", "GetLocktimeType"))]
45#[cfg_attr(feature = "spec-lock", blvm_spec_lock::requires(locktime >= LOCKTIME_THRESHOLD))]
46#[cfg_attr(feature = "spec-lock", blvm_spec_lock::ensures(result == LocktimeType::Timestamp))]
47pub fn get_locktime_type_timestamp(locktime: u32) -> LocktimeType {
48 if locktime < LOCKTIME_THRESHOLD {
49 LocktimeType::BlockHeight
50 } else {
51 LocktimeType::Timestamp
52 }
53}
54
55#[inline]
61#[cfg_attr(feature = "spec-lock", spec_locked("5.4.7", "BIP65Check"))]
62pub fn check_bip65(tx_locktime: u32, stack_locktime: u32) -> bool {
63 locktime_types_match(tx_locktime, stack_locktime) && tx_locktime >= stack_locktime
64}
65
66#[inline]
71pub fn check_bip112(stack_sequence: u32, input_sequence: u32) -> bool {
72 extract_sequence_type_flag(stack_sequence) == extract_sequence_type_flag(input_sequence)
73 && extract_sequence_locktime_value(input_sequence)
74 >= extract_sequence_locktime_value(stack_sequence)
75}
76
77#[inline]
81pub fn locktime_types_match(locktime1: u32, locktime2: u32) -> bool {
82 get_locktime_type(locktime1) == get_locktime_type(locktime2)
83}
84
85pub fn decode_locktime_value(bytes: &[u8]) -> Option<i64> {
91 if bytes.len() > 5 {
92 return None;
93 }
94 if bytes.is_empty() {
95 return Some(0);
96 }
97
98 let mut result: i64 = 0;
99 for (i, &byte) in bytes.iter().enumerate() {
100 result |= (byte as i64) << (8 * i);
101 }
102 let last = bytes.len() - 1;
103 if bytes[last] & 0x80 != 0 {
104 result &= !(0x80i64 << (8 * last));
105 result = -result;
106 }
107 Some(result)
108}
109
110pub fn encode_locktime_value(value: u32) -> ByteString {
115 let mut bytes = Vec::new();
116
117 let mut temp = value;
119 while temp > 0 {
120 bytes.push((temp & 0xff) as u8);
121 temp >>= 8;
122
123 debug_assert!(
126 temp < value || bytes.len() <= 4,
127 "Locktime encoding loop must terminate (temp: {}, value: {}, bytes: {})",
128 temp,
129 value,
130 bytes.len()
131 );
132 }
133
134 if bytes.is_empty() {
136 bytes.push(0);
137 }
138 if bytes.last().is_some_and(|b| b & 0x80 != 0) {
141 bytes.push(0);
142 }
143
144 let len = bytes.len();
146 debug_assert!(
147 !bytes.is_empty() && len <= 5,
148 "Encoded locktime length ({len}) must be between 1 and 5 bytes"
149 );
150
151 bytes
152}
153
154#[inline]
163#[cfg_attr(feature = "spec-lock", spec_locked("5.5", "ExtractSequenceTypeFlag"))]
164#[cfg_attr(feature = "spec-lock", blvm_spec_lock::ensures(result == false || sequence >= 4194304))]
165pub fn extract_sequence_type_flag(sequence: u32) -> bool {
166 (sequence & 0x00400000) != 0
167}
168
169#[inline]
173#[cfg_attr(
174 feature = "spec-lock",
175 spec_locked("5.5", "ExtractSequenceLocktimeValue")
176)]
177#[cfg_attr(feature = "spec-lock", blvm_spec_lock::ensures(result <= 65535))]
178pub fn extract_sequence_locktime_value(sequence: u32) -> u16 {
179 (sequence & 0x0000ffff) as u16
180}
181
182#[inline]
189#[cfg_attr(feature = "spec-lock", spec_locked("5.5", "IsSequenceDisabled"))]
190#[cfg_attr(feature = "spec-lock", blvm_spec_lock::ensures(result == false || sequence > 2147483647))]
191pub fn is_sequence_disabled(sequence: u32) -> bool {
192 (sequence & 0x80000000) != 0
193}
194
195#[cfg(test)]
196mod tests {
197 use super::*;
198
199 #[test]
200 fn test_get_locktime_type_block_height() {
201 assert_eq!(get_locktime_type(100), LocktimeType::BlockHeight);
202 assert_eq!(
203 get_locktime_type(LOCKTIME_THRESHOLD - 1),
204 LocktimeType::BlockHeight
205 );
206 }
207
208 #[test]
209 fn test_get_locktime_type_timestamp() {
210 assert_eq!(
211 get_locktime_type(LOCKTIME_THRESHOLD),
212 LocktimeType::Timestamp
213 );
214 assert_eq!(get_locktime_type(1_000_000_000), LocktimeType::Timestamp);
215 }
216
217 #[test]
218 fn test_locktime_types_match() {
219 assert!(locktime_types_match(100, 200));
220 assert!(locktime_types_match(
221 LOCKTIME_THRESHOLD,
222 LOCKTIME_THRESHOLD + 1000
223 ));
224 assert!(!locktime_types_match(100, LOCKTIME_THRESHOLD));
225 }
226
227 #[test]
228 fn test_decode_locktime_value() {
229 assert_eq!(decode_locktime_value(&[100, 0, 0, 0]), Some(100));
230 assert_eq!(decode_locktime_value(&[0]), Some(0));
231 assert_eq!(decode_locktime_value(&[]), Some(0));
232 assert_eq!(
234 decode_locktime_value(&[0xff, 0xff, 0xff, 0xff]),
235 Some(-2_147_483_647)
236 );
237 assert_eq!(decode_locktime_value(&[0x80]), Some(0));
238 assert_eq!(decode_locktime_value(&[0x81]), Some(-1));
239 assert_eq!(
240 decode_locktime_value(&[0x01, 0x00, 0x00, 0x00, 0x80]),
241 Some(-1)
242 );
243 assert_eq!(
244 decode_locktime_value(&[0x00, 0x00, 0x00, 0x80, 0x00]),
245 Some(0x8000_0000)
246 );
247 assert_eq!(
248 decode_locktime_value(&[0x00, 0x00, 0x00, 0x00, 0x01]),
249 Some(1_i64 << 32)
250 );
251 assert_eq!(decode_locktime_value(&[0; 6]), None);
252 }
253
254 #[test]
255 fn test_encode_locktime_value() {
256 assert_eq!(encode_locktime_value(100), vec![100]); assert_eq!(encode_locktime_value(0), vec![0]);
259 assert_eq!(
260 encode_locktime_value(0x12345678),
261 vec![0x78, 0x56, 0x34, 0x12]
262 );
263 assert_eq!(encode_locktime_value(0x00001234), vec![0x34, 0x12]);
265 assert_eq!(
266 encode_locktime_value(0x12345600),
267 vec![0x00, 0x56, 0x34, 0x12]
268 );
269 }
270
271 #[test]
272 fn test_extract_sequence_type_flag() {
273 assert!(extract_sequence_type_flag(0x00400000));
274 assert!(!extract_sequence_type_flag(0x00000000));
275 assert!(extract_sequence_type_flag(0x00410000));
276 }
277
278 #[test]
279 fn test_extract_sequence_locktime_value() {
280 assert_eq!(extract_sequence_locktime_value(0x00001234), 0x1234);
281 assert_eq!(extract_sequence_locktime_value(0x00401234), 0x1234); }
283
284 #[test]
285 fn test_is_sequence_disabled() {
286 assert!(is_sequence_disabled(0x80000000));
287 assert!(!is_sequence_disabled(0x00000000));
288 assert!(is_sequence_disabled(0x80010000));
289 }
290}