diff --git a/lightning/src/ln/chan_utils.rs b/lightning/src/ln/chan_utils.rs index 4bb8ffac9ef..b9a3788532a 100644 --- a/lightning/src/ln/chan_utils.rs +++ b/lightning/src/ln/chan_utils.rs @@ -1169,24 +1169,21 @@ impl_writeable_tlv_based!(CounterpartyChannelTransactionParameters, { (2, selected_contest_delay, required), }); -impl Writeable for ChannelTransactionParameters { - #[rustfmt::skip] - fn write(&self, writer: &mut W) -> Result<(), io::Error> { - let legacy_deserialization_prevention_marker = legacy_deserialization_prevention_marker_for_channel_type_features(&self.channel_type_features); - write_tlv_fields!(writer, { - (0, self.holder_pubkeys, required), - (2, self.holder_selected_contest_delay, required), - (4, self.is_outbound_from_holder, required), - (6, self.counterparty_parameters, option), - (8, self.funding_outpoint, option), - (10, legacy_deserialization_prevention_marker, option), - (11, self.channel_type_features, required), - (12, self.splice_parent_funding_txid, option), - (13, self.channel_value_satoshis, required), - }); - Ok(()) - } -} +impl_writeable_only_tlv_fields!(ChannelTransactionParameters, self, { + (0, self.holder_pubkeys, required), + (2, self.holder_selected_contest_delay, required), + (4, self.is_outbound_from_holder, required), + (6, self.counterparty_parameters, option), + (8, self.funding_outpoint, option), + ( + 10, + legacy_deserialization_prevention_marker_for_channel_type_features(&self.channel_type_features), + option + ), + (11, self.channel_type_features, required), + (12, self.splice_parent_funding_txid, option), + (13, self.channel_value_satoshis, required), +}); impl ReadableArgs> for ChannelTransactionParameters { #[rustfmt::skip] @@ -1634,25 +1631,22 @@ impl PartialEq for CommitmentTransaction { } } -impl Writeable for CommitmentTransaction { - #[rustfmt::skip] - fn write(&self, writer: &mut W) -> Result<(), io::Error> { - let legacy_deserialization_prevention_marker = legacy_deserialization_prevention_marker_for_channel_type_features(&self.channel_type_features); - write_tlv_fields!(writer, { - (0, self.commitment_number, required), - (1, self.to_broadcaster_delay, option), - (2, self.to_broadcaster_value_sat, required), - (4, self.to_countersignatory_value_sat, required), - (6, self.feerate_per_kw, required), - (8, self.keys, required), - (10, self.built, required), - (12, self.nondust_htlcs, required_vec), - (14, legacy_deserialization_prevention_marker, option), - (15, self.channel_type_features, required), - }); - Ok(()) - } -} +impl_writeable_only_tlv_fields!(CommitmentTransaction, self, { + (0, self.commitment_number, required), + (1, self.to_broadcaster_delay, option), + (2, self.to_broadcaster_value_sat, required), + (4, self.to_countersignatory_value_sat, required), + (6, self.feerate_per_kw, required), + (8, self.keys, required), + (10, self.built, required), + (12, self.nondust_htlcs, required_vec), + ( + 14, + legacy_deserialization_prevention_marker_for_channel_type_features(&self.channel_type_features), + option + ), + (15, self.channel_type_features, required), +}); impl Readable for CommitmentTransaction { #[rustfmt::skip] diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index d0072da226a..7e0aed8c306 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -2596,22 +2596,17 @@ pub(super) struct FundingScope { minimum_depth_override: Option, } -impl Writeable for FundingScope { - fn write(&self, writer: &mut W) -> Result<(), io::Error> { - write_tlv_fields!(writer, { - (1, self.value_to_self_msat, required), - (3, self.counterparty_selected_channel_reserve_satoshis, option), - (5, self.holder_selected_channel_reserve_satoshis, required), - (7, self.channel_transaction_parameters, (required: ReadableArgs, None)), - (9, self.funding_transaction, option), - (11, self.funding_tx_confirmed_in, option), - (13, self.funding_tx_confirmation_height, required), - (15, self.short_channel_id, option), - (17, self.minimum_depth_override, option), - }); - Ok(()) - } -} +impl_writeable_only_tlv_fields!(FundingScope, self, { + (1, self.value_to_self_msat, required), + (3, self.counterparty_selected_channel_reserve_satoshis, option), + (5, self.holder_selected_channel_reserve_satoshis, required), + (7, self.channel_transaction_parameters, (required: ReadableArgs, None)), + (9, self.funding_transaction, option), + (11, self.funding_tx_confirmed_in, option), + (13, self.funding_tx_confirmation_height, required), + (15, self.short_channel_id, option), + (17, self.minimum_depth_override, option), +}); impl Readable for FundingScope { #[rustfmt::skip] diff --git a/lightning/src/util/ser.rs b/lightning/src/util/ser.rs index 154c5bd8fde..c27b8249083 100644 --- a/lightning/src/util/ser.rs +++ b/lightning/src/util/ser.rs @@ -317,6 +317,11 @@ impl<'a, T: Writeable> Writeable for &'a T { fn write(&self, writer: &mut W) -> Result<(), io::Error> { (*self).write(writer) } + + #[inline] + fn serialized_length(&self) -> usize { + (*self).serialized_length() + } } /// A trait that various LDK types implement allowing them to be read in from a [`Read`]. @@ -846,6 +851,11 @@ impl Writeable for WithoutLength { } Ok(()) } + + #[inline] + fn serialized_length(&self) -> usize { + self.0.as_slice().iter().map(|v| v.serialized_length()).sum() + } } impl LengthReadable for WithoutLength> { @@ -1366,6 +1376,11 @@ impl Writeable for Box { fn write(&self, w: &mut W) -> Result<(), io::Error> { T::write(&**self, w) } + + #[inline] + fn serialized_length(&self) -> usize { + (**self).serialized_length() + } } impl Readable for Box { @@ -1385,6 +1400,17 @@ impl Writeable for Option { } Ok(()) } + + #[inline] + fn serialized_length(&self) -> usize { + match *self { + None => 1, + Some(ref data) => { + let data_len = data.serialized_length(); + BigSize(data_len as u64 + 1).serialized_length() + data_len + }, + } + } } impl Readable for Option { diff --git a/lightning/src/util/ser_macros.rs b/lightning/src/util/ser_macros.rs index 53777d26130..72621e94ab9 100644 --- a/lightning/src/util/ser_macros.rs +++ b/lightning/src/util/ser_macros.rs @@ -839,6 +839,58 @@ macro_rules! write_tlv_fields { } } +#[doc(hidden)] +#[macro_export] +macro_rules! _tlv_fields_serialized_length { + ({$(($type: expr, $field: expr, $fieldty: tt $(, $self: ident)?)),* $(,)*}) => { { + use $crate::util::ser::BigSize; + let len = { + #[allow(unused_mut)] + let mut len = $crate::util::ser::LengthCalculatingWriter(0); + $( + $crate::_get_varint_length_prefixed_tlv_length!(len, $type, &$field, $fieldty $(, $self)?); + )* + len.0 + }; + let mut len_calc = $crate::util::ser::LengthCalculatingWriter(0); + BigSize(len as u64).write(&mut len_calc).expect("No in-memory data may fail to serialize"); + len + len_calc.0 + } } +} + +/// Implements [`Writeable`] for a type serialized as a length-prefixed TLV stream. +/// +/// This is useful for types that share the TLV-writing format used by +/// [`impl_writeable_tlv_based`] but need a custom read implementation. The field list uses the +/// same entries accepted by [`write_tlv_fields`], and the macro derives both `write` and +/// `serialized_length` from that list so the two paths stay aligned. +/// +/// The `$self` argument names the generated `self` binding, allowing field expressions to refer +/// to it explicitly. +/// +/// [`Writeable`]: crate::util::ser::Writeable +/// [`impl_writeable_tlv_based`]: crate::impl_writeable_tlv_based +/// [`write_tlv_fields`]: crate::write_tlv_fields +macro_rules! impl_writeable_only_tlv_fields { + ($st: ty, $self: ident, {$(($type: expr, $field: expr, $fieldty: tt)),* $(,)*}) => { + impl $crate::util::ser::Writeable for $st { + fn write(&$self, writer: &mut W) -> Result<(), $crate::io::Error> { + write_tlv_fields!(writer, { + $(($type, $field, $fieldty)),* + }); + Ok(()) + } + + #[inline] + fn serialized_length(&$self) -> usize { + $crate::_tlv_fields_serialized_length!({ + $(($type, $field, $fieldty)),* + }) + } + } + } +} + /// Reads a prefix added by [`write_ver_prefix`], above. Takes the current version of the /// serialization logic for this object. This is compared against the /// `$min_version_that_can_read_this` added by [`write_ver_prefix`]. @@ -1095,18 +1147,9 @@ macro_rules! impl_writeable_tlv_based { #[inline] fn serialized_length(&self) -> usize { - use $crate::util::ser::BigSize; - let len = { - #[allow(unused_mut)] - let mut len = $crate::util::ser::LengthCalculatingWriter(0); - $( - $crate::_get_varint_length_prefixed_tlv_length!(len, $type, &self.$field, $fieldty, self); - )* - len.0 - }; - let mut len_calc = $crate::util::ser::LengthCalculatingWriter(0); - BigSize(len as u64).write(&mut len_calc).expect("No in-memory data may fail to serialize"); - len + len_calc.0 + $crate::_tlv_fields_serialized_length!({ + $(($type, self.$field, $fieldty, self)),* + }) } }