Skip to main content

lsp_primitives/lsps0/
util.rs

1use anyhow::Context;
2/// Contains LSPS0 related utilities
3///
4/// To determine if a Lightning-node is an LSP-server you can
5/// inspect the feature flags.
6///
7use std::str::FromStr;
8
9pub const LSP_SERVER_FEATURE_BIT: usize = 729;
10
11pub struct FeatureBitMap(Vec<u8>);
12
13impl FromStr for FeatureBitMap {
14    type Err = anyhow::Error;
15
16    fn from_str(s: &str) -> Result<Self, Self::Err> {
17        let hex = hex::decode(s).context("Failed to parse feature-bitmap")?;
18        Ok(FeatureBitMap(hex))
19    }
20}
21
22impl AsRef<[u8]> for &FeatureBitMap {
23    fn as_ref(&self) -> &[u8] {
24        &self.0
25    }
26}
27
28impl FeatureBitMap {
29    pub fn new(bitmap: Vec<u8>) -> Self {
30        FeatureBitMap(bitmap)
31    }
32}
33
34/// Returns True if the feature-bit at index usize is enabled
35pub fn is_feature_bit_enabled<T: AsRef<[u8]>>(bitmap: T, index: usize) -> bool {
36    let bm = bitmap.as_ref();
37    let n_bytes = bm.len();
38    let (byte_index, bit_index) = (index / 8, index % 8);
39
40    // The index doesn't fit in the byte-array
41    if byte_index >= n_bytes {
42        return false;
43    }
44
45    let selected_byte = bm[n_bytes - 1 - byte_index];
46    let bit_mask = 1u8 << (bit_index);
47
48    (selected_byte & bit_mask) != 0
49}
50
51#[cfg(test)]
52mod test {
53    use super::*;
54
55    #[test]
56    fn test_parse_bitmap() {
57        // Check the lowest bits in the bitmap
58        let feature_bitmap_00 = FeatureBitMap::from_str("01").unwrap();
59        let feature_bitmap_01 = FeatureBitMap::from_str("02").unwrap();
60        let feature_bitmap_02 = FeatureBitMap::from_str("04").unwrap();
61        let feature_bitmap_03 = FeatureBitMap::from_str("08").unwrap();
62        let feature_bitmap_04 = FeatureBitMap::from_str("10").unwrap();
63        let feature_bitmap_05 = FeatureBitMap::from_str("20").unwrap();
64        let feature_bitmap_06 = FeatureBitMap::from_str("40").unwrap();
65        let feature_bitmap_07 = FeatureBitMap::from_str("80").unwrap();
66
67        // Check that the expected bit is enabled
68        assert!(is_feature_bit_enabled(&feature_bitmap_00, 0));
69        assert!(is_feature_bit_enabled(&feature_bitmap_01, 1));
70        assert!(is_feature_bit_enabled(&feature_bitmap_02, 2));
71        assert!(is_feature_bit_enabled(&feature_bitmap_03, 3));
72        assert!(is_feature_bit_enabled(&feature_bitmap_04, 4));
73        assert!(is_feature_bit_enabled(&feature_bitmap_05, 5));
74        assert!(is_feature_bit_enabled(&feature_bitmap_06, 6));
75        assert!(is_feature_bit_enabled(&feature_bitmap_07, 7));
76
77        // Check that other bits are disabled
78        assert!(!is_feature_bit_enabled(&feature_bitmap_01, 0));
79        assert!(!is_feature_bit_enabled(&feature_bitmap_01, 2));
80        assert!(!is_feature_bit_enabled(&feature_bitmap_01, 3));
81        assert!(!is_feature_bit_enabled(&feature_bitmap_01, 4));
82        assert!(!is_feature_bit_enabled(&feature_bitmap_01, 5));
83        assert!(!is_feature_bit_enabled(&feature_bitmap_01, 6));
84        assert!(!is_feature_bit_enabled(&feature_bitmap_01, 7));
85        assert!(!is_feature_bit_enabled(&feature_bitmap_01, 8));
86        assert!(!is_feature_bit_enabled(&feature_bitmap_01, 9));
87
88        assert!(!is_feature_bit_enabled(&feature_bitmap_01, 1000));
89    }
90
91    #[test]
92    fn test_lsps_option_enabled_bitmap() {
93        // Copied from LSPS0
94        // This set bit number 729
95        let data = "0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
96        let bitmap = FeatureBitMap::from_str(data).unwrap();
97
98        // Check that the expected bit is enabled
99        assert!(is_feature_bit_enabled(&bitmap, LSP_SERVER_FEATURE_BIT));
100
101        // Check that the expected bit is disabled
102        assert!(!is_feature_bit_enabled(&bitmap, 728));
103        assert!(!is_feature_bit_enabled(&bitmap, 730));
104    }
105}