From 3313abb37d8745597c7fe8aeaa230f4e89160e02 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Fri, 5 May 2023 13:38:50 -0500 Subject: [PATCH] Add Features::requires_unknown_bits_from When checking features, rather than checking against which features LDK knows about, it is more useful to check against a peer's features. Add Features::requires_unknown_bits_from such that the given features are used instead. --- lightning/src/ln/features.rs | 56 ++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/lightning/src/ln/features.rs b/lightning/src/ln/features.rs index f0e2f112a..4b49a56ea 100644 --- a/lightning/src/ln/features.rs +++ b/lightning/src/ln/features.rs @@ -679,6 +679,25 @@ impl Features { self.flags.iter().any(|&byte| (byte & 0b10_10_10_10) != 0) } + /// Returns true if this `Features` object contains required features unknown by `other`. + pub fn requires_unknown_bits_from(&self, other: &Features) -> bool { + // Bitwise AND-ing with all even bits set except for known features will select required + // unknown features. + self.flags.iter().enumerate().any(|(i, &byte)| { + const REQUIRED_FEATURES: u8 = 0b01_01_01_01; + const OPTIONAL_FEATURES: u8 = 0b10_10_10_10; + let unknown_features = if i < other.flags.len() { + // Form a mask similar to !T::KNOWN_FEATURE_MASK only for `other` + !(other.flags[i] + | ((other.flags[i] >> 1) & REQUIRED_FEATURES) + | ((other.flags[i] << 1) & OPTIONAL_FEATURES)) + } else { + 0b11_11_11_11 + }; + (byte & (REQUIRED_FEATURES & unknown_features)) != 0 + }) + } + /// Returns true if this `Features` object contains unknown feature flags which are set as /// "required". pub fn requires_unknown_bits(&self) -> bool { @@ -852,6 +871,43 @@ mod tests { assert!(features.supports_unknown_bits()); } + #[test] + fn requires_unknown_bits_from() { + let mut features1 = InitFeatures::empty(); + let mut features2 = InitFeatures::empty(); + assert!(!features1.requires_unknown_bits_from(&features2)); + assert!(!features2.requires_unknown_bits_from(&features1)); + + features1.set_data_loss_protect_required(); + assert!(features1.requires_unknown_bits_from(&features2)); + assert!(!features2.requires_unknown_bits_from(&features1)); + + features2.set_data_loss_protect_optional(); + assert!(!features1.requires_unknown_bits_from(&features2)); + assert!(!features2.requires_unknown_bits_from(&features1)); + + features2.set_gossip_queries_required(); + assert!(!features1.requires_unknown_bits_from(&features2)); + assert!(features2.requires_unknown_bits_from(&features1)); + + features1.set_gossip_queries_optional(); + assert!(!features1.requires_unknown_bits_from(&features2)); + assert!(!features2.requires_unknown_bits_from(&features1)); + + features1.set_variable_length_onion_required(); + assert!(features1.requires_unknown_bits_from(&features2)); + assert!(!features2.requires_unknown_bits_from(&features1)); + + features2.set_variable_length_onion_optional(); + assert!(!features1.requires_unknown_bits_from(&features2)); + assert!(!features2.requires_unknown_bits_from(&features1)); + + features1.set_basic_mpp_required(); + features2.set_wumbo_required(); + assert!(features1.requires_unknown_bits_from(&features2)); + assert!(features2.requires_unknown_bits_from(&features1)); + } + #[test] fn convert_to_context_with_relevant_flags() { let mut init_features = InitFeatures::empty(); -- 2.39.5