X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Ffeatures.rs;h=e78fa3d50d2d05c5bfcafe1fd58eb1b654c167f7;hb=0dfcacd22c23f69b6526c9c6507d21427a2b7ccb;hp=b459baf06580bff8414715b82c1845e7334c23ee;hpb=12461fcba179a1b6726f5c2557d12cb1f1b33b25;p=rust-lightning diff --git a/lightning/src/ln/features.rs b/lightning/src/ln/features.rs index b459baf0..e78fa3d5 100644 --- a/lightning/src/ln/features.rs +++ b/lightning/src/ln/features.rs @@ -22,6 +22,7 @@ //! [BOLT #9]: https://github.com/lightningnetwork/lightning-rfc/blob/master/09-features.md //! [messages]: crate::ln::msgs +use io; use prelude::*; use core::{cmp, fmt}; use core::marker::PhantomData; @@ -89,6 +90,28 @@ mod sealed { )* ]; } + + impl alloc::fmt::Display for Features<$context> { + fn fmt(&self, fmt: &mut alloc::fmt::Formatter) -> Result<(), alloc::fmt::Error> { + $( + $( + fmt.write_fmt(format_args!("{}: {}, ", stringify!($required_feature), + if <$context as $required_feature>::requires_feature(&self.flags) { "required" } + else if <$context as $required_feature>::supports_feature(&self.flags) { "supported" } + else { "not supported" }))?; + )* + $( + fmt.write_fmt(format_args!("{}: {}, ", stringify!($optional_feature), + if <$context as $optional_feature>::requires_feature(&self.flags) { "required" } + else if <$context as $optional_feature>::supports_feature(&self.flags) { "supported" } + else { "not supported" }))?; + )* + )* + fmt.write_fmt(format_args!("unknown flags: {}", + if self.requires_unknown_bits() { "required" } + else if self.supports_unknown_bits() { "supported" } else { "none" })) + } + } }; } @@ -124,6 +147,12 @@ mod sealed { , // Byte 3 , + // Byte 4 + , + // Byte 5 + , + // Byte 6 + , ], optional_features: [ // Byte 0 @@ -134,6 +163,12 @@ mod sealed { BasicMPP, // Byte 3 ShutdownAnySegwit, + // Byte 4 + , + // Byte 5 + , + // Byte 6 + Keysend, ], }); define_context!(ChannelContext { @@ -299,29 +334,11 @@ mod sealed { define_feature!(27, ShutdownAnySegwit, [InitContext, NodeContext], "Feature flags for `opt_shutdown_anysegwit`.", set_shutdown_any_segwit_optional, set_shutdown_any_segwit_required); + define_feature!(55, Keysend, [NodeContext], + "Feature flags for keysend payments.", set_keysend_optional, set_keysend_required); #[cfg(test)] - define_context!(TestingContext { - required_features: [ - // Byte 0 - , - // Byte 1 - , - // Byte 2 - UnknownFeature, - ], - optional_features: [ - // Byte 0 - , - // Byte 1 - , - // Byte 2 - , - ], - }); - - #[cfg(test)] - define_feature!(23, UnknownFeature, [TestingContext], + define_feature!(123456789, UnknownFeature, [NodeContext, ChannelContext, InvoiceContext], "Feature flags for an unknown feature used in testing.", set_unknown_feature_optional, set_unknown_feature_required); } @@ -367,7 +384,7 @@ pub type InvoiceFeatures = Features; impl InitFeatures { /// Writes all features present up to, and including, 13. - pub(crate) fn write_up_to_13(&self, w: &mut W) -> Result<(), ::std::io::Error> { + pub(crate) fn write_up_to_13(&self, w: &mut W) -> Result<(), io::Error> { let len = cmp::min(2, self.flags.len()); w.size_hint(len + 2); (len as u16).write(w)?; @@ -406,6 +423,18 @@ impl InvoiceFeatures { pub(crate) fn to_context(&self) -> Features { self.to_context_internal() } + + /// Getting a route for a keysend payment to a private node requires providing the payee's + /// features (since they were not announced in a node announcement). However, keysend payments + /// don't have an invoice to pull the payee's features from, so this method is provided for use in + /// [`get_keysend_route`], thus omitting the need for payers to manually construct an + /// `InvoiceFeatures` for [`get_route`]. + /// + /// [`get_keysend_route`]: crate::routing::router::get_keysend_route + /// [`get_route`]: crate::routing::router::get_route + pub(crate) fn for_keysend() -> InvoiceFeatures { + InvoiceFeatures::empty().set_variable_length_onion_optional() + } } impl ToBase32 for InvoiceFeatures { @@ -490,13 +519,14 @@ impl Features { /// Converts `Features` to `Features`. Only known `T` features relevant to context `C` are /// included in the result. fn to_context_internal(&self) -> Features { - let byte_count = C::KNOWN_FEATURE_MASK.len(); + let from_byte_count = T::KNOWN_FEATURE_MASK.len(); + let to_byte_count = C::KNOWN_FEATURE_MASK.len(); let mut flags = Vec::new(); for (i, byte) in self.flags.iter().enumerate() { - if i < byte_count { - let known_source_features = T::KNOWN_FEATURE_MASK[i]; - let known_target_features = C::KNOWN_FEATURE_MASK[i]; - flags.push(byte & known_source_features & known_target_features); + if i < from_byte_count && i < to_byte_count { + let from_known_features = T::KNOWN_FEATURE_MASK[i]; + let to_known_features = C::KNOWN_FEATURE_MASK[i]; + flags.push(byte & from_known_features & to_known_features); } } Features:: { flags, mark: PhantomData, } @@ -552,21 +582,6 @@ impl Features { pub(crate) fn byte_count(&self) -> usize { self.flags.len() } - - #[cfg(test)] - pub(crate) fn set_required_unknown_bits(&mut self) { - ::set_required_bit(&mut self.flags); - } - - #[cfg(test)] - pub(crate) fn set_optional_unknown_bits(&mut self) { - ::set_optional_bit(&mut self.flags); - } - - #[cfg(test)] - pub(crate) fn clear_unknown_bits(&mut self) { - ::clear_bits(&mut self.flags); - } } impl Features { @@ -574,6 +589,7 @@ impl Features { pub(crate) fn requires_data_loss_protect(&self) -> bool { ::requires_feature(&self.flags) } + #[cfg(test)] pub(crate) fn supports_data_loss_protect(&self) -> bool { ::supports_feature(&self.flags) } @@ -677,7 +693,7 @@ impl Features { } impl Writeable for Features { - fn write(&self, w: &mut W) -> Result<(), ::std::io::Error> { + fn write(&self, w: &mut W) -> Result<(), io::Error> { w.size_hint(self.flags.len() + 2); (self.flags.len() as u16).write(w)?; for f in self.flags.iter().rev() { // Swap back to big-endian @@ -688,7 +704,7 @@ impl Writeable for Features { } impl Readable for Features { - fn read(r: &mut R) -> Result { + fn read(r: &mut R) -> Result { let mut flags: Vec = Readable::read(r)?; flags.reverse(); // Swap to little-endian Ok(Self { @@ -764,19 +780,15 @@ mod tests { #[test] fn sanity_test_unknown_bits() { - let mut features = ChannelFeatures::empty(); + let features = ChannelFeatures::empty(); assert!(!features.requires_unknown_bits()); assert!(!features.supports_unknown_bits()); - features.set_required_unknown_bits(); + let features = ChannelFeatures::empty().set_unknown_feature_required(); assert!(features.requires_unknown_bits()); assert!(features.supports_unknown_bits()); - features.clear_unknown_bits(); - assert!(!features.requires_unknown_bits()); - assert!(!features.supports_unknown_bits()); - - features.set_optional_unknown_bits(); + let features = ChannelFeatures::empty().set_unknown_feature_optional(); assert!(!features.requires_unknown_bits()); assert!(features.supports_unknown_bits()); } @@ -812,6 +824,16 @@ mod tests { assert!(!init_features.supports_gossip_queries()); } + #[test] + fn convert_to_context_with_unknown_flags() { + // Ensure the `from` context has fewer known feature bytes than the `to` context. + assert!(InvoiceFeatures::known().byte_count() < NodeFeatures::known().byte_count()); + let invoice_features = InvoiceFeatures::known().set_unknown_feature_optional(); + assert!(invoice_features.supports_unknown_bits()); + let node_features: NodeFeatures = invoice_features.to_context(); + assert!(!node_features.supports_unknown_bits()); + } + #[test] fn set_feature_bits() { let features = InvoiceFeatures::empty()