//! and HTLC transactions are pre-signed with zero fee (see
//! [BOLT-3](https://github.com/lightning/bolts/blob/master/03-transactions.md) for more
//! information).
+//! - `RouteBlinding` - requires/supports that a node can relay payments over blinded paths
+//! (see [BOLT-4](https://github.com/lightning/bolts/blob/master/04-onion-routing.md#route-blinding) for more information).
//! - `ShutdownAnySegwit` - requires/supports that future segwit versions are allowed in `shutdown`
//! (see [BOLT-2](https://github.com/lightning/bolts/blob/master/02-peer-protocol.md) for more information).
//! - `OnionMessages` - requires/supports forwarding onion messages
//! for more info).
//! - `Keysend` - send funds to a node without an invoice
//! (see the [`Keysend` feature assignment proposal](https://github.com/lightning/bolts/issues/605#issuecomment-606679798) for more information).
+//! - `Trampoline` - supports receiving and forwarding Trampoline payments
+//! (see the [`Trampoline` feature proposal](https://github.com/lightning/bolts/pull/836) for more information).
//!
//! LDK knows about the following features, but does not support them:
//! - `AnchorsNonzeroFeeHtlcTx` - the initial version of anchor outputs, which was later found to be
//! [BOLT #9]: https://github.com/lightning/bolts/blob/master/09-features.md
//! [messages]: crate::ln::msgs
-use crate::{io, io_extras};
+#[allow(unused_imports)]
use crate::prelude::*;
+
+use crate::{io, io_extras};
use core::{cmp, fmt};
use core::borrow::Borrow;
use core::hash::{Hash, Hasher};
use core::marker::PhantomData;
-use bitcoin::bech32;
-use bitcoin::bech32::{Base32Len, FromBase32, ToBase32, u5, WriteBase32};
+use bech32::{Base32Len, FromBase32, ToBase32, u5, WriteBase32};
use crate::ln::msgs::DecodeError;
use crate::util::ser::{Readable, WithoutLength, Writeable, Writer};
mod sealed {
+ #[allow(unused_imports)]
use crate::prelude::*;
use crate::ln::features::Features;
// Byte 2
BasicMPP | Wumbo | AnchorsNonzeroFeeHtlcTx | AnchorsZeroFeeHtlcTx,
// Byte 3
- ShutdownAnySegwit | Taproot,
+ RouteBlinding | ShutdownAnySegwit | Taproot,
// Byte 4
OnionMessages,
// Byte 5
ChannelType | SCIDPrivacy,
// Byte 6
ZeroConf,
+ // Byte 7
+ Trampoline,
]);
define_context!(NodeContext, [
// Byte 0
// Byte 2
BasicMPP | Wumbo | AnchorsNonzeroFeeHtlcTx | AnchorsZeroFeeHtlcTx,
// Byte 3
- ShutdownAnySegwit | Taproot,
+ RouteBlinding | ShutdownAnySegwit | Taproot,
// Byte 4
OnionMessages,
// Byte 5
ChannelType | SCIDPrivacy,
// Byte 6
ZeroConf | Keysend,
+ // Byte 7
+ Trampoline,
]);
define_context!(ChannelContext, []);
define_context!(Bolt11InvoiceContext, [
,
// Byte 6
PaymentMetadata,
+ // Byte 7
+ Trampoline,
]);
define_context!(OfferContext, []);
define_context!(InvoiceRequestContext, []);
define_feature!(23, AnchorsZeroFeeHtlcTx, [InitContext, NodeContext, ChannelTypeContext],
"Feature flags for `option_anchors_zero_fee_htlc_tx`.", set_anchors_zero_fee_htlc_tx_optional,
set_anchors_zero_fee_htlc_tx_required, supports_anchors_zero_fee_htlc_tx, requires_anchors_zero_fee_htlc_tx);
+ define_feature!(25, RouteBlinding, [InitContext, NodeContext],
+ "Feature flags for `option_route_blinding`.", set_route_blinding_optional,
+ set_route_blinding_required, supports_route_blinding, requires_route_blinding);
define_feature!(27, ShutdownAnySegwit, [InitContext, NodeContext],
"Feature flags for `opt_shutdown_anysegwit`.", set_shutdown_any_segwit_optional,
set_shutdown_any_segwit_required, supports_shutdown_anysegwit, requires_shutdown_anysegwit);
define_feature!(55, Keysend, [NodeContext],
"Feature flags for keysend payments.", set_keysend_optional, set_keysend_required,
supports_keysend, requires_keysend);
+ define_feature!(57, Trampoline, [InitContext, NodeContext, Bolt11InvoiceContext],
+ "Feature flags for Trampoline routing.", set_trampoline_routing_optional, set_trampoline_routing_required,
+ supports_trampoline_routing, requires_trampoline_routing);
// Note: update the module-level docs when a new feature bit is added!
#[cfg(test)]
set_unknown_feature_required, supports_unknown_test_feature, requires_unknown_test_feature);
}
+const ANY_REQUIRED_FEATURES_MASK: u8 = 0b01_01_01_01;
+const ANY_OPTIONAL_FEATURES_MASK: u8 = 0b10_10_10_10;
+
/// Tracks the set of features which a node implements, templated by the context in which it
/// appears.
///
}
impl<T: sealed::Context> Hash for Features<T> {
fn hash<H: Hasher>(&self, hasher: &mut H) {
- self.flags.hash(hasher);
+ let mut nonzero_flags = &self.flags[..];
+ while nonzero_flags.last() == Some(&0) {
+ nonzero_flags = &nonzero_flags[..nonzero_flags.len() - 1];
+ }
+ nonzero_flags.hash(hasher);
}
}
impl<T: sealed::Context> PartialEq for Features<T> {
fn eq(&self, o: &Self) -> bool {
- self.flags.eq(&o.flags)
+ let mut o_iter = o.flags.iter();
+ let mut self_iter = self.flags.iter();
+ loop {
+ match (o_iter.next(), self_iter.next()) {
+ (Some(o), Some(us)) => if o != us { return false },
+ (Some(b), None) | (None, Some(b)) => if *b != 0 { return false },
+ (None, None) => return true,
+ }
+ }
}
}
impl<T: sealed::Context> PartialOrd for Features<T> {
// 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;
+ *byte |= (*byte & ANY_OPTIONAL_FEATURES_MASK) >> 1;
+ *byte &= ANY_REQUIRED_FEATURES_MASK;
}
ret
}
}
pub(crate) fn supports_any_optional_bits(&self) -> bool {
- self.flags.iter().any(|&byte| (byte & 0b10_10_10_10) != 0)
+ self.flags.iter().any(|&byte| (byte & ANY_OPTIONAL_FEATURES_MASK) != 0)
}
/// Returns true if this `Features` object contains required features unknown by `other`.
// Bitwise AND-ing with all even bits set except for known features will select required
// unknown features.
self.flags.iter().enumerate().any(|(i, &byte)| {
- const REQUIRED_FEATURES: u8 = 0b01_01_01_01;
- const OPTIONAL_FEATURES: u8 = 0b10_10_10_10;
- let unknown_features = if i < other.flags.len() {
- // Form a mask similar to !T::KNOWN_FEATURE_MASK only for `other`
- !(other.flags[i]
- | ((other.flags[i] >> 1) & REQUIRED_FEATURES)
- | ((other.flags[i] << 1) & OPTIONAL_FEATURES))
- } else {
- 0b11_11_11_11
- };
- (byte & (REQUIRED_FEATURES & unknown_features)) != 0
+ let unknown_features = unset_features_mask_at_position(other, i);
+ (byte & (ANY_REQUIRED_FEATURES_MASK & unknown_features)) != 0
})
}
+ pub(crate) fn required_unknown_bits_from(&self, other: &Self) -> Vec<usize> {
+ let mut unknown_bits = Vec::new();
+
+ // Bitwise AND-ing with all even bits set except for known features will select required
+ // unknown features.
+ self.flags.iter().enumerate().for_each(|(i, &byte)| {
+ let unknown_features = unset_features_mask_at_position(other, i);
+ if byte & unknown_features != 0 {
+ for bit in (0..8).step_by(2) {
+ if ((byte & unknown_features) >> bit) & 1 == 1 {
+ unknown_bits.push(i * 8 + bit);
+ }
+ }
+ }
+ });
+
+ unknown_bits
+ }
+
/// Returns true if this `Features` object contains unknown feature flags which are set as
/// "required".
pub fn requires_unknown_bits(&self) -> bool {
// unknown features.
let byte_count = T::KNOWN_FEATURE_MASK.len();
self.flags.iter().enumerate().any(|(i, &byte)| {
- let required_features = 0b01_01_01_01;
let unknown_features = if i < byte_count {
!T::KNOWN_FEATURE_MASK[i]
} else {
0b11_11_11_11
};
- (byte & (required_features & unknown_features)) != 0
+ (byte & (ANY_REQUIRED_FEATURES_MASK & unknown_features)) != 0
})
}
}
}
+impl<T: sealed::RouteBlinding> Features<T> {
+ #[cfg(test)]
+ pub(crate) fn clear_route_blinding(&mut self) {
+ <T as sealed::RouteBlinding>::clear_bits(&mut self.flags);
+ }
+}
+
#[cfg(test)]
impl<T: sealed::UnknownFeature> Features<T> {
pub(crate) fn unknown() -> Self {
}
}
+pub(crate) fn unset_features_mask_at_position<T: sealed::Context>(other: &Features<T>, index: usize) -> u8 {
+ if index < other.flags.len() {
+ // Form a mask similar to !T::KNOWN_FEATURE_MASK only for `other`
+ !(other.flags[index]
+ | ((other.flags[index] >> 1) & ANY_REQUIRED_FEATURES_MASK)
+ | ((other.flags[index] << 1) & ANY_OPTIONAL_FEATURES_MASK))
+ } else {
+ 0b11_11_11_11
+ }
+}
+
#[cfg(test)]
mod tests {
use super::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, Bolt11InvoiceFeatures, NodeFeatures, OfferFeatures, sealed};
- use bitcoin::bech32::{Base32Len, FromBase32, ToBase32, u5};
+ use bech32::{Base32Len, FromBase32, ToBase32, u5};
use crate::util::ser::{Readable, WithoutLength, Writeable};
#[test]
features.set_unknown_feature_required();
assert!(features.requires_unknown_bits());
assert!(features.supports_unknown_bits());
+ assert_eq!(features.required_unknown_bits_from(&ChannelFeatures::empty()), vec![123456788]);
let mut features = ChannelFeatures::empty();
features.set_unknown_feature_optional();
assert!(!features.requires_unknown_bits());
assert!(features.supports_unknown_bits());
+ assert_eq!(features.required_unknown_bits_from(&ChannelFeatures::empty()), vec![]);
+
+ let mut features = ChannelFeatures::empty();
+ features.set_unknown_feature_required();
+ features.set_custom_bit(123456786).unwrap();
+ assert!(features.requires_unknown_bits());
+ assert!(features.supports_unknown_bits());
+ assert_eq!(features.required_unknown_bits_from(&ChannelFeatures::empty()), vec![123456786, 123456788]);
+
+ let mut limiter = ChannelFeatures::empty();
+ limiter.set_unknown_feature_optional();
+ assert_eq!(features.required_unknown_bits_from(&limiter), vec![123456786]);
}
#[test]
init_features.set_basic_mpp_optional();
init_features.set_wumbo_optional();
init_features.set_anchors_zero_fee_htlc_tx_optional();
+ init_features.set_route_blinding_optional();
init_features.set_shutdown_any_segwit_optional();
init_features.set_onion_messages_optional();
init_features.set_channel_type_optional();
// - option_data_loss_protect (req)
// - var_onion_optin (req) | static_remote_key (req) | payment_secret(req)
// - basic_mpp | wumbo | option_anchors_zero_fee_htlc_tx
- // - opt_shutdown_anysegwit
+ // - option_route_blinding | opt_shutdown_anysegwit
// - onion_messages
// - option_channel_type | option_scid_alias
// - option_zeroconf
assert_eq!(node_features.flags[0], 0b00000001);
assert_eq!(node_features.flags[1], 0b01010001);
assert_eq!(node_features.flags[2], 0b10001010);
- assert_eq!(node_features.flags[3], 0b00001000);
+ assert_eq!(node_features.flags[3], 0b00001010);
assert_eq!(node_features.flags[4], 0b10000000);
assert_eq!(node_features.flags[5], 0b10100000);
assert_eq!(node_features.flags[6], 0b00001000);
assert!(!converted_features.supports_any_optional_bits());
assert!(converted_features.requires_static_remote_key());
}
+
+ #[test]
+ #[cfg(feature = "std")]
+ fn test_excess_zero_bytes_ignored() {
+ // Checks that `Hash` and `PartialEq` ignore excess zero bytes, which may appear due to
+ // feature conversion or because a peer serialized their feature poorly.
+ use std::collections::hash_map::DefaultHasher;
+ use std::hash::{Hash, Hasher};
+
+ let mut zerod_features = InitFeatures::empty();
+ zerod_features.flags = vec![0];
+ let empty_features = InitFeatures::empty();
+ assert!(empty_features.flags.is_empty());
+
+ assert_eq!(zerod_features, empty_features);
+
+ let mut zerod_hash = DefaultHasher::new();
+ zerod_features.hash(&mut zerod_hash);
+ let mut empty_hash = DefaultHasher::new();
+ empty_features.hash(&mut empty_hash);
+ assert_eq!(zerod_hash.finish(), empty_hash.finish());
+ }
}