X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;ds=sidebyside;f=lightning%2Fsrc%2Fln%2Ffeatures.rs;h=32ba9de758632036942318c756f64708793e1b1a;hb=4d6c26248d85abe9a3c8aeefe31b4ebafd3b5bee;hp=5d908ee01a4957bd7c85d305043af8e5204523a2;hpb=d37b1dd6730535cebe0ce5d0434046848b244211;p=rust-lightning diff --git a/lightning/src/ln/features.rs b/lightning/src/ln/features.rs index 5d908ee0..32ba9de7 100644 --- a/lightning/src/ln/features.rs +++ b/lightning/src/ln/features.rs @@ -22,8 +22,10 @@ //! [BOLT #9]: https://github.com/lightningnetwork/lightning-rfc/blob/master/09-features.md //! [messages]: crate::ln::msgs +use {io, io_extras}; use prelude::*; use core::{cmp, fmt}; +use core::hash::{Hash, Hasher}; use core::marker::PhantomData; use bitcoin::bech32; @@ -89,6 +91,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 +148,12 @@ mod sealed { , // Byte 3 , + // Byte 4 + , + // Byte 5 + , + // Byte 6 + , ], optional_features: [ // Byte 0 @@ -134,6 +164,12 @@ mod sealed { BasicMPP, // Byte 3 ShutdownAnySegwit, + // Byte 4 + , + // Byte 5 + , + // Byte 6 + Keysend, ], }); define_context!(ChannelContext { @@ -158,6 +194,30 @@ mod sealed { BasicMPP, ], }); + // This isn't a "real" feature context, and is only used in the channel_type field in an + // `OpenChannel` message. + define_context!(ChannelTypeContext { + required_features: [ + // Byte 0 + , + // Byte 1 + StaticRemoteKey, + // Byte 2 + , + // Byte 3 + , + ], + optional_features: [ + // Byte 0 + , + // Byte 1 + , + // Byte 2 + , + // Byte 3 + , + ], + }); /// Defines a feature with the given bits for the specified [`Context`]s. The generated trait is /// useful for manipulating feature flags. @@ -289,7 +349,7 @@ mod sealed { 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], + define_feature!(13, StaticRemoteKey, [InitContext, NodeContext, ChannelTypeContext], "Feature flags for `option_static_remotekey`.", set_static_remote_key_optional, set_static_remote_key_required); define_feature!(15, PaymentSecret, [InitContext, NodeContext, InvoiceContext], @@ -299,6 +359,8 @@ 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_feature!(123456789, UnknownFeature, [NodeContext, ChannelContext, InvoiceContext], @@ -325,6 +387,11 @@ impl Clone for Features { } } } +impl Hash for Features { + fn hash(&self, hasher: &mut H) { + self.flags.hash(hasher); + } +} impl PartialEq for Features { fn eq(&self, o: &Self) -> bool { self.flags.eq(&o.flags) @@ -345,11 +412,22 @@ pub type ChannelFeatures = Features; /// Features used within an invoice. pub type InvoiceFeatures = Features; +/// Features used within the channel_type field in an OpenChannel message. +/// +/// A channel is always of some known "type", describing the transaction formats used and the exact +/// semantics of our interaction with our peer. +/// +/// Note that because a channel is a specific type which is proposed by the opener and accepted by +/// the counterparty, only required features are allowed here. +/// +/// This is serialized differently from other feature types - it is not prefixed by a length, and +/// thus must only appear inside a TLV where its length is known in advance. +pub type ChannelTypeFeatures = 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)?; for i in (0..len).rev() { if i == 0 { @@ -386,6 +464,40 @@ 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 + /// [`Payee::for_keysend`], thus omitting the need for payers to manually construct an + /// `InvoiceFeatures` for [`find_route`]. + /// + /// [`Payee::for_keysend`]: crate::routing::router::Payee::for_keysend + /// [`find_route`]: crate::routing::router::find_route + pub(crate) fn for_keysend() -> InvoiceFeatures { + InvoiceFeatures::empty().set_variable_length_onion_optional() + } +} + +impl ChannelTypeFeatures { + /// Constructs the implicit channel type based on the common supported types between us and our + /// counterparty + pub(crate) fn from_counterparty_init(counterparty_init: &InitFeatures) -> Self { + let mut ret = counterparty_init.to_context_internal(); + // ChannelTypeFeatures must only contain required bits, so we OR the required forms of all + // optional bits and then AND out the optional ones. + for byte in ret.flags.iter_mut() { + *byte |= (*byte & 0b10_10_10_10) >> 1; + *byte &= 0b01_01_01_01; + } + ret + } + + /// Constructs a ChannelTypeFeatures with only static_remotekey set + pub(crate) fn only_static_remote_key() -> Self { + let mut ret = Self::empty(); + ::set_required_bit(&mut ret.flags); + ret + } } impl ToBase32 for InvoiceFeatures { @@ -499,7 +611,28 @@ impl Features { &self.flags } - pub(crate) fn requires_unknown_bits(&self) -> bool { + fn write_be(&self, w: &mut W) -> Result<(), io::Error> { + for f in self.flags.iter().rev() { // Swap back to big-endian + f.write(w)?; + } + Ok(()) + } + + fn from_be_bytes(mut flags: Vec) -> Features { + flags.reverse(); // Swap to little-endian + Self { + flags, + mark: PhantomData, + } + } + + pub(crate) fn supports_any_optional_bits(&self) -> bool { + self.flags.iter().any(|&byte| (byte & 0b10_10_10_10) != 0) + } + + /// Returns true if this `Features` object contains unknown feature flags which are set as + /// "required". + pub fn requires_unknown_bits(&self) -> bool { // Bitwise AND-ing with all even bits set except for known features will select required // unknown features. let byte_count = T::KNOWN_FEATURE_MASK.len(); @@ -527,12 +660,6 @@ impl Features { (byte & unknown_features) != 0 }) } - - /// The number of bytes required to represent the feature flags present. This does not include - /// the length bytes which are included in the serialized form. - pub(crate) fn byte_count(&self) -> usize { - self.flags.len() - } } impl Features { @@ -540,6 +667,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) } @@ -641,32 +769,44 @@ impl Features { self } } - -impl Writeable for Features { - fn write(&self, w: &mut W) -> Result<(), ::std::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 - f.write(w)?; +macro_rules! impl_feature_len_prefixed_write { + ($features: ident) => { + impl Writeable for $features { + fn write(&self, w: &mut W) -> Result<(), io::Error> { + (self.flags.len() as u16).write(w)?; + self.write_be(w) + } + } + impl Readable for $features { + fn read(r: &mut R) -> Result { + Ok(Self::from_be_bytes(Vec::::read(r)?)) + } } - Ok(()) } } - -impl Readable for Features { - fn read(r: &mut R) -> Result { - let mut flags: Vec = Readable::read(r)?; - flags.reverse(); // Swap to little-endian - Ok(Self { - flags, - mark: PhantomData, - }) +impl_feature_len_prefixed_write!(InitFeatures); +impl_feature_len_prefixed_write!(ChannelFeatures); +impl_feature_len_prefixed_write!(NodeFeatures); +impl_feature_len_prefixed_write!(InvoiceFeatures); + +// Because ChannelTypeFeatures only appears inside of TLVs, it doesn't have a length prefix when +// serialized. Thus, we can't use `impl_feature_len_prefixed_write`, above, and have to write our +// own serialization. +impl Writeable for ChannelTypeFeatures { + fn write(&self, w: &mut W) -> Result<(), io::Error> { + self.write_be(w) + } +} +impl Readable for ChannelTypeFeatures { + fn read(r: &mut R) -> Result { + let v = io_extras::read_to_end(r)?; + Ok(Self::from_be_bytes(v)) } } #[cfg(test)] mod tests { - use super::{ChannelFeatures, InitFeatures, InvoiceFeatures, NodeFeatures}; + use super::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, InvoiceFeatures, NodeFeatures}; use bitcoin::bech32::{Base32Len, FromBase32, ToBase32, u5}; #[test] @@ -777,7 +917,7 @@ mod tests { #[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()); + assert!(InvoiceFeatures::known().flags.len() < NodeFeatures::known().flags.len()); let invoice_features = InvoiceFeatures::known().set_unknown_feature_optional(); assert!(invoice_features.supports_unknown_bits()); let node_features: NodeFeatures = invoice_features.to_context(); @@ -825,4 +965,15 @@ mod tests { let features_deserialized = InvoiceFeatures::from_base32(&features_as_u5s).unwrap(); assert_eq!(features, features_deserialized); } + + #[test] + fn test_channel_type_mapping() { + // If we map an InvoiceFeatures with StaticRemoteKey optional, it should map into a + // required-StaticRemoteKey ChannelTypeFeatures. + let init_features = InitFeatures::empty().set_static_remote_key_optional(); + let converted_features = ChannelTypeFeatures::from_counterparty_init(&init_features); + assert_eq!(converted_features, ChannelTypeFeatures::only_static_remote_key()); + assert!(!converted_features.supports_any_optional_bits()); + assert!(converted_features.requires_static_remote_key()); + } }