Disable MPP routing when the payee does not support it
[rust-lightning] / lightning / src / ln / features.rs
index c97e18100fc769fd906a201f4868f3e662d21852..488d6d70f5768ffde2d0af6afd80707a595625c9 100644 (file)
@@ -100,6 +100,8 @@ mod sealed {
                        StaticRemoteKey,
                        // Byte 2
                        ,
+                       // Byte 3
+                       ,
                ],
                optional_features: [
                        // Byte 0
@@ -108,6 +110,8 @@ mod sealed {
                        VariableLengthOnion | PaymentSecret,
                        // Byte 2
                        BasicMPP,
+                       // Byte 3
+                       ShutdownAnySegwit,
                ],
        });
        define_context!(NodeContext {
@@ -118,6 +122,8 @@ mod sealed {
                        StaticRemoteKey,
                        // Byte 2
                        ,
+                       // Byte 3
+                       ,
                ],
                optional_features: [
                        // Byte 0
@@ -126,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.
@@ -244,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 {
@@ -313,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.
@@ -349,6 +372,14 @@ 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() -> Self {
@@ -543,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);
@@ -619,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();
@@ -657,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: