Skip to content

Commit 005566a

Browse files
committed
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.
1 parent fd483ae commit 005566a

File tree

3 files changed

+37
-9
lines changed

3 files changed

+37
-9
lines changed

lightning/src/ln/features.rs

+35-7
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ use core::marker::PhantomData;
6565
use bitcoin::bech32;
6666
use bitcoin::bech32::{Base32Len, FromBase32, ToBase32, u5, WriteBase32};
6767
use crate::ln::msgs::DecodeError;
68-
use crate::util::ser::{Readable, Writeable, Writer};
68+
use crate::util::ser::{Readable, WithoutLength, Writeable, Writer};
6969

7070
mod sealed {
7171
use crate::prelude::*;
@@ -725,26 +725,40 @@ macro_rules! impl_feature_tlv_write {
725725
($features: ident) => {
726726
impl Writeable for $features {
727727
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
728-
self.write_be(w)
728+
WithoutLength(self).write(w)
729729
}
730730
}
731731
impl Readable for $features {
732732
fn read<R: io::Read>(r: &mut R) -> Result<Self, DecodeError> {
733-
let v = io_extras::read_to_end(r)?;
734-
Ok(Self::from_be_bytes(v))
733+
Ok(WithoutLength::<Self>::read(r)?.0)
735734
}
736735
}
737736
}
738737
}
739738

740739
impl_feature_tlv_write!(ChannelTypeFeatures);
741-
impl_feature_tlv_write!(OfferFeatures);
742-
impl_feature_tlv_write!(InvoiceRequestFeatures);
740+
741+
// Some features may appear both in a TLV record and as part of a TLV subtype sequence. The latter
742+
// requires a length but the former does not.
743+
744+
impl<T: sealed::Context> Writeable for WithoutLength<&Features<T>> {
745+
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
746+
self.0.write_be(w)
747+
}
748+
}
749+
750+
impl<T: sealed::Context> Readable for WithoutLength<Features<T>> {
751+
fn read<R: io::Read>(r: &mut R) -> Result<Self, DecodeError> {
752+
let v = io_extras::read_to_end(r)?;
753+
Ok(WithoutLength(Features::<T>::from_be_bytes(v)))
754+
}
755+
}
743756

744757
#[cfg(test)]
745758
mod tests {
746-
use super::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, InvoiceFeatures, NodeFeatures, sealed};
759+
use super::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, InvoiceFeatures, NodeFeatures, OfferFeatures, sealed};
747760
use bitcoin::bech32::{Base32Len, FromBase32, ToBase32, u5};
761+
use crate::util::ser::{Readable, WithoutLength, Writeable};
748762

749763
#[test]
750764
fn sanity_test_unknown_bits() {
@@ -838,6 +852,20 @@ mod tests {
838852
assert!(features.supports_payment_secret());
839853
}
840854

855+
#[test]
856+
fn encodes_features_without_length() {
857+
let features = OfferFeatures::from_le_bytes(vec![1, 2, 3, 4, 5, 42, 100, 101]);
858+
assert_eq!(features.flags.len(), 8);
859+
860+
let mut serialized_features = Vec::new();
861+
WithoutLength(&features).write(&mut serialized_features).unwrap();
862+
assert_eq!(serialized_features.len(), 8);
863+
864+
let deserialized_features =
865+
WithoutLength::<OfferFeatures>::read(&mut &serialized_features[..]).unwrap().0;
866+
assert_eq!(features, deserialized_features);
867+
}
868+
841869
#[test]
842870
fn invoice_features_encoding() {
843871
let features_as_u5s = vec![

lightning/src/offers/invoice_request.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,7 @@ impl Writeable for InvoiceRequestContents {
380380
tlv_stream!(InvoiceRequestTlvStream, InvoiceRequestTlvStreamRef, 80..160, {
381381
(80, chain: ChainHash),
382382
(82, amount: (u64, HighZeroBytesDroppedBigSize)),
383-
(84, features: InvoiceRequestFeatures),
383+
(84, features: (InvoiceRequestFeatures, WithoutLength)),
384384
(86, quantity: (u64, HighZeroBytesDroppedBigSize)),
385385
(88, payer_id: PublicKey),
386386
(89, payer_note: (String, WithoutLength)),

lightning/src/offers/offer.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -567,7 +567,7 @@ tlv_stream!(OfferTlvStream, OfferTlvStreamRef, 1..80, {
567567
(6, currency: CurrencyCode),
568568
(8, amount: (u64, HighZeroBytesDroppedBigSize)),
569569
(10, description: (String, WithoutLength)),
570-
(12, features: OfferFeatures),
570+
(12, features: (OfferFeatures, WithoutLength)),
571571
(14, absolute_expiry: (u64, HighZeroBytesDroppedBigSize)),
572572
(16, paths: (Vec<BlindedPath>, WithoutLength)),
573573
(18, issuer: (String, WithoutLength)),

0 commit comments

Comments
 (0)