Add support for `opt_shutdown_anysegwit` feature #780
[rust-lightning] / lightning / src / ln / features.rs
index 613d2db14590b5115b9ae6c18461699141dd0c19..35c9410bc0b2b70ce4f7b5bd342b74134e950040 100644 (file)
@@ -1,3 +1,12 @@
+// This file is Copyright its original authors, visible in version control
+// history.
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+
 //! Feature flag definitions for the Lightning protocol according to [BOLT #9].
 //!
 //! Lightning nodes advertise a supported set of operation through feature flags. Features are
@@ -17,7 +26,6 @@
 //! [`Context`]: sealed/trait.Context.html
 
 use std::{cmp, fmt};
-use std::result::Result;
 use std::marker::PhantomData;
 
 use ln::msgs::DecodeError;
@@ -89,17 +97,21 @@ mod sealed {
                        // Byte 0
                        ,
                        // Byte 1
-                       ,
+                       StaticRemoteKey,
                        // Byte 2
                        ,
+                       // Byte 3
+                       ,
                ],
                optional_features: [
                        // Byte 0
-                       DataLossProtect | InitialRoutingSync | UpfrontShutdownScript,
+                       DataLossProtect | InitialRoutingSync | UpfrontShutdownScript | GossipQueries,
                        // Byte 1
                        VariableLengthOnion | PaymentSecret,
                        // Byte 2
                        BasicMPP,
+                       // Byte 3
+                       ShutdownAnySegwit,
                ],
        });
        define_context!(NodeContext {
@@ -107,17 +119,21 @@ mod sealed {
                        // Byte 0
                        ,
                        // Byte 1
-                       ,
+                       StaticRemoteKey,
                        // Byte 2
                        ,
+                       // Byte 3
+                       ,
                ],
                optional_features: [
                        // Byte 0
-                       DataLossProtect | UpfrontShutdownScript,
+                       DataLossProtect | UpfrontShutdownScript | GossipQueries,
                        // Byte 1
                        VariableLengthOnion | PaymentSecret,
                        // Byte 2
                        BasicMPP,
+                       // Byte 3
+                       ShutdownAnySegwit,
                ],
        });
        define_context!(ChannelContext {
@@ -166,6 +182,13 @@ mod sealed {
                                /// [`BYTE_OFFSET`]: #associatedconstant.BYTE_OFFSET
                                const OPTIONAL_MASK: u8 = 1 << (Self::ODD_BIT - 8 * Self::BYTE_OFFSET);
 
+                               /// Returns whether the feature is required by the given flags.
+                               #[inline]
+                               fn requires_feature(flags: &Vec<u8>) -> bool {
+                                       flags.len() > Self::BYTE_OFFSET &&
+                                               (flags[Self::BYTE_OFFSET] & Self::REQUIRED_MASK) != 0
+                               }
+
                                /// Returns whether the feature is supported by the given flags.
                                #[inline]
                                fn supports_feature(flags: &Vec<u8>) -> bool {
@@ -227,12 +250,18 @@ mod sealed {
                "Feature flags for `initial_routing_sync`.");
        define_feature!(5, UpfrontShutdownScript, [InitContext, NodeContext],
                "Feature flags for `option_upfront_shutdown_script`.");
+       define_feature!(7, GossipQueries, [InitContext, NodeContext],
+               "Feature flags for `gossip_queries`.");
        define_feature!(9, VariableLengthOnion, [InitContext, NodeContext],
                "Feature flags for `var_onion_optin`.");
+       define_feature!(13, StaticRemoteKey, [InitContext, NodeContext],
+               "Feature flags for `option_static_remotekey`.");
        define_feature!(15, PaymentSecret, [InitContext, NodeContext],
                "Feature flags for `payment_secret`.");
        define_feature!(17, BasicMPP, [InitContext, NodeContext],
                "Feature flags for `basic_mpp`.");
+       define_feature!(27, ShutdownAnySegwit, [InitContext, NodeContext],
+               "Feature flags for `opt_shutdown_anysegwit`.");
 
        #[cfg(test)]
        define_context!(TestingContext {
@@ -261,6 +290,8 @@ mod sealed {
 
 /// Tracks the set of features which a node implements, templated by the context in which it
 /// appears.
+///
+/// (C-not exported) as we map the concrete feature types below directly instead
 pub struct Features<T: sealed::Context> {
        /// Note that, for convenience, flags is LITTLE endian (despite being big-endian on the wire)
        flags: Vec<u8>,
@@ -330,7 +361,7 @@ impl InitFeatures {
 
 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,
@@ -340,7 +371,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,
@@ -429,12 +460,20 @@ impl<T: sealed::Context> Features<T> {
 }
 
 impl<T: sealed::DataLossProtect> Features<T> {
+       #[cfg(test)]
+       pub(crate) fn requires_data_loss_protect(&self) -> bool {
+               <T as sealed::DataLossProtect>::requires_feature(&self.flags)
+       }
        pub(crate) fn supports_data_loss_protect(&self) -> bool {
                <T as sealed::DataLossProtect>::supports_feature(&self.flags)
        }
 }
 
 impl<T: sealed::UpfrontShutdownScript> Features<T> {
+       #[cfg(test)]
+       pub(crate) fn requires_upfront_shutdown_script(&self) -> bool {
+               <T as sealed::UpfrontShutdownScript>::requires_feature(&self.flags)
+       }
        pub(crate) fn supports_upfront_shutdown_script(&self) -> bool {
                <T as sealed::UpfrontShutdownScript>::supports_feature(&self.flags)
        }
@@ -445,32 +484,74 @@ impl<T: sealed::UpfrontShutdownScript> Features<T> {
        }
 }
 
+
+impl<T: sealed::GossipQueries> Features<T> {
+       #[cfg(test)]
+       pub(crate) fn requires_gossip_queries(&self) -> bool {
+               <T as sealed::GossipQueries>::requires_feature(&self.flags)
+       }
+       pub(crate) fn supports_gossip_queries(&self) -> bool {
+               <T as sealed::GossipQueries>::supports_feature(&self.flags)
+       }
+       #[cfg(test)]
+       pub(crate) fn clear_gossip_queries(mut self) -> Self {
+               <T as sealed::GossipQueries>::clear_bits(&mut self.flags);
+               self
+       }
+}
+
 impl<T: sealed::VariableLengthOnion> Features<T> {
+       #[cfg(test)]
+       pub(crate) fn requires_variable_length_onion(&self) -> bool {
+               <T as sealed::VariableLengthOnion>::requires_feature(&self.flags)
+       }
        pub(crate) fn supports_variable_length_onion(&self) -> bool {
                <T as sealed::VariableLengthOnion>::supports_feature(&self.flags)
        }
 }
 
+impl<T: sealed::StaticRemoteKey> Features<T> {
+       pub(crate) fn supports_static_remote_key(&self) -> bool {
+               <T as sealed::StaticRemoteKey>::supports_feature(&self.flags)
+       }
+       #[cfg(test)]
+       pub(crate) fn requires_static_remote_key(&self) -> bool {
+               <T as sealed::StaticRemoteKey>::requires_feature(&self.flags)
+       }
+}
+
 impl<T: sealed::InitialRoutingSync> Features<T> {
        pub(crate) fn initial_routing_sync(&self) -> bool {
                <T as sealed::InitialRoutingSync>::supports_feature(&self.flags)
        }
+       // We are no longer setting initial_routing_sync now that gossip_queries
+       // is enabled. This feature is ignored by a peer when gossip_queries has 
+       // been negotiated.
+       #[cfg(test)]
        pub(crate) fn clear_initial_routing_sync(&mut self) {
                <T as sealed::InitialRoutingSync>::clear_bits(&mut self.flags)
        }
 }
 
 impl<T: sealed::PaymentSecret> Features<T> {
-       #[allow(dead_code)]
+       #[cfg(test)]
+       pub(crate) fn requires_payment_secret(&self) -> bool {
+               <T as sealed::PaymentSecret>::requires_feature(&self.flags)
+       }
        // Note that we never need to test this since what really matters is the invoice - iff the
        // invoice provides a payment_secret, we assume that we can use it (ie that the recipient
        // supports payment_secret).
+       #[allow(dead_code)]
        pub(crate) fn supports_payment_secret(&self) -> bool {
                <T as sealed::PaymentSecret>::supports_feature(&self.flags)
        }
 }
 
 impl<T: sealed::BasicMPP> Features<T> {
+       #[cfg(test)]
+       pub(crate) fn requires_basic_mpp(&self) -> bool {
+               <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 {
@@ -478,6 +559,17 @@ impl<T: sealed::BasicMPP> Features<T> {
        }
 }
 
+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);
@@ -505,7 +597,7 @@ mod tests {
        use super::{ChannelFeatures, InitFeatures, NodeFeatures};
 
        #[test]
-       fn sanity_test_our_features() {
+       fn sanity_test_known_features() {
                assert!(!ChannelFeatures::known().requires_unknown_bits());
                assert!(!ChannelFeatures::known().supports_unknown_bits());
                assert!(!InitFeatures::known().requires_unknown_bits());
@@ -515,18 +607,41 @@ mod tests {
 
                assert!(InitFeatures::known().supports_upfront_shutdown_script());
                assert!(NodeFeatures::known().supports_upfront_shutdown_script());
+               assert!(!InitFeatures::known().requires_upfront_shutdown_script());
+               assert!(!NodeFeatures::known().requires_upfront_shutdown_script());
+
+               assert!(InitFeatures::known().supports_gossip_queries());
+               assert!(NodeFeatures::known().supports_gossip_queries());
+               assert!(!InitFeatures::known().requires_gossip_queries());
+               assert!(!NodeFeatures::known().requires_gossip_queries());
 
                assert!(InitFeatures::known().supports_data_loss_protect());
                assert!(NodeFeatures::known().supports_data_loss_protect());
+               assert!(!InitFeatures::known().requires_data_loss_protect());
+               assert!(!NodeFeatures::known().requires_data_loss_protect());
 
                assert!(InitFeatures::known().supports_variable_length_onion());
                assert!(NodeFeatures::known().supports_variable_length_onion());
+               assert!(!InitFeatures::known().requires_variable_length_onion());
+               assert!(!NodeFeatures::known().requires_variable_length_onion());
+
+               assert!(InitFeatures::known().supports_static_remote_key());
+               assert!(NodeFeatures::known().supports_static_remote_key());
+               assert!(InitFeatures::known().requires_static_remote_key());
+               assert!(NodeFeatures::known().requires_static_remote_key());
 
                assert!(InitFeatures::known().supports_payment_secret());
                assert!(NodeFeatures::known().supports_payment_secret());
+               assert!(!InitFeatures::known().requires_payment_secret());
+               assert!(!NodeFeatures::known().requires_payment_secret());
 
                assert!(InitFeatures::known().supports_basic_mpp());
                assert!(NodeFeatures::known().supports_basic_mpp());
+               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());
@@ -555,27 +670,32 @@ mod tests {
 
        #[test]
        fn convert_to_context_with_relevant_flags() {
-               let init_features = InitFeatures::known().clear_upfront_shutdown_script();
+               let init_features = InitFeatures::known().clear_upfront_shutdown_script().clear_gossip_queries();
                assert!(init_features.initial_routing_sync());
                assert!(!init_features.supports_upfront_shutdown_script());
+               assert!(!init_features.supports_gossip_queries());
 
                let node_features: NodeFeatures = init_features.to_context();
                {
                        // Check that the flags are as expected:
                        // - option_data_loss_protect
-                       // - var_onion_optin | payment_secret
+                       // - 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], 0b10000010);
+                       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:
                // - initial_routing_sync was not applicable to NodeContext
                // - upfront_shutdown_script was cleared before converting
+               // - gossip_queries was cleared before converting
                let features: InitFeatures = node_features.to_context_internal();
                assert!(!features.initial_routing_sync());
                assert!(!features.supports_upfront_shutdown_script());
+               assert!(!init_features.supports_gossip_queries());
        }
 }