X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Ffeatures.rs;h=259bda85eee7925f8f455058803fa850b3f29259;hb=bfd11282131bd642d7920bf7ad9d1e59d329ccf8;hp=35c9410bc0b2b70ce4f7b5bd342b74134e950040;hpb=4894d52d30399c21b7994952a8de0d1d7848c58d;p=rust-lightning diff --git a/lightning/src/ln/features.rs b/lightning/src/ln/features.rs index 35c9410b..259bda85 100644 --- a/lightning/src/ln/features.rs +++ b/lightning/src/ln/features.rs @@ -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 Features { + /// Set this feature as optional. + pub fn $optional_setter(mut self) -> Self { + ::set_optional_bit(&mut self.flags); + self + } + + /// Set this feature as required. + pub fn $required_setter(mut self) -> Self { + ::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 = (::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; pub type NodeFeatures = Features; /// Features used within a `channel_announcement` message. pub type ChannelFeatures = Features; +/// Features used within an invoice. +pub type InvoiceFeatures = Features; impl InitFeatures { /// Writes all features present up to, and including, 13. @@ -359,6 +387,14 @@ impl InitFeatures { } } +impl InvoiceFeatures { + /// Converts `InvoiceFeatures` to `Features`. Only known `InvoiceFeatures` relevant to + /// context `C` are included in the result. + pub(crate) fn to_context(&self) -> Features { + self.to_context_internal() + } +} + impl Features { /// Create a blank Features with no features set pub fn empty() -> Self { @@ -368,9 +404,7 @@ impl Features { } } - /// 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(), @@ -553,7 +587,6 @@ impl Features { ::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 { ::supports_feature(&self.flags) } @@ -594,7 +627,7 @@ impl Readable for Features { #[cfg(test)] mod tests { - use super::{ChannelFeatures, InitFeatures, NodeFeatures}; + use super::{ChannelFeatures, InitFeatures, InvoiceFeatures, NodeFeatures}; #[test] fn sanity_test_known_features() { @@ -698,4 +731,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()); + } }