From ea1a68c6e6098e8d330792204b05c20d705a372c Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Fri, 16 Dec 2022 13:35:50 -0600 Subject: [PATCH] Use explicit WithoutLength for BOLT 12 features Most BOLT 12 features are used as the value of a TLV record and thus don't use an explicit length. One exception is the features inside the blinded payinfo subtype since the TLV record contains a list of them. However, these features are also used in the BOLT 4 encrypted_data_tlv TLV stream as a single record, where the length is implicit. Implement Readable and Writeable for Features wrapped in WithoutLength such that either serialization can be used where required. --- lightning/src/ln/features.rs | 42 ++++++++++++++++++++----- lightning/src/offers/invoice_request.rs | 2 +- lightning/src/offers/offer.rs | 2 +- 3 files changed, 37 insertions(+), 9 deletions(-) diff --git a/lightning/src/ln/features.rs b/lightning/src/ln/features.rs index 1f455471..9d344331 100644 --- a/lightning/src/ln/features.rs +++ b/lightning/src/ln/features.rs @@ -65,7 +65,7 @@ use core::marker::PhantomData; use bitcoin::bech32; use bitcoin::bech32::{Base32Len, FromBase32, ToBase32, u5, WriteBase32}; use crate::ln::msgs::DecodeError; -use crate::util::ser::{Readable, Writeable, Writer}; +use crate::util::ser::{Readable, WithoutLength, Writeable, Writer}; mod sealed { use crate::prelude::*; @@ -725,26 +725,40 @@ macro_rules! impl_feature_tlv_write { ($features: ident) => { impl Writeable for $features { fn write(&self, w: &mut W) -> Result<(), io::Error> { - self.write_be(w) + WithoutLength(self).write(w) } } impl Readable for $features { fn read(r: &mut R) -> Result { - let v = io_extras::read_to_end(r)?; - Ok(Self::from_be_bytes(v)) + Ok(WithoutLength::::read(r)?.0) } } } } impl_feature_tlv_write!(ChannelTypeFeatures); -impl_feature_tlv_write!(OfferFeatures); -impl_feature_tlv_write!(InvoiceRequestFeatures); + +// 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.0.write_be(w) + } +} + +impl Readable for WithoutLength> { + fn read(r: &mut R) -> Result { + let v = io_extras::read_to_end(r)?; + 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() { @@ -838,6 +852,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![ diff --git a/lightning/src/offers/invoice_request.rs b/lightning/src/offers/invoice_request.rs index 690bc8d0..fd5ecda5 100644 --- a/lightning/src/offers/invoice_request.rs +++ b/lightning/src/offers/invoice_request.rs @@ -371,7 +371,7 @@ impl Writeable for InvoiceRequestContents { tlv_stream!(InvoiceRequestTlvStream, InvoiceRequestTlvStreamRef, 80..160, { (80, chain: ChainHash), (82, amount: (u64, HighZeroBytesDroppedBigSize)), - (84, features: InvoiceRequestFeatures), + (84, features: (InvoiceRequestFeatures, WithoutLength)), (86, quantity: (u64, HighZeroBytesDroppedBigSize)), (88, payer_id: PublicKey), (89, payer_note: (String, WithoutLength)), diff --git a/lightning/src/offers/offer.rs b/lightning/src/offers/offer.rs index 6451d943..e6550044 100644 --- a/lightning/src/offers/offer.rs +++ b/lightning/src/offers/offer.rs @@ -567,7 +567,7 @@ tlv_stream!(OfferTlvStream, OfferTlvStreamRef, 1..80, { (6, currency: CurrencyCode), (8, amount: (u64, HighZeroBytesDroppedBigSize)), (10, description: (String, WithoutLength)), - (12, features: OfferFeatures), + (12, features: (OfferFeatures, WithoutLength)), (14, absolute_expiry: (u64, HighZeroBytesDroppedBigSize)), (16, paths: (Vec, WithoutLength)), (18, issuer: (String, WithoutLength)), -- 2.30.2