//! [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;
)*
];
}
+
+ 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" }))
+ }
+ }
};
}
,
// Byte 3
,
+ // Byte 4
+ ,
+ // Byte 5
+ ,
+ // Byte 6
+ ,
],
optional_features: [
// Byte 0
BasicMPP,
// Byte 3
ShutdownAnySegwit,
+ // Byte 4
+ ,
+ // Byte 5
+ ,
+ // Byte 6
+ Keysend,
],
});
define_context!(ChannelContext {
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],
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)?;
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 {
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)
}
}
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
}
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 {