Implement core::hash::Hash more incl invoice::RawTaggedField
[rust-lightning] / lightning / src / ln / features.rs
index 5d908ee01a4957bd7c85d305043af8e5204523a2..d1f6b89db4f87e968e3624289331c00c476875fe 100644 (file)
 //! [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::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 {
@@ -299,6 +335,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 +363,11 @@ impl<T: sealed::Context> Clone for Features<T> {
                }
        }
 }
+impl<T: sealed::Context> Hash for Features<T> {
+       fn hash<H: Hasher>(&self, hasher: &mut H) {
+               self.flags.hash(hasher);
+       }
+}
 impl<T: sealed::Context> PartialEq for Features<T> {
        fn eq(&self, o: &Self) -> bool {
                self.flags.eq(&o.flags)
@@ -347,7 +390,7 @@ pub type InvoiceFeatures = Features<sealed::InvoiceContext>;
 
 impl InitFeatures {
        /// Writes all features present up to, and including, 13.
-       pub(crate) fn write_up_to_13<W: Writer>(&self, w: &mut W) -> Result<(), ::std::io::Error> {
+       pub(crate) fn write_up_to_13<W: Writer>(&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)?;
@@ -386,6 +429,18 @@ impl InvoiceFeatures {
        pub(crate) fn to_context<C: sealed::Context>(&self) -> Features<C> {
                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 {
@@ -499,7 +554,9 @@ impl<T: sealed::Context> Features<T> {
                &self.flags
        }
 
-       pub(crate) fn requires_unknown_bits(&self) -> bool {
+       /// 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();
@@ -540,6 +597,7 @@ impl<T: sealed::DataLossProtect> Features<T> {
        pub(crate) fn requires_data_loss_protect(&self) -> bool {
                <T as sealed::DataLossProtect>::requires_feature(&self.flags)
        }
+       #[cfg(test)]
        pub(crate) fn supports_data_loss_protect(&self) -> bool {
                <T as sealed::DataLossProtect>::supports_feature(&self.flags)
        }
@@ -643,7 +701,7 @@ impl<T: sealed::ShutdownAnySegwit> Features<T> {
 }
 
 impl<T: sealed::Context> Writeable for Features<T> {
-       fn write<W: Writer>(&self, w: &mut W) -> Result<(), ::std::io::Error> {
+       fn write<W: Writer>(&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
@@ -654,7 +712,7 @@ impl<T: sealed::Context> Writeable for Features<T> {
 }
 
 impl<T: sealed::Context> Readable for Features<T> {
-       fn read<R: ::std::io::Read>(r: &mut R) -> Result<Self, DecodeError> {
+       fn read<R: io::Read>(r: &mut R) -> Result<Self, DecodeError> {
                let mut flags: Vec<u8> = Readable::read(r)?;
                flags.reverse(); // Swap to little-endian
                Ok(Self {