blvm_consensus/
locktime.rs1use crate::constants::LOCKTIME_THRESHOLD;
7use crate::types::*;
8use blvm_spec_lock::spec_locked;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum LocktimeType {
13 BlockHeight,
15 Timestamp,
17}
18
19#[inline]
23pub fn get_locktime_type(locktime: u32) -> LocktimeType {
24 if locktime < LOCKTIME_THRESHOLD {
25 LocktimeType::BlockHeight
26 } else {
27 LocktimeType::Timestamp
28 }
29}
30
31#[inline]
34#[spec_locked("5.4.7", "BIP65Check")]
35pub fn check_bip65(tx_locktime: u32, stack_locktime: u32) -> bool {
36 tx_locktime != 0
37 && locktime_types_match(tx_locktime, stack_locktime)
38 && tx_locktime >= stack_locktime
39}
40
41#[inline]
45pub fn locktime_types_match(locktime1: u32, locktime2: u32) -> bool {
46 get_locktime_type(locktime1) == get_locktime_type(locktime2)
47}
48
49pub fn decode_locktime_value(bytes: &[u8]) -> Option<u32> {
60 if bytes.len() > 5 {
61 return None; }
63
64 debug_assert!(
66 bytes.len() <= 5,
67 "Locktime byte string length ({}) must be <= 5",
68 bytes.len()
69 );
70
71 let mut value: u32 = 0;
72 for (i, &byte) in bytes.iter().enumerate() {
73 if i >= 4 {
74 break; }
76
77 debug_assert!(i < 4, "Byte index ({i}) must be < 4 for locktime decoding");
79
80 let shift_amount = i * 8;
82 debug_assert!(
83 shift_amount < 32,
84 "Shift amount ({shift_amount}) must be < 32 (i: {i})"
85 );
86
87 value |= (byte as u32) << shift_amount;
88 }
89
90 Some(value)
93}
94
95pub fn encode_locktime_value(value: u32) -> ByteString {
100 let mut bytes = Vec::new();
101
102 let mut temp = value;
104 while temp > 0 {
105 bytes.push((temp & 0xff) as u8);
106 temp >>= 8;
107
108 debug_assert!(
111 temp < value || bytes.len() <= 4,
112 "Locktime encoding loop must terminate (temp: {}, value: {}, bytes: {})",
113 temp,
114 value,
115 bytes.len()
116 );
117 }
118
119 if bytes.is_empty() {
121 bytes.push(0);
122 }
123
124 let len = bytes.len();
126 debug_assert!(
127 !bytes.is_empty() && len <= 4,
128 "Encoded locktime length ({len}) must be between 1 and 4 bytes"
129 );
130
131 bytes
132}
133
134#[inline]
140#[spec_locked("5.5", "ExtractSequenceTypeFlag")]
141pub fn extract_sequence_type_flag(sequence: u32) -> bool {
142 (sequence & 0x00400000) != 0
143}
144
145#[inline]
149#[spec_locked("5.5", "ExtractSequenceLocktimeValue")]
150pub fn extract_sequence_locktime_value(sequence: u32) -> u16 {
151 (sequence & 0x0000ffff) as u16
152}
153
154#[inline]
158#[spec_locked("5.5", "IsSequenceDisabled")]
159pub fn is_sequence_disabled(sequence: u32) -> bool {
160 (sequence & 0x80000000) != 0
161}
162
163#[cfg(test)]
164mod tests {
165 use super::*;
166
167 #[test]
168 fn test_get_locktime_type_block_height() {
169 assert_eq!(get_locktime_type(100), LocktimeType::BlockHeight);
170 assert_eq!(
171 get_locktime_type(LOCKTIME_THRESHOLD - 1),
172 LocktimeType::BlockHeight
173 );
174 }
175
176 #[test]
177 fn test_get_locktime_type_timestamp() {
178 assert_eq!(
179 get_locktime_type(LOCKTIME_THRESHOLD),
180 LocktimeType::Timestamp
181 );
182 assert_eq!(get_locktime_type(1_000_000_000), LocktimeType::Timestamp);
183 }
184
185 #[test]
186 fn test_locktime_types_match() {
187 assert!(locktime_types_match(100, 200));
188 assert!(locktime_types_match(
189 LOCKTIME_THRESHOLD,
190 LOCKTIME_THRESHOLD + 1000
191 ));
192 assert!(!locktime_types_match(100, LOCKTIME_THRESHOLD));
193 }
194
195 #[test]
196 fn test_decode_locktime_value() {
197 assert_eq!(decode_locktime_value(&vec![100, 0, 0, 0]), Some(100));
198 assert_eq!(decode_locktime_value(&vec![0]), Some(0));
199 assert_eq!(
200 decode_locktime_value(&vec![0xff, 0xff, 0xff, 0xff]),
201 Some(0xffffffff)
202 );
203 assert_eq!(decode_locktime_value(&vec![0; 6]), None); }
205
206 #[test]
207 fn test_encode_locktime_value() {
208 assert_eq!(encode_locktime_value(100), vec![100]); assert_eq!(encode_locktime_value(0), vec![0]);
211 assert_eq!(
212 encode_locktime_value(0x12345678),
213 vec![0x78, 0x56, 0x34, 0x12]
214 );
215 assert_eq!(encode_locktime_value(0x00001234), vec![0x34, 0x12]);
217 assert_eq!(
218 encode_locktime_value(0x12345600),
219 vec![0x00, 0x56, 0x34, 0x12]
220 );
221 }
222
223 #[test]
224 fn test_extract_sequence_type_flag() {
225 assert!(extract_sequence_type_flag(0x00400000));
226 assert!(!extract_sequence_type_flag(0x00000000));
227 assert!(extract_sequence_type_flag(0x00410000));
228 }
229
230 #[test]
231 fn test_extract_sequence_locktime_value() {
232 assert_eq!(extract_sequence_locktime_value(0x00001234), 0x1234);
233 assert_eq!(extract_sequence_locktime_value(0x00401234), 0x1234); }
235
236 #[test]
237 fn test_is_sequence_disabled() {
238 assert!(is_sequence_disabled(0x80000000));
239 assert!(!is_sequence_disabled(0x00000000));
240 assert!(is_sequence_disabled(0x80010000));
241 }
242}