X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Ffeatures.rs;h=8ccbf4166bbe71294a64309ed4832b9364845fa9;hb=adc1b55a6fa064852d838ceb91b11e6b228d169e;hp=b372e6af6bf3df3fcf50a8c2ea3177c7f9989e07;hpb=ee17faff904b0be91902b64e2fbcb05f9db28a51;p=rust-lightning diff --git a/lightning/src/ln/features.rs b/lightning/src/ln/features.rs index b372e6af..8ccbf416 100644 --- a/lightning/src/ln/features.rs +++ b/lightning/src/ln/features.rs @@ -45,31 +45,43 @@ //! (see [BOLT-2](https://github.com/lightning/bolts/blob/master/02-peer-protocol.md) for more information). //! - `OnionMessages` - requires/supports forwarding onion messages //! (see [BOLT-7](https://github.com/lightning/bolts/pull/759/files) for more information). -//! TODO: update link +// TODO: update link //! - `ChannelType` - node supports the channel_type field in open/accept //! (see [BOLT-2](https://github.com/lightning/bolts/blob/master/02-peer-protocol.md) for more information). //! - `SCIDPrivacy` - supply channel aliases for routing //! (see [BOLT-2](https://github.com/lightning/bolts/blob/master/02-peer-protocol.md) for more information). +//! - `PaymentMetadata` - include additional data in invoices which is passed to recipients in the +//! onion. +//! (see [BOLT-11](https://github.com/lightning/bolts/blob/master/11-payment-encoding.md) for +//! more). +//! - `ZeroConf` - supports accepting HTLCs and using channels prior to funding confirmation +//! (see +//! [BOLT-2](https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#the-channel_ready-message) +//! 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). +//! - `AnchorsZeroFeeHtlcTx` - requires/supports that commitment transactions include anchor outputs +//! 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). //! //! [BOLT #9]: https://github.com/lightning/bolts/blob/master/09-features.md //! [messages]: crate::ln::msgs -use {io, io_extras}; -use prelude::*; +use crate::{io, io_extras}; +use crate::prelude::*; use core::{cmp, fmt}; use core::hash::{Hash, Hasher}; use core::marker::PhantomData; use bitcoin::bech32; use bitcoin::bech32::{Base32Len, FromBase32, ToBase32, u5, WriteBase32}; -use ln::msgs::DecodeError; -use util::ser::{Readable, Writeable, Writer}; +use crate::ln::msgs::DecodeError; +use crate::util::ser::{Readable, WithoutLength, Writeable, Writer}; mod sealed { - use prelude::*; - use ln::features::Features; + use crate::prelude::*; + use crate::ln::features::Features; /// The context in which [`Features`] are applicable. Defines which features are known to the /// implementation, though specification of them as required or optional is up to the code @@ -122,7 +134,7 @@ mod sealed { // Byte 1 VariableLengthOnion | StaticRemoteKey | PaymentSecret, // Byte 2 - BasicMPP | Wumbo, + BasicMPP | Wumbo | AnchorsZeroFeeHtlcTx, // Byte 3 ShutdownAnySegwit, // Byte 4 @@ -138,7 +150,7 @@ mod sealed { // Byte 1 VariableLengthOnion | StaticRemoteKey | PaymentSecret, // Byte 2 - BasicMPP | Wumbo, + BasicMPP | Wumbo | AnchorsZeroFeeHtlcTx, // Byte 3 ShutdownAnySegwit, // Byte 4 @@ -156,7 +168,26 @@ mod sealed { VariableLengthOnion | PaymentSecret, // Byte 2 BasicMPP, + // Byte 3 + , + // Byte 4 + , + // Byte 5 + , + // Byte 6 + PaymentMetadata, + ]); + define_context!(OfferContext, []); + define_context!(InvoiceRequestContext, []); + define_context!(Bolt12InvoiceContext, [ + // Byte 0 + , + // Byte 1 + , + // Byte 2 + BasicMPP, ]); + define_context!(BlindedHopContext, []); // This isn't a "real" feature context, and is only used in the channel_type field in an // `OpenChannel` message. define_context!(ChannelTypeContext, [ @@ -165,7 +196,7 @@ mod sealed { // Byte 1 StaticRemoteKey, // Byte 2 - , + AnchorsZeroFeeHtlcTx, // Byte 3 , // Byte 4 @@ -244,6 +275,7 @@ mod sealed { } flags[Self::BYTE_OFFSET] |= Self::REQUIRED_MASK; + flags[Self::BYTE_OFFSET] &= !Self::OPTIONAL_MASK; } /// Sets the feature's optional (odd) bit in the given flags. @@ -340,12 +372,15 @@ mod sealed { define_feature!(15, PaymentSecret, [InitContext, NodeContext, InvoiceContext], "Feature flags for `payment_secret`.", set_payment_secret_optional, set_payment_secret_required, supports_payment_secret, requires_payment_secret); - define_feature!(17, BasicMPP, [InitContext, NodeContext, InvoiceContext], + define_feature!(17, BasicMPP, [InitContext, NodeContext, InvoiceContext, Bolt12InvoiceContext], "Feature flags for `basic_mpp`.", set_basic_mpp_optional, set_basic_mpp_required, supports_basic_mpp, requires_basic_mpp); define_feature!(19, Wumbo, [InitContext, NodeContext], "Feature flags for `option_support_large_channel` (aka wumbo channels).", set_wumbo_optional, set_wumbo_required, supports_wumbo, requires_wumbo); + 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!(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); @@ -358,15 +393,20 @@ mod sealed { define_feature!(47, SCIDPrivacy, [InitContext, NodeContext, ChannelTypeContext], "Feature flags for only forwarding with SCID aliasing. Called `option_scid_alias` in the BOLTs", set_scid_privacy_optional, set_scid_privacy_required, supports_scid_privacy, requires_scid_privacy); + define_feature!(49, PaymentMetadata, [InvoiceContext], + "Feature flags for payment metadata in invoices.", set_payment_metadata_optional, + set_payment_metadata_required, supports_payment_metadata, requires_payment_metadata); define_feature!(51, ZeroConf, [InitContext, NodeContext, ChannelTypeContext], "Feature flags for accepting channels with zero confirmations. Called `option_zeroconf` in the BOLTs", set_zero_conf_optional, set_zero_conf_required, supports_zero_conf, requires_zero_conf); define_feature!(55, Keysend, [NodeContext], "Feature flags for keysend payments.", set_keysend_optional, set_keysend_required, supports_keysend, requires_keysend); + // Note: update the module-level docs when a new feature bit is added! #[cfg(test)] - define_feature!(123456789, UnknownFeature, [NodeContext, ChannelContext, InvoiceContext], + define_feature!(123456789, UnknownFeature, + [NodeContext, ChannelContext, InvoiceContext, OfferContext, InvoiceRequestContext, Bolt12InvoiceContext, BlindedHopContext], "Feature flags for an unknown feature used in testing.", set_unknown_feature_optional, set_unknown_feature_required, supports_unknown_test_feature, requires_unknown_test_feature); } @@ -374,7 +414,7 @@ mod sealed { /// Tracks the set of features which a node implements, templated by the context in which it /// appears. /// -/// (C-not exported) as we map the concrete feature types below directly instead +/// This is not exported to bindings users as we map the concrete feature types below directly instead #[derive(Eq)] pub struct Features { /// Note that, for convenience, flags is LITTLE endian (despite being big-endian on the wire) @@ -425,6 +465,14 @@ pub type NodeFeatures = Features; pub type ChannelFeatures = Features; /// Features used within an invoice. pub type InvoiceFeatures = Features; +/// Features used within an `offer`. +pub type OfferFeatures = Features; +/// Features used within an `invoice_request`. +pub type InvoiceRequestFeatures = Features; +/// Features used within an `invoice`. +pub type Bolt12InvoiceFeatures = Features; +/// Features used within BOLT 4 encrypted_data_tlv and BOLT 12 blinded_payinfo +pub type BlindedHopFeatures = Features; /// Features used within the channel_type field in an OpenChannel message. /// @@ -485,10 +533,10 @@ impl InvoiceFeatures { } 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(); + // Maps the relevant `InitFeatures` to `ChannelTypeFeatures`. Any unknown features to + // `ChannelTypeFeatures` are not included in the result. + pub(crate) fn from_init(init: &InitFeatures) -> Self { + let mut ret = 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() { @@ -595,7 +643,8 @@ impl Features { /// Create a Features given a set of flags, in little-endian. This is in reverse byte order from /// most on-the-wire encodings. - /// (C-not exported) as we don't support export across multiple T + /// + /// This is not exported to bindings users as we don't support export across multiple T pub fn from_le_bytes(flags: Vec) -> Features { Features { flags, @@ -658,6 +707,24 @@ impl Features { (byte & unknown_features) != 0 }) } + + // Returns true if the features within `self` are a subset of the features within `other`. + pub(crate) fn is_subset(&self, other: &Self) -> bool { + for (idx, byte) in self.flags.iter().enumerate() { + if let Some(other_byte) = other.flags.get(idx) { + if byte & other_byte != *byte { + // `self` has bits set that `other` doesn't. + return false; + } + } else { + if *byte > 0 { + // `self` has a non-zero byte that `other` doesn't. + return false; + } + } + } + true + } } impl Features { @@ -684,6 +751,27 @@ impl Features { } } +impl Features { + pub(crate) fn clear_scid_privacy(&mut self) { + ::clear_bits(&mut self.flags); + } +} + +impl Features { + pub(crate) fn clear_anchors_zero_fee_htlc_tx(&mut self) { + ::clear_bits(&mut self.flags); + } +} + +#[cfg(test)] +impl Features { + pub(crate) fn unknown() -> Self { + let mut features = Self::empty(); + features.set_unknown_feature_required(); + features + } +} + macro_rules! impl_feature_len_prefixed_write { ($features: ident) => { impl Writeable for $features { @@ -703,26 +791,47 @@ impl_feature_len_prefixed_write!(InitFeatures); impl_feature_len_prefixed_write!(ChannelFeatures); impl_feature_len_prefixed_write!(NodeFeatures); impl_feature_len_prefixed_write!(InvoiceFeatures); +impl_feature_len_prefixed_write!(BlindedHopFeatures); -// 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 { +// Some features only appear inside of TLVs, so they don't have a length prefix when serialized. +macro_rules! impl_feature_tlv_write { + ($features: ident) => { + impl Writeable for $features { + fn write(&self, w: &mut W) -> Result<(), io::Error> { + WithoutLength(self).write(w) + } + } + impl Readable for $features { + fn read(r: &mut R) -> Result { + Ok(WithoutLength::::read(r)?.0) + } + } + } +} + +impl_feature_tlv_write!(ChannelTypeFeatures); + +// Some features may appear both in a TLV record and as part of a TLV subtype sequence. The latter +// requires a length but the former does not. + +impl Writeable for WithoutLength<&Features> { fn write(&self, w: &mut W) -> Result<(), io::Error> { - self.write_be(w) + self.0.write_be(w) } } -impl Readable for ChannelTypeFeatures { + +impl Readable for WithoutLength> { fn read(r: &mut R) -> Result { let v = io_extras::read_to_end(r)?; - Ok(Self::from_be_bytes(v)) + Ok(WithoutLength(Features::::from_be_bytes(v))) } } #[cfg(test)] mod tests { - use super::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, InvoiceFeatures, NodeFeatures, sealed}; + use super::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, InvoiceFeatures, NodeFeatures, OfferFeatures, sealed}; use bitcoin::bech32::{Base32Len, FromBase32, ToBase32, u5}; + use crate::util::ser::{Readable, WithoutLength, Writeable}; #[test] fn sanity_test_unknown_bits() { @@ -747,7 +856,7 @@ mod tests { // Set a bunch of features we use, plus initial_routing_sync_required (which shouldn't get // converted as it's only relevant in an init context). init_features.set_initial_routing_sync_required(); - init_features.set_data_loss_protect_optional(); + init_features.set_data_loss_protect_required(); init_features.set_variable_length_onion_required(); init_features.set_static_remote_key_required(); init_features.set_payment_secret_required(); @@ -758,6 +867,7 @@ mod tests { init_features.set_channel_type_optional(); init_features.set_scid_privacy_optional(); init_features.set_zero_conf_optional(); + init_features.set_anchors_zero_fee_htlc_tx_optional(); assert!(init_features.initial_routing_sync()); assert!(!init_features.supports_upfront_shutdown_script()); @@ -766,7 +876,7 @@ mod tests { let node_features: NodeFeatures = init_features.to_context(); { // Check that the flags are as expected: - // - option_data_loss_protect + // - option_data_loss_protect (req) // - var_onion_optin (req) | static_remote_key (req) | payment_secret(req) // - basic_mpp | wumbo // - opt_shutdown_anysegwit @@ -774,9 +884,9 @@ mod tests { // - option_channel_type | option_scid_alias // - option_zeroconf assert_eq!(node_features.flags.len(), 7); - assert_eq!(node_features.flags[0], 0b00000010); + assert_eq!(node_features.flags[0], 0b00000001); assert_eq!(node_features.flags[1], 0b01010001); - assert_eq!(node_features.flags[2], 0b00001010); + assert_eq!(node_features.flags[2], 0b10001010); assert_eq!(node_features.flags[3], 0b00001000); assert_eq!(node_features.flags[4], 0b10000000); assert_eq!(node_features.flags[5], 0b10100000); @@ -796,13 +906,13 @@ mod tests { #[test] fn convert_to_context_with_unknown_flags() { // Ensure the `from` context has fewer known feature bytes than the `to` context. - assert!(::KNOWN_FEATURE_MASK.len() < - ::KNOWN_FEATURE_MASK.len()); - let mut invoice_features = InvoiceFeatures::empty(); - invoice_features.set_unknown_feature_optional(); - assert!(invoice_features.supports_unknown_bits()); - let node_features: NodeFeatures = invoice_features.to_context(); - assert!(!node_features.supports_unknown_bits()); + assert!(::KNOWN_FEATURE_MASK.len() < + ::KNOWN_FEATURE_MASK.len()); + let mut channel_features = ChannelFeatures::empty(); + channel_features.set_unknown_feature_optional(); + assert!(channel_features.supports_unknown_bits()); + let invoice_features: InvoiceFeatures = channel_features.to_context_internal(); + assert!(!invoice_features.supports_unknown_bits()); } #[test] @@ -816,6 +926,20 @@ mod tests { assert!(features.supports_payment_secret()); } + #[test] + fn encodes_features_without_length() { + let features = OfferFeatures::from_le_bytes(vec![1, 2, 3, 4, 5, 42, 100, 101]); + assert_eq!(features.flags.len(), 8); + + let mut serialized_features = Vec::new(); + WithoutLength(&features).write(&mut serialized_features).unwrap(); + assert_eq!(serialized_features.len(), 8); + + let deserialized_features = + WithoutLength::::read(&mut &serialized_features[..]).unwrap().0; + assert_eq!(features, deserialized_features); + } + #[test] fn invoice_features_encoding() { let features_as_u5s = vec![ @@ -853,7 +977,7 @@ mod tests { // required-StaticRemoteKey ChannelTypeFeatures. let mut init_features = InitFeatures::empty(); init_features.set_static_remote_key_optional(); - let converted_features = ChannelTypeFeatures::from_counterparty_init(&init_features); + let converted_features = ChannelTypeFeatures::from_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());