Disable MPP routing when the payee does not support it
[rust-lightning] / lightning / src / ln / features.rs
index 3ce3d4fa7e604b9e0fb979dd8f4da0911adbdda2..488d6d70f5768ffde2d0af6afd80707a595625c9 100644 (file)
@@ -26,7 +26,6 @@
 //! [`Context`]: sealed/trait.Context.html
 
 use std::{cmp, fmt};
-use std::result::Result;
 use std::marker::PhantomData;
 
 use ln::msgs::DecodeError;
@@ -101,6 +100,8 @@ mod sealed {
                        StaticRemoteKey,
                        // Byte 2
                        ,
+                       // Byte 3
+                       ,
                ],
                optional_features: [
                        // Byte 0
@@ -109,6 +110,8 @@ mod sealed {
                        VariableLengthOnion | PaymentSecret,
                        // Byte 2
                        BasicMPP,
+                       // Byte 3
+                       ShutdownAnySegwit,
                ],
        });
        define_context!(NodeContext {
@@ -119,6 +122,8 @@ mod sealed {
                        StaticRemoteKey,
                        // Byte 2
                        ,
+                       // Byte 3
+                       ,
                ],
                optional_features: [
                        // Byte 0
@@ -127,12 +132,25 @@ mod sealed {
                        VariableLengthOnion | PaymentSecret,
                        // Byte 2
                        BasicMPP,
+                       // Byte 3
+                       ShutdownAnySegwit,
                ],
        });
        define_context!(ChannelContext {
                required_features: [],
                optional_features: [],
        });
+       define_context!(InvoiceContext {
+               required_features: [,,,],
+               optional_features: [
+                       // Byte 0
+                       ,
+                       // Byte 1
+                       VariableLengthOnion | PaymentSecret,
+                       // Byte 2
+                       BasicMPP,
+               ],
+       });
 
        /// Defines a feature with the given bits for the specified [`Context`]s. The generated trait is
        /// useful for manipulating feature flags.
@@ -245,14 +263,16 @@ mod sealed {
                "Feature flags for `option_upfront_shutdown_script`.");
        define_feature!(7, GossipQueries, [InitContext, NodeContext],
                "Feature flags for `gossip_queries`.");
-       define_feature!(9, VariableLengthOnion, [InitContext, NodeContext],
+       define_feature!(9, VariableLengthOnion, [InitContext, NodeContext, InvoiceContext],
                "Feature flags for `var_onion_optin`.");
        define_feature!(13, StaticRemoteKey, [InitContext, NodeContext],
                "Feature flags for `option_static_remotekey`.");
-       define_feature!(15, PaymentSecret, [InitContext, NodeContext],
+       define_feature!(15, PaymentSecret, [InitContext, NodeContext, InvoiceContext],
                "Feature flags for `payment_secret`.");
-       define_feature!(17, BasicMPP, [InitContext, NodeContext],
+       define_feature!(17, BasicMPP, [InitContext, NodeContext, InvoiceContext],
                "Feature flags for `basic_mpp`.");
+       define_feature!(27, ShutdownAnySegwit, [InitContext, NodeContext],
+               "Feature flags for `opt_shutdown_anysegwit`.");
 
        #[cfg(test)]
        define_context!(TestingContext {
@@ -314,6 +334,8 @@ pub type InitFeatures = Features<sealed::InitContext>;
 pub type NodeFeatures = Features<sealed::NodeContext>;
 /// Features used within a `channel_announcement` message.
 pub type ChannelFeatures = Features<sealed::ChannelContext>;
+/// Features used within an invoice.
+pub type InvoiceFeatures = Features<sealed::InvoiceContext>;
 
 impl InitFeatures {
        /// Writes all features present up to, and including, 13.
@@ -350,9 +372,17 @@ impl InitFeatures {
        }
 }
 
+impl InvoiceFeatures {
+       /// Converts `InvoiceFeatures` to `Features<C>`. Only known `InvoiceFeatures` 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<T: sealed::Context> Features<T> {
        /// Create a blank Features with no features set
-       pub fn empty() -> Features<T> {
+       pub fn empty() -> Self {
                Features {
                        flags: Vec::new(),
                        mark: PhantomData,
@@ -362,7 +392,7 @@ impl<T: sealed::Context> Features<T> {
        /// Creates features known by the implementation as defined by [`T::KNOWN_FEATURE_FLAGS`].
        ///
        /// [`T::KNOWN_FEATURE_FLAGS`]: sealed/trait.Context.html#associatedconstant.KNOWN_FEATURE_FLAGS
-       pub fn known() -> Features<T> {
+       pub fn known() -> Self {
                Self {
                        flags: T::KNOWN_FEATURE_FLAGS.to_vec(),
                        mark: PhantomData,
@@ -544,12 +574,22 @@ impl<T: sealed::BasicMPP> Features<T> {
                <T as sealed::BasicMPP>::requires_feature(&self.flags)
        }
        // We currently never test for this since we don't actually *generate* multipath routes.
-       #[allow(dead_code)]
        pub(crate) fn supports_basic_mpp(&self) -> bool {
                <T as sealed::BasicMPP>::supports_feature(&self.flags)
        }
 }
 
+impl<T: sealed::ShutdownAnySegwit> Features<T> {
+       pub(crate) fn supports_shutdown_anysegwit(&self) -> bool {
+               <T as sealed::ShutdownAnySegwit>::supports_feature(&self.flags)
+       }
+       #[cfg(test)]
+       pub(crate) fn clear_shutdown_anysegwit(mut self) -> Self {
+               <T as sealed::ShutdownAnySegwit>::clear_bits(&mut self.flags);
+               self
+       }
+}
+
 impl<T: sealed::Context> Writeable for Features<T> {
        fn write<W: Writer>(&self, w: &mut W) -> Result<(), ::std::io::Error> {
                w.size_hint(self.flags.len() + 2);
@@ -620,6 +660,9 @@ mod tests {
                assert!(!InitFeatures::known().requires_basic_mpp());
                assert!(!NodeFeatures::known().requires_basic_mpp());
 
+               assert!(InitFeatures::known().supports_shutdown_anysegwit());
+               assert!(NodeFeatures::known().supports_shutdown_anysegwit());
+
                let mut init_features = InitFeatures::known();
                assert!(init_features.initial_routing_sync());
                init_features.clear_initial_routing_sync();
@@ -658,10 +701,12 @@ mod tests {
                        // - option_data_loss_protect
                        // - var_onion_optin | static_remote_key (req) | payment_secret
                        // - basic_mpp
-                       assert_eq!(node_features.flags.len(), 3);
+                       // - opt_shutdown_anysegwit
+                       assert_eq!(node_features.flags.len(), 4);
                        assert_eq!(node_features.flags[0], 0b00000010);
                        assert_eq!(node_features.flags[1], 0b10010010);
                        assert_eq!(node_features.flags[2], 0b00000010);
+                       assert_eq!(node_features.flags[3], 0b00001000);
                }
 
                // Check that cleared flags are kept blank when converting back: