|
22 | 22 | //! [BOLT #9]: https://github.com/lightningnetwork/lightning-rfc/blob/master/09-features.md
|
23 | 23 | //! [messages]: crate::ln::msgs
|
24 | 24 |
|
25 |
| -use io; |
| 25 | +use {io, io_extras}; |
26 | 26 | use prelude::*;
|
27 | 27 | use core::{cmp, fmt};
|
28 | 28 | use core::hash::{Hash, Hasher};
|
@@ -194,6 +194,30 @@ mod sealed {
|
194 | 194 | BasicMPP,
|
195 | 195 | ],
|
196 | 196 | });
|
| 197 | + // This isn't a "real" feature context, and is only used in the channel_type field in an |
| 198 | + // `OpenChannel` message. |
| 199 | + define_context!(ChannelTypeContext { |
| 200 | + required_features: [ |
| 201 | + // Byte 0 |
| 202 | + , |
| 203 | + // Byte 1 |
| 204 | + StaticRemoteKey, |
| 205 | + // Byte 2 |
| 206 | + , |
| 207 | + // Byte 3 |
| 208 | + , |
| 209 | + ], |
| 210 | + optional_features: [ |
| 211 | + // Byte 0 |
| 212 | + , |
| 213 | + // Byte 1 |
| 214 | + , |
| 215 | + // Byte 2 |
| 216 | + , |
| 217 | + // Byte 3 |
| 218 | + , |
| 219 | + ], |
| 220 | + }); |
197 | 221 |
|
198 | 222 | /// Defines a feature with the given bits for the specified [`Context`]s. The generated trait is
|
199 | 223 | /// useful for manipulating feature flags.
|
@@ -325,7 +349,7 @@ mod sealed {
|
325 | 349 | define_feature!(9, VariableLengthOnion, [InitContext, NodeContext, InvoiceContext],
|
326 | 350 | "Feature flags for `var_onion_optin`.", set_variable_length_onion_optional,
|
327 | 351 | set_variable_length_onion_required);
|
328 |
| - define_feature!(13, StaticRemoteKey, [InitContext, NodeContext], |
| 352 | + define_feature!(13, StaticRemoteKey, [InitContext, NodeContext, ChannelTypeContext], |
329 | 353 | "Feature flags for `option_static_remotekey`.", set_static_remote_key_optional,
|
330 | 354 | set_static_remote_key_required);
|
331 | 355 | define_feature!(15, PaymentSecret, [InitContext, NodeContext, InvoiceContext],
|
@@ -388,6 +412,18 @@ pub type ChannelFeatures = Features<sealed::ChannelContext>;
|
388 | 412 | /// Features used within an invoice.
|
389 | 413 | pub type InvoiceFeatures = Features<sealed::InvoiceContext>;
|
390 | 414 |
|
| 415 | +/// Features used within the channel_type field in an OpenChannel message. |
| 416 | +/// |
| 417 | +/// A channel is always of some known "type", describing the transaction formats used and the exact |
| 418 | +/// semantics of our interaction with our peer. |
| 419 | +/// |
| 420 | +/// Note that because a channel is a specific type which is proposed by the opener and accepted by |
| 421 | +/// the counterparty, only required features are allowed here. |
| 422 | +/// |
| 423 | +/// This is serialized differently from other feature types - it is not prefixed by a length, and |
| 424 | +/// thus must only appear inside a TLV where its length is known in advance. |
| 425 | +pub type ChannelTypeFeatures = Features<sealed::ChannelTypeContext>; |
| 426 | + |
391 | 427 | impl InitFeatures {
|
392 | 428 | /// Writes all features present up to, and including, 13.
|
393 | 429 | pub(crate) fn write_up_to_13<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
|
@@ -442,6 +478,28 @@ impl InvoiceFeatures {
|
442 | 478 | }
|
443 | 479 | }
|
444 | 480 |
|
| 481 | +impl ChannelTypeFeatures { |
| 482 | + /// Constructs the implicit channel type based on the common supported types between us and our |
| 483 | + /// counterparty |
| 484 | + pub(crate) fn from_counterparty_init(counterparty_init: &InitFeatures) -> Self { |
| 485 | + let mut ret = counterparty_init.to_context_internal(); |
| 486 | + // ChannelTypeFeatures must only contain required bits, so we OR the required forms of all |
| 487 | + // optional bits and then AND out the optional ones. |
| 488 | + for byte in ret.flags.iter_mut() { |
| 489 | + *byte |= (*byte & 0b10_10_10_10) >> 1; |
| 490 | + *byte &= 0b01_01_01_01; |
| 491 | + } |
| 492 | + ret |
| 493 | + } |
| 494 | + |
| 495 | + /// Constructs a ChannelTypeFeatures with only static_remotekey set |
| 496 | + pub(crate) fn only_static_remote_key() -> Self { |
| 497 | + let mut ret = Self::empty(); |
| 498 | + <sealed::ChannelTypeContext as sealed::StaticRemoteKey>::set_required_bit(&mut ret.flags); |
| 499 | + ret |
| 500 | + } |
| 501 | +} |
| 502 | + |
445 | 503 | impl ToBase32 for InvoiceFeatures {
|
446 | 504 | fn write_base32<W: WriteBase32>(&self, writer: &mut W) -> Result<(), <W as WriteBase32>::Err> {
|
447 | 505 | // Explanation for the "4": the normal way to round up when dividing is to add the divisor
|
@@ -553,6 +611,25 @@ impl<T: sealed::Context> Features<T> {
|
553 | 611 | &self.flags
|
554 | 612 | }
|
555 | 613 |
|
| 614 | + fn write_be<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> { |
| 615 | + for f in self.flags.iter().rev() { // Swap back to big-endian |
| 616 | + f.write(w)?; |
| 617 | + } |
| 618 | + Ok(()) |
| 619 | + } |
| 620 | + |
| 621 | + fn from_be_bytes(mut flags: Vec<u8>) -> Features<T> { |
| 622 | + flags.reverse(); // Swap to little-endian |
| 623 | + Self { |
| 624 | + flags, |
| 625 | + mark: PhantomData, |
| 626 | + } |
| 627 | + } |
| 628 | + |
| 629 | + pub(crate) fn supports_any_optional_bits(&self) -> bool { |
| 630 | + self.flags.iter().any(|&byte| (byte & 0b10_10_10_10) != 0) |
| 631 | + } |
| 632 | + |
556 | 633 | /// Returns true if this `Features` object contains unknown feature flags which are set as
|
557 | 634 | /// "required".
|
558 | 635 | pub fn requires_unknown_bits(&self) -> bool {
|
@@ -692,31 +769,44 @@ impl<T: sealed::ShutdownAnySegwit> Features<T> {
|
692 | 769 | self
|
693 | 770 | }
|
694 | 771 | }
|
695 |
| - |
696 |
| -impl<T: sealed::Context> Writeable for Features<T> { |
697 |
| - fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> { |
698 |
| - (self.flags.len() as u16).write(w)?; |
699 |
| - for f in self.flags.iter().rev() { // Swap back to big-endian |
700 |
| - f.write(w)?; |
| 772 | +macro_rules! impl_feature_len_prefixed_write { |
| 773 | + ($features: ident) => { |
| 774 | + impl Writeable for $features { |
| 775 | + fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> { |
| 776 | + (self.flags.len() as u16).write(w)?; |
| 777 | + self.write_be(w) |
| 778 | + } |
| 779 | + } |
| 780 | + impl Readable for $features { |
| 781 | + fn read<R: io::Read>(r: &mut R) -> Result<Self, DecodeError> { |
| 782 | + Ok(Self::from_be_bytes(Vec::<u8>::read(r)?)) |
| 783 | + } |
701 | 784 | }
|
702 |
| - Ok(()) |
703 | 785 | }
|
704 | 786 | }
|
705 |
| - |
706 |
| -impl<T: sealed::Context> Readable for Features<T> { |
| 787 | +impl_feature_len_prefixed_write!(InitFeatures); |
| 788 | +impl_feature_len_prefixed_write!(ChannelFeatures); |
| 789 | +impl_feature_len_prefixed_write!(NodeFeatures); |
| 790 | +impl_feature_len_prefixed_write!(InvoiceFeatures); |
| 791 | + |
| 792 | +// Because ChannelTypeFeatures only appears inside of TLVs, it doesn't have a length prefix when |
| 793 | +// serialized. Thus, we can't use `impl_feature_len_prefixed_write`, above, and have to write our |
| 794 | +// own serialization. |
| 795 | +impl Writeable for ChannelTypeFeatures { |
| 796 | + fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> { |
| 797 | + self.write_be(w) |
| 798 | + } |
| 799 | +} |
| 800 | +impl Readable for ChannelTypeFeatures { |
707 | 801 | fn read<R: io::Read>(r: &mut R) -> Result<Self, DecodeError> {
|
708 |
| - let mut flags: Vec<u8> = Readable::read(r)?; |
709 |
| - flags.reverse(); // Swap to little-endian |
710 |
| - Ok(Self { |
711 |
| - flags, |
712 |
| - mark: PhantomData, |
713 |
| - }) |
| 802 | + let v = io_extras::read_to_end(r)?; |
| 803 | + Ok(Self::from_be_bytes(v)) |
714 | 804 | }
|
715 | 805 | }
|
716 | 806 |
|
717 | 807 | #[cfg(test)]
|
718 | 808 | mod tests {
|
719 |
| - use super::{ChannelFeatures, InitFeatures, InvoiceFeatures, NodeFeatures}; |
| 809 | + use super::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, InvoiceFeatures, NodeFeatures}; |
720 | 810 | use bitcoin::bech32::{Base32Len, FromBase32, ToBase32, u5};
|
721 | 811 |
|
722 | 812 | #[test]
|
@@ -875,4 +965,15 @@ mod tests {
|
875 | 965 | let features_deserialized = InvoiceFeatures::from_base32(&features_as_u5s).unwrap();
|
876 | 966 | assert_eq!(features, features_deserialized);
|
877 | 967 | }
|
| 968 | + |
| 969 | + #[test] |
| 970 | + fn test_channel_type_mapping() { |
| 971 | + // If we map an InvoiceFeatures with StaticRemoteKey optional, it should map into a |
| 972 | + // required-StaticRemoteKey ChannelTypeFeatures. |
| 973 | + let init_features = InitFeatures::empty().set_static_remote_key_optional(); |
| 974 | + let converted_features = ChannelTypeFeatures::from_counterparty_init(&init_features); |
| 975 | + assert_eq!(converted_features, ChannelTypeFeatures::only_static_remote_key()); |
| 976 | + assert!(!converted_features.supports_any_optional_bits()); |
| 977 | + assert!(converted_features.requires_static_remote_key()); |
| 978 | + } |
878 | 979 | }
|
0 commit comments