Add test for duplicate keysend payment
[rust-lightning] / lightning / src / ln / features.rs
index 47e1cbcc4cba67295e5c2e2d954629a9695d399c..d24d32ba0fa039dd9356621ec66839b2c59ffc28 100644 (file)
@@ -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.
@@ -450,6 +451,16 @@ impl<T: sealed::Context> PartialEq for Features<T> {
                self.flags.eq(&o.flags)
        }
 }
+impl<T: sealed::Context> PartialOrd for Features<T> {
+       fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
+               self.flags.partial_cmp(&other.flags)
+       }
+}
+impl<T: sealed::Context + Eq> Ord for Features<T> {
+       fn cmp(&self, other: &Self) -> cmp::Ordering {
+               self.flags.cmp(&other.flags)
+       }
+}
 impl<T: sealed::Context> fmt::Debug for Features<T> {
        fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
                self.flags.fmt(fmt)
@@ -522,15 +533,29 @@ impl InvoiceFeatures {
        /// [`PaymentParameters::for_keysend`], thus omitting the need for payers to manually construct an
        /// `InvoiceFeatures` for [`find_route`].
        ///
+       /// MPP keysend is not widely supported yet, so we parameterize support to allow the user to
+       /// choose whether their router should find multi-part routes.
+       ///
        /// [`PaymentParameters::for_keysend`]: crate::routing::router::PaymentParameters::for_keysend
        /// [`find_route`]: crate::routing::router::find_route
-       pub(crate) fn for_keysend() -> InvoiceFeatures {
+       pub(crate) fn for_keysend(allow_mpp: bool) -> InvoiceFeatures {
                let mut res = InvoiceFeatures::empty();
                res.set_variable_length_onion_optional();
+               if allow_mpp {
+                       res.set_basic_mpp_optional();
+               }
                res
        }
 }
 
+impl Bolt12InvoiceFeatures {
+       /// Converts `Bolt12InvoiceFeatures` to `Features<C>`. Only known `Bolt12InvoiceFeatures` relevant
+       /// to context `C` are included in the result.
+       pub(crate) fn to_context<C: sealed::Context>(&self) -> Features<C> {
+               self.to_context_internal()
+       }
+}
+
 impl ChannelTypeFeatures {
        // Maps the relevant `InitFeatures` to `ChannelTypeFeatures`. Any unknown features to
        // `ChannelTypeFeatures` are not included in the result.
@@ -790,6 +815,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.
@@ -855,7 +881,7 @@ mod tests {
                // 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();
@@ -875,7 +901,7 @@ 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
                        // - opt_shutdown_anysegwit
@@ -883,7 +909,7 @@ mod tests {
                        // - 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);