Expose Features::from_le_bytes() method
[rust-lightning] / lightning / src / ln / features.rs
index 35c9410bc0b2b70ce4f7b5bd342b74134e950040..4a9526aff5687d3916230c9d0c6e28b7b0a2ce32 100644 (file)
@@ -12,8 +12,7 @@
 //! Lightning nodes advertise a supported set of operation through feature flags. Features are
 //! applicable for a specific context as indicated in some [messages]. [`Features`] encapsulates
 //! behavior for specifying and checking feature flags for a particular context. Each feature is
-//! defined internally by a trait specifying the corresponding flags (i.e., even and odd bits). A
-//! [`Context`] is used to parameterize [`Features`] and defines which features it can support.
+//! defined internally by a trait specifying the corresponding flags (i.e., even and odd bits).
 //!
 //! Whether a feature is considered "known" or "unknown" is relative to the implementation, whereas
 //! the term "supports" is used in reference to a particular set of [`Features`]. That is, a node
@@ -21,9 +20,7 @@
 //! And the implementation can interpret a feature if the feature is known to it.
 //!
 //! [BOLT #9]: https://github.com/lightningnetwork/lightning-rfc/blob/master/09-features.md
-//! [messages]: ../msgs/index.html
-//! [`Features`]: struct.Features.html
-//! [`Context`]: sealed/trait.Context.html
+//! [messages]: crate::ln::msgs
 
 use std::{cmp, fmt};
 use std::marker::PhantomData;
@@ -32,10 +29,10 @@ use ln::msgs::DecodeError;
 use util::ser::{Readable, Writeable, Writer};
 
 mod sealed {
+       use ln::features::Features;
+
        /// The context in which [`Features`] are applicable. Defines which features are required and
        /// which are optional for the context.
-       ///
-       /// [`Features`]: ../struct.Features.html
        pub trait Context {
                /// Features that are known to the implementation, where a required feature is indicated by
                /// its even bit and an optional feature is indicated by its odd bit.
@@ -49,8 +46,6 @@ mod sealed {
        /// Defines a [`Context`] by stating which features it requires and which are optional. Features
        /// are specified as a comma-separated list of bytes where each byte is a pipe-delimited list of
        /// feature identifiers.
-       ///
-       /// [`Context`]: trait.Context.html
        macro_rules! define_context {
                ($context: ident {
                        required_features: [$( $( $required_feature: ident )|*, )*],
@@ -140,13 +135,23 @@ mod sealed {
                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.
-       ///
-       /// [`Context`]: trait.Context.html
        macro_rules! define_feature {
-               ($odd_bit: expr, $feature: ident, [$($context: ty),+], $doc: expr) => {
+               ($odd_bit: expr, $feature: ident, [$($context: ty),+], $doc: expr, $optional_setter: ident,
+                $required_setter: ident) => {
                        #[doc = $doc]
                        ///
                        /// See [BOLT #9] for details.
@@ -231,6 +236,20 @@ mod sealed {
                                }
                        }
 
+                       impl <T: $feature> Features<T> {
+                               /// Set this feature as optional.
+                               pub fn $optional_setter(mut self) -> Self {
+                                       <T as $feature>::set_optional_bit(&mut self.flags);
+                                       self
+                               }
+
+                               /// Set this feature as required.
+                               pub fn $required_setter(mut self) -> Self {
+                                       <T as $feature>::set_required_bit(&mut self.flags);
+                                       self
+                               }
+                       }
+
                        $(
                                impl $feature for $context {
                                        // EVEN_BIT % 2 == 0
@@ -240,28 +259,34 @@ mod sealed {
                                        const ASSERT_ODD_BIT_PARITY: usize = (<Self as $feature>::ODD_BIT % 2) - 1;
                                }
                        )*
+
                }
        }
 
        define_feature!(1, DataLossProtect, [InitContext, NodeContext],
-               "Feature flags for `option_data_loss_protect`.");
+               "Feature flags for `option_data_loss_protect`.", set_data_loss_protect_optional,
+               set_data_loss_protect_required);
        // NOTE: Per Bolt #9, initial_routing_sync has no even bit.
-       define_feature!(3, InitialRoutingSync, [InitContext],
-               "Feature flags for `initial_routing_sync`.");
+       define_feature!(3, InitialRoutingSync, [InitContext], "Feature flags for `initial_routing_sync`.",
+               set_initial_routing_sync_optional, set_initial_routing_sync_required);
        define_feature!(5, UpfrontShutdownScript, [InitContext, NodeContext],
-               "Feature flags for `option_upfront_shutdown_script`.");
+               "Feature flags for `option_upfront_shutdown_script`.", set_upfront_shutdown_script_optional,
+               set_upfront_shutdown_script_required);
        define_feature!(7, GossipQueries, [InitContext, NodeContext],
-               "Feature flags for `gossip_queries`.");
-       define_feature!(9, VariableLengthOnion, [InitContext, NodeContext],
-               "Feature flags for `var_onion_optin`.");
+               "Feature flags for `gossip_queries`.", set_gossip_queries_optional, set_gossip_queries_required);
+       define_feature!(9, VariableLengthOnion, [InitContext, NodeContext, InvoiceContext],
+               "Feature flags for `var_onion_optin`.", set_variable_length_onion_optional,
+               set_variable_length_onion_required);
        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`.");
+               "Feature flags for `option_static_remotekey`.", set_static_remote_key_optional,
+               set_static_remote_key_required);
+       define_feature!(15, PaymentSecret, [InitContext, NodeContext, InvoiceContext],
+               "Feature flags for `payment_secret`.", set_payment_secret_optional, set_payment_secret_required);
+       define_feature!(17, BasicMPP, [InitContext, NodeContext, InvoiceContext],
+               "Feature flags for `basic_mpp`.", set_basic_mpp_optional, set_basic_mpp_required);
        define_feature!(27, ShutdownAnySegwit, [InitContext, NodeContext],
-               "Feature flags for `opt_shutdown_anysegwit`.");
+               "Feature flags for `opt_shutdown_anysegwit`.", set_shutdown_any_segwit_optional,
+               set_shutdown_any_segwit_required);
 
        #[cfg(test)]
        define_context!(TestingContext {
@@ -285,7 +310,8 @@ mod sealed {
 
        #[cfg(test)]
        define_feature!(23, UnknownFeature, [TestingContext],
-               "Feature flags for an unknown feature used in testing.");
+               "Feature flags for an unknown feature used in testing.", set_unknown_feature_optional,
+               set_unknown_feature_required);
 }
 
 /// Tracks the set of features which a node implements, templated by the context in which it
@@ -323,6 +349,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.
@@ -359,6 +387,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 {
@@ -368,9 +404,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
+       /// Creates a Features with the bits set which are known by the implementation
        pub fn known() -> Self {
                Self {
                        flags: T::KNOWN_FEATURE_FLAGS.to_vec(),
@@ -393,7 +427,6 @@ impl<T: sealed::Context> Features<T> {
                Features::<C> { flags, mark: PhantomData, }
        }
 
-       #[cfg(test)]
        /// Create a Features given a set of flags, in LE.
        pub fn from_le_bytes(flags: Vec<u8>) -> Features<T> {
                Features {
@@ -553,7 +586,6 @@ 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)
        }
@@ -594,7 +626,7 @@ impl<T: sealed::Context> Readable for Features<T> {
 
 #[cfg(test)]
 mod tests {
-       use super::{ChannelFeatures, InitFeatures, NodeFeatures};
+       use super::{ChannelFeatures, InitFeatures, InvoiceFeatures, NodeFeatures};
 
        #[test]
        fn sanity_test_known_features() {
@@ -698,4 +730,15 @@ mod tests {
                assert!(!features.supports_upfront_shutdown_script());
                assert!(!init_features.supports_gossip_queries());
        }
+
+       #[test]
+       fn set_feature_bits() {
+               let features = InvoiceFeatures::empty()
+                       .set_basic_mpp_optional()
+                       .set_payment_secret_required();
+               assert!(features.supports_basic_mpp());
+               assert!(!features.requires_basic_mpp());
+               assert!(features.requires_payment_secret());
+               assert!(features.supports_payment_secret());
+       }
 }