X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Ffeatures.rs;h=b8087546c7445060230a5ad776a9b3f13c113d37;hb=7a78998552b1d3c2d97f337a7d5aaf7fe1aa70b4;hp=47e1cbcc4cba67295e5c2e2d954629a9695d399c;hpb=35b597a4c27e54fcdd1feeb1c7dc77356c45c11b;p=rust-lightning diff --git a/lightning/src/ln/features.rs b/lightning/src/ln/features.rs index 47e1cbcc..b8087546 100644 --- a/lightning/src/ln/features.rs +++ b/lightning/src/ln/features.rs @@ -275,6 +275,7 @@ mod sealed { } flags[Self::BYTE_OFFSET] |= Self::REQUIRED_MASK; + flags[Self::BYTE_OFFSET] &= !Self::OPTIONAL_MASK; } /// Sets the feature's optional (odd) bit in the given flags. @@ -421,8 +422,10 @@ pub struct Features { mark: PhantomData, } -impl Features { - pub(crate) fn or(mut self, o: Self) -> Self { +impl core::ops::BitOr for Features { + type Output = Self; + + fn bitor(mut self, o: Self) -> Self { let total_feature_len = cmp::max(self.flags.len(), o.flags.len()); self.flags.resize(total_feature_len, 0u8); for (byte, o_byte) in self.flags.iter_mut().zip(o.flags.iter()) { @@ -450,6 +453,16 @@ impl PartialEq for Features { self.flags.eq(&o.flags) } } +impl PartialOrd for Features { + fn partial_cmp(&self, other: &Self) -> Option { + self.flags.partial_cmp(&other.flags) + } +} +impl Ord for Features { + fn cmp(&self, other: &Self) -> cmp::Ordering { + self.flags.cmp(&other.flags) + } +} impl fmt::Debug for Features { fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { self.flags.fmt(fmt) @@ -531,6 +544,14 @@ impl InvoiceFeatures { } } +impl Bolt12InvoiceFeatures { + /// Converts `Bolt12InvoiceFeatures` to `Features`. Only known `Bolt12InvoiceFeatures` relevant + /// to context `C` are included in the result. + pub(crate) fn to_context(&self) -> Features { + self.to_context_internal() + } +} + impl ChannelTypeFeatures { // Maps the relevant `InitFeatures` to `ChannelTypeFeatures`. Any unknown features to // `ChannelTypeFeatures` are not included in the result. @@ -676,6 +697,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 { @@ -724,6 +764,50 @@ impl Features { } true } + + /// Sets a required custom feature bit. Errors if `bit` is outside the custom range as defined + /// by [bLIP 2] or if it is a known `T` feature. + /// + /// Note: Required bits are even. If an odd bit is given, then the corresponding even bit will + /// be set instead (i.e., `bit - 1`). + /// + /// [bLIP 2]: https://github.com/lightning/blips/blob/master/blip-0002.md#feature-bits + pub fn set_required_custom_bit(&mut self, bit: usize) -> Result<(), ()> { + self.set_custom_bit(bit - (bit % 2)) + } + + /// Sets an optional custom feature bit. Errors if `bit` is outside the custom range as defined + /// by [bLIP 2] or if it is a known `T` feature. + /// + /// Note: Optional bits are odd. If an even bit is given, then the corresponding odd bit will be + /// set instead (i.e., `bit + 1`). + /// + /// [bLIP 2]: https://github.com/lightning/blips/blob/master/blip-0002.md#feature-bits + pub fn set_optional_custom_bit(&mut self, bit: usize) -> Result<(), ()> { + self.set_custom_bit(bit + (1 - (bit % 2))) + } + + fn set_custom_bit(&mut self, bit: usize) -> Result<(), ()> { + if bit < 256 { + return Err(()); + } + + let byte_offset = bit / 8; + let mask = 1 << (bit - 8 * byte_offset); + if byte_offset < T::KNOWN_FEATURE_MASK.len() { + if (T::KNOWN_FEATURE_MASK[byte_offset] & mask) != 0 { + return Err(()); + } + } + + if self.flags.len() <= byte_offset { + self.flags.resize(byte_offset + 1, 0u8); + } + + self.flags[byte_offset] |= mask; + + Ok(()) + } } impl Features { @@ -790,6 +874,7 @@ impl_feature_len_prefixed_write!(InitFeatures); impl_feature_len_prefixed_write!(ChannelFeatures); impl_feature_len_prefixed_write!(NodeFeatures); impl_feature_len_prefixed_write!(InvoiceFeatures); +impl_feature_len_prefixed_write!(Bolt12InvoiceFeatures); impl_feature_len_prefixed_write!(BlindedHopFeatures); // Some features only appear inside of TLVs, so they don't have a length prefix when serialized. @@ -849,24 +934,61 @@ 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(); // Set a bunch of features we use, plus initial_routing_sync_required (which shouldn't get // converted as it's only relevant in an init context). init_features.set_initial_routing_sync_required(); - init_features.set_data_loss_protect_optional(); + init_features.set_data_loss_protect_required(); init_features.set_variable_length_onion_required(); init_features.set_static_remote_key_required(); init_features.set_payment_secret_required(); init_features.set_basic_mpp_optional(); init_features.set_wumbo_optional(); + init_features.set_anchors_zero_fee_htlc_tx_optional(); init_features.set_shutdown_any_segwit_optional(); init_features.set_onion_messages_optional(); init_features.set_channel_type_optional(); init_features.set_scid_privacy_optional(); init_features.set_zero_conf_optional(); - init_features.set_anchors_zero_fee_htlc_tx_optional(); assert!(init_features.initial_routing_sync()); assert!(!init_features.supports_upfront_shutdown_script()); @@ -875,15 +997,15 @@ mod tests { let node_features: NodeFeatures = init_features.to_context(); { // Check that the flags are as expected: - // - option_data_loss_protect + // - option_data_loss_protect (req) // - var_onion_optin (req) | static_remote_key (req) | payment_secret(req) - // - basic_mpp | wumbo + // - basic_mpp | wumbo | anchors_zero_fee_htlc_tx // - opt_shutdown_anysegwit // - onion_messages // - option_channel_type | option_scid_alias // - option_zeroconf assert_eq!(node_features.flags.len(), 7); - assert_eq!(node_features.flags[0], 0b00000010); + assert_eq!(node_features.flags[0], 0b00000001); assert_eq!(node_features.flags[1], 0b01010001); assert_eq!(node_features.flags[2], 0b10001010); assert_eq!(node_features.flags[3], 0b00001000); @@ -925,6 +1047,36 @@ mod tests { assert!(features.supports_payment_secret()); } + #[test] + fn set_custom_bits() { + let mut features = InvoiceFeatures::empty(); + features.set_variable_length_onion_optional(); + assert_eq!(features.flags[1], 0b00000010); + + assert!(features.set_optional_custom_bit(255).is_err()); + assert!(features.set_required_custom_bit(256).is_ok()); + assert!(features.set_required_custom_bit(258).is_ok()); + assert_eq!(features.flags[31], 0b00000000); + assert_eq!(features.flags[32], 0b00000101); + + let known_bit = ::EVEN_BIT; + let byte_offset = ::BYTE_OFFSET; + assert_eq!(byte_offset, 1); + assert_eq!(features.flags[byte_offset], 0b00000010); + assert!(features.set_required_custom_bit(known_bit).is_err()); + assert_eq!(features.flags[byte_offset], 0b00000010); + + let mut features = InvoiceFeatures::empty(); + assert!(features.set_optional_custom_bit(256).is_ok()); + assert!(features.set_optional_custom_bit(259).is_ok()); + assert_eq!(features.flags[32], 0b00001010); + + let mut features = InvoiceFeatures::empty(); + assert!(features.set_required_custom_bit(257).is_ok()); + assert!(features.set_required_custom_bit(258).is_ok()); + assert_eq!(features.flags[32], 0b00000101); + } + #[test] fn encodes_features_without_length() { let features = OfferFeatures::from_le_bytes(vec![1, 2, 3, 4, 5, 42, 100, 101]);