Merge pull request #2871 from dunxen/2024-02-msgcommonfields
[rust-lightning] / lightning / src / ln / msgs.rs
index d39f1a6084274762331b456d28494b725999d69e..cfa6a1dd80645d2b61405d31721092d5abfd0738 100644 (file)
@@ -172,76 +172,20 @@ pub struct Pong {
        pub byteslen: u16,
 }
 
-/// An [`open_channel`] message to be sent to or received from a peer.
-///
-/// Used in V1 channel establishment
+/// Contains fields that are both common to [`open_channel`] and `open_channel2` messages.
 ///
 /// [`open_channel`]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#the-open_channel-message
-#[derive(Clone, Debug, Hash, PartialEq, Eq)]
-pub struct OpenChannel {
-       /// The genesis hash of the blockchain where the channel is to be opened
-       pub chain_hash: ChainHash,
-       /// A temporary channel ID, until the funding outpoint is announced
-       pub temporary_channel_id: ChannelId,
-       /// The channel value
-       pub funding_satoshis: u64,
-       /// The amount to push to the counterparty as part of the open, in milli-satoshi
-       pub push_msat: u64,
-       /// The threshold below which outputs on transactions broadcast by sender will be omitted
-       pub dust_limit_satoshis: u64,
-       /// The maximum inbound HTLC value in flight towards sender, in milli-satoshi
-       pub max_htlc_value_in_flight_msat: u64,
-       /// The minimum value unencumbered by HTLCs for the counterparty to keep in the channel
-       pub channel_reserve_satoshis: u64,
-       /// The minimum HTLC size incoming to sender, in milli-satoshi
-       pub htlc_minimum_msat: u64,
-       /// The feerate per 1000-weight of sender generated transactions, until updated by
-       /// [`UpdateFee`]
-       pub feerate_per_kw: u32,
-       /// The number of blocks which the counterparty will have to wait to claim on-chain funds if
-       /// they broadcast a commitment transaction
-       pub to_self_delay: u16,
-       /// The maximum number of inbound HTLCs towards sender
-       pub max_accepted_htlcs: u16,
-       /// The sender's key controlling the funding transaction
-       pub funding_pubkey: PublicKey,
-       /// Used to derive a revocation key for transactions broadcast by counterparty
-       pub revocation_basepoint: PublicKey,
-       /// A payment key to sender for transactions broadcast by counterparty
-       pub payment_point: PublicKey,
-       /// Used to derive a payment key to sender for transactions broadcast by sender
-       pub delayed_payment_basepoint: PublicKey,
-       /// Used to derive an HTLC payment key to sender
-       pub htlc_basepoint: PublicKey,
-       /// The first to-be-broadcast-by-sender transaction's per commitment point
-       pub first_per_commitment_point: PublicKey,
-       /// The channel flags to be used
-       pub channel_flags: u8,
-       /// A request to pre-set the to-sender output's `scriptPubkey` for when we collaboratively close
-       pub shutdown_scriptpubkey: Option<ScriptBuf>,
-       /// The channel type that this channel will represent
-       ///
-       /// If this is `None`, we derive the channel type from the intersection of our
-       /// feature bits with our counterparty's feature bits from the [`Init`] message.
-       pub channel_type: Option<ChannelTypeFeatures>,
-}
-
-/// An open_channel2 message to be sent by or received from the channel initiator.
-///
-/// Used in V2 channel establishment
-///
 // TODO(dual_funding): Add spec link for `open_channel2`.
 #[derive(Clone, Debug, Hash, PartialEq, Eq)]
-pub struct OpenChannelV2 {
+pub struct CommonOpenChannelFields {
        /// The genesis hash of the blockchain where the channel is to be opened
        pub chain_hash: ChainHash,
-       /// A temporary channel ID derived using a zeroed out value for the channel acceptor's revocation basepoint
+       /// A temporary channel ID
+       /// For V2 channels: derived using a zeroed out value for the channel acceptor's revocation basepoint
+       /// For V1 channels: a temporary channel ID, until the funding outpoint is announced
        pub temporary_channel_id: ChannelId,
-       /// The feerate for the funding transaction set by the channel initiator
-       pub funding_feerate_sat_per_1000_weight: u32,
-       /// The feerate for the commitment transaction set by the channel initiator
-       pub commitment_feerate_sat_per_1000_weight: u32,
-       /// Part of the channel value contributed by the channel initiator
+       /// For V1 channels: The channel value
+       /// For V2 channels: Part of the channel value contributed by the channel initiator
        pub funding_satoshis: u64,
        /// The threshold below which outputs on transactions broadcast by the channel initiator will be
        /// omitted
@@ -250,13 +194,14 @@ pub struct OpenChannelV2 {
        pub max_htlc_value_in_flight_msat: u64,
        /// The minimum HTLC size incoming to channel initiator, in milli-satoshi
        pub htlc_minimum_msat: u64,
+       /// The feerate for the commitment transaction set by the channel initiator until updated by
+       /// [`UpdateFee`]
+       pub commitment_feerate_sat_per_1000_weight: u32,
        /// The number of blocks which the counterparty will have to wait to claim on-chain funds if they
        /// broadcast a commitment transaction
        pub to_self_delay: u16,
        /// The maximum number of inbound HTLCs towards channel initiator
        pub max_accepted_htlcs: u16,
-       /// The locktime for the funding transaction
-       pub locktime: u32,
        /// The channel initiator's key controlling the funding transaction
        pub funding_pubkey: PublicKey,
        /// Used to derive a revocation key for transactions broadcast by counterparty
@@ -270,84 +215,64 @@ pub struct OpenChannelV2 {
        pub htlc_basepoint: PublicKey,
        /// The first to-be-broadcast-by-channel-initiator transaction's per commitment point
        pub first_per_commitment_point: PublicKey,
-       /// The second to-be-broadcast-by-channel-initiator transaction's per commitment point
-       pub second_per_commitment_point: PublicKey,
-       /// Channel flags
+       /// The channel flags to be used
        pub channel_flags: u8,
        /// Optionally, a request to pre-set the to-channel-initiator output's scriptPubkey for when we
        /// collaboratively close
        pub shutdown_scriptpubkey: Option<ScriptBuf>,
-       /// The channel type that this channel will represent. If none is set, we derive the channel
-       /// type from the intersection of our feature bits with our counterparty's feature bits from
-       /// the Init message.
+       /// The channel type that this channel will represent
+       ///
+       /// If this is `None`, we derive the channel type from the intersection of our
+       /// feature bits with our counterparty's feature bits from the [`Init`] message.
        pub channel_type: Option<ChannelTypeFeatures>,
-       /// Optionally, a requirement that only confirmed inputs can be added
-       pub require_confirmed_inputs: Option<()>,
 }
 
-/// An [`accept_channel`] message to be sent to or received from a peer.
+/// An [`open_channel`] message to be sent to or received from a peer.
 ///
 /// Used in V1 channel establishment
 ///
-/// [`accept_channel`]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#the-accept_channel-message
+/// [`open_channel`]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#the-open_channel-message
 #[derive(Clone, Debug, Hash, PartialEq, Eq)]
-pub struct AcceptChannel {
-       /// A temporary channel ID, until the funding outpoint is announced
-       pub temporary_channel_id: ChannelId,
-       /// The threshold below which outputs on transactions broadcast by sender will be omitted
-       pub dust_limit_satoshis: u64,
-       /// The maximum inbound HTLC value in flight towards sender, in milli-satoshi
-       pub max_htlc_value_in_flight_msat: u64,
+pub struct OpenChannel {
+       /// Common fields of `open_channel(2)`-like messages
+       pub common_fields: CommonOpenChannelFields,
+       /// The amount to push to the counterparty as part of the open, in milli-satoshi
+       pub push_msat: u64,
        /// The minimum value unencumbered by HTLCs for the counterparty to keep in the channel
        pub channel_reserve_satoshis: u64,
-       /// The minimum HTLC size incoming to sender, in milli-satoshi
-       pub htlc_minimum_msat: u64,
-       /// Minimum depth of the funding transaction before the channel is considered open
-       pub minimum_depth: u32,
-       /// The number of blocks which the counterparty will have to wait to claim on-chain funds if they broadcast a commitment transaction
-       pub to_self_delay: u16,
-       /// The maximum number of inbound HTLCs towards sender
-       pub max_accepted_htlcs: u16,
-       /// The sender's key controlling the funding transaction
-       pub funding_pubkey: PublicKey,
-       /// Used to derive a revocation key for transactions broadcast by counterparty
-       pub revocation_basepoint: PublicKey,
-       /// A payment key to sender for transactions broadcast by counterparty
-       pub payment_point: PublicKey,
-       /// Used to derive a payment key to sender for transactions broadcast by sender
-       pub delayed_payment_basepoint: PublicKey,
-       /// Used to derive an HTLC payment key to sender for transactions broadcast by counterparty
-       pub htlc_basepoint: PublicKey,
-       /// The first to-be-broadcast-by-sender transaction's per commitment point
-       pub first_per_commitment_point: PublicKey,
-       /// A request to pre-set the to-sender output's scriptPubkey for when we collaboratively close
-       pub shutdown_scriptpubkey: Option<ScriptBuf>,
-       /// The channel type that this channel will represent.
-       ///
-       /// If this is `None`, we derive the channel type from the intersection of
-       /// our feature bits with our counterparty's feature bits from the [`Init`] message.
-       /// This is required to match the equivalent field in [`OpenChannel::channel_type`].
-       pub channel_type: Option<ChannelTypeFeatures>,
-       #[cfg(taproot)]
-       /// Next nonce the channel initiator should use to create a funding output signature against
-       pub next_local_nonce: Option<musig2::types::PublicNonce>,
 }
 
-/// An accept_channel2 message to be sent by or received from the channel accepter.
+/// An open_channel2 message to be sent by or received from the channel initiator.
 ///
 /// Used in V2 channel establishment
 ///
+// TODO(dual_funding): Add spec link for `open_channel2`.
+#[derive(Clone, Debug, Hash, PartialEq, Eq)]
+pub struct OpenChannelV2 {
+       /// Common fields of `open_channel(2)`-like messages
+       pub common_fields: CommonOpenChannelFields,
+       /// The feerate for the funding transaction set by the channel initiator
+       pub funding_feerate_sat_per_1000_weight: u32,
+       /// The locktime for the funding transaction
+       pub locktime: u32,
+       /// The second to-be-broadcast-by-channel-initiator transaction's per commitment point
+       pub second_per_commitment_point: PublicKey,
+       /// Optionally, a requirement that only confirmed inputs can be added
+       pub require_confirmed_inputs: Option<()>,
+}
+
+/// Contains fields that are both common to [`accept_channel`] and `accept_channel2` messages.
+///
+/// [`accept_channel`]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#the-accept_channel-message
 // TODO(dual_funding): Add spec link for `accept_channel2`.
 #[derive(Clone, Debug, Hash, PartialEq, Eq)]
-pub struct AcceptChannelV2 {
-       /// The same `temporary_channel_id` received from the initiator's `open_channel2` message.
+pub struct CommonAcceptChannelFields {
+       /// The same `temporary_channel_id` received from the initiator's `open_channel2` or `open_channel` message.
        pub temporary_channel_id: ChannelId,
-       /// Part of the channel value contributed by the channel acceptor
-       pub funding_satoshis: u64,
        /// The threshold below which outputs on transactions broadcast by the channel acceptor will be
        /// omitted
        pub dust_limit_satoshis: u64,
-       /// The maximum inbound HTLC value in flight towards channel acceptor, in milli-satoshi
+       /// The maximum inbound HTLC value in flight towards sender, in milli-satoshi
        pub max_htlc_value_in_flight_msat: u64,
        /// The minimum HTLC size incoming to channel acceptor, in milli-satoshi
        pub htlc_minimum_msat: u64,
@@ -371,8 +296,6 @@ pub struct AcceptChannelV2 {
        pub htlc_basepoint: PublicKey,
        /// The first to-be-broadcast-by-channel-acceptor transaction's per commitment point
        pub first_per_commitment_point: PublicKey,
-       /// The second to-be-broadcast-by-channel-acceptor transaction's per commitment point
-       pub second_per_commitment_point: PublicKey,
        /// Optionally, a request to pre-set the to-channel-acceptor output's scriptPubkey for when we
        /// collaboratively close
        pub shutdown_scriptpubkey: Option<ScriptBuf>,
@@ -380,8 +303,40 @@ pub struct AcceptChannelV2 {
        /// type from the intersection of our feature bits with our counterparty's feature bits from
        /// the Init message.
        ///
-       /// This is required to match the equivalent field in [`OpenChannelV2::channel_type`].
+       /// This is required to match the equivalent field in [`OpenChannel`] or [`OpenChannelV2`]'s
+       /// [`CommonOpenChannelFields::channel_type`].
        pub channel_type: Option<ChannelTypeFeatures>,
+}
+
+/// An [`accept_channel`] message to be sent to or received from a peer.
+///
+/// Used in V1 channel establishment
+///
+/// [`accept_channel`]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#the-accept_channel-message
+#[derive(Clone, Debug, Hash, PartialEq, Eq)]
+pub struct AcceptChannel {
+       /// Common fields of `accept_channel(2)`-like messages
+       pub common_fields: CommonAcceptChannelFields,
+       /// The minimum value unencumbered by HTLCs for the counterparty to keep in the channel
+       pub channel_reserve_satoshis: u64,
+       #[cfg(taproot)]
+       /// Next nonce the channel initiator should use to create a funding output signature against
+       pub next_local_nonce: Option<musig2::types::PublicNonce>,
+}
+
+/// An accept_channel2 message to be sent by or received from the channel accepter.
+///
+/// Used in V2 channel establishment
+///
+// TODO(dual_funding): Add spec link for `accept_channel2`.
+#[derive(Clone, Debug, Hash, PartialEq, Eq)]
+pub struct AcceptChannelV2 {
+       /// Common fields of `accept_channel(2)`-like messages
+       pub common_fields: CommonAcceptChannelFields,
+       /// Part of the channel value contributed by the channel acceptor
+       pub funding_satoshis: u64,
+       /// The second to-be-broadcast-by-channel-acceptor transaction's per commitment point
+       pub second_per_commitment_point: PublicKey,
        /// Optionally, a requirement that only confirmed inputs can be added
        pub require_confirmed_inputs: Option<()>,
 }
@@ -1831,70 +1786,173 @@ impl From<io::Error> for DecodeError {
        }
 }
 
-#[cfg(not(taproot))]
-impl_writeable_msg!(AcceptChannel, {
-       temporary_channel_id,
-       dust_limit_satoshis,
-       max_htlc_value_in_flight_msat,
-       channel_reserve_satoshis,
-       htlc_minimum_msat,
-       minimum_depth,
-       to_self_delay,
-       max_accepted_htlcs,
-       funding_pubkey,
-       revocation_basepoint,
-       payment_point,
-       delayed_payment_basepoint,
-       htlc_basepoint,
-       first_per_commitment_point,
-}, {
-       (0, shutdown_scriptpubkey, (option, encoding: (ScriptBuf, WithoutLength))), // Don't encode length twice.
-       (1, channel_type, option),
-});
+impl Writeable for AcceptChannel {
+    fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
+       self.common_fields.temporary_channel_id.write(w)?;
+       self.common_fields.dust_limit_satoshis.write(w)?;
+       self.common_fields.max_htlc_value_in_flight_msat.write(w)?;
+       self.channel_reserve_satoshis.write(w)?;
+       self.common_fields.htlc_minimum_msat.write(w)?;
+       self.common_fields.minimum_depth.write(w)?;
+       self.common_fields.to_self_delay.write(w)?;
+       self.common_fields.max_accepted_htlcs.write(w)?;
+       self.common_fields.funding_pubkey.write(w)?;
+       self.common_fields.revocation_basepoint.write(w)?;
+       self.common_fields.payment_basepoint.write(w)?;
+       self.common_fields.delayed_payment_basepoint.write(w)?;
+       self.common_fields.htlc_basepoint.write(w)?;
+       self.common_fields.first_per_commitment_point.write(w)?;
+       #[cfg(not(taproot))]
+        encode_tlv_stream!(w, {
+                       (0, self.common_fields.shutdown_scriptpubkey.as_ref().map(|s| WithoutLength(s)), option), // Don't encode length twice.
+                       (1, self.common_fields.channel_type, option),
+        });
+        #[cfg(taproot)]
+               encode_tlv_stream!(w, {
+                       (0, self.common_fields.shutdown_scriptpubkey.as_ref().map(|s| WithoutLength(s)), option), // Don't encode length twice.
+                       (1, self.common_fields.channel_type, option),
+                       (4, self.next_local_nonce, option),
+        });
+        Ok(())
+    }
+}
 
-#[cfg(taproot)]
-impl_writeable_msg!(AcceptChannel, {
-       temporary_channel_id,
-       dust_limit_satoshis,
-       max_htlc_value_in_flight_msat,
-       channel_reserve_satoshis,
-       htlc_minimum_msat,
-       minimum_depth,
-       to_self_delay,
-       max_accepted_htlcs,
-       funding_pubkey,
-       revocation_basepoint,
-       payment_point,
-       delayed_payment_basepoint,
-       htlc_basepoint,
-       first_per_commitment_point,
-}, {
-       (0, shutdown_scriptpubkey, (option, encoding: (ScriptBuf, WithoutLength))), // Don't encode length twice.
-       (1, channel_type, option),
-       (4, next_local_nonce, option),
-});
+impl Readable for AcceptChannel {
+       fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
+               let temporary_channel_id: ChannelId = Readable::read(r)?;
+               let dust_limit_satoshis: u64 = Readable::read(r)?;
+       let max_htlc_value_in_flight_msat: u64 = Readable::read(r)?;
+       let channel_reserve_satoshis: u64 = Readable::read(r)?;
+       let htlc_minimum_msat: u64 = Readable::read(r)?;
+       let minimum_depth: u32 = Readable::read(r)?;
+       let to_self_delay: u16 = Readable::read(r)?;
+       let max_accepted_htlcs: u16 = Readable::read(r)?;
+       let funding_pubkey: PublicKey = Readable::read(r)?;
+       let revocation_basepoint: PublicKey = Readable::read(r)?;
+       let payment_basepoint: PublicKey = Readable::read(r)?;
+       let delayed_payment_basepoint: PublicKey = Readable::read(r)?;
+       let htlc_basepoint: PublicKey = Readable::read(r)?;
+       let first_per_commitment_point: PublicKey = Readable::read(r)?;
+
+               let mut shutdown_scriptpubkey: Option<ScriptBuf> = None;
+               let mut channel_type: Option<ChannelTypeFeatures> = None;
+       #[cfg(not(taproot))]
+               decode_tlv_stream!(r, {
+                       (0, shutdown_scriptpubkey, (option, encoding: (ScriptBuf, WithoutLength))),
+                       (1, channel_type, option),
+               });
+        #[cfg(taproot)]
+        let mut next_local_nonce: Option<musig2::types::PublicNonce> = None;
+        #[cfg(taproot)]
+               decode_tlv_stream!(r, {
+                       (0, shutdown_scriptpubkey, (option, encoding: (ScriptBuf, WithoutLength))),
+                       (1, channel_type, option),
+                       (4, next_local_nonce, option),
+               });
 
-impl_writeable_msg!(AcceptChannelV2, {
-       temporary_channel_id,
-       funding_satoshis,
-       dust_limit_satoshis,
-       max_htlc_value_in_flight_msat,
-       htlc_minimum_msat,
-       minimum_depth,
-       to_self_delay,
-       max_accepted_htlcs,
-       funding_pubkey,
-       revocation_basepoint,
-       payment_basepoint,
-       delayed_payment_basepoint,
-       htlc_basepoint,
-       first_per_commitment_point,
-       second_per_commitment_point,
-}, {
-       (0, shutdown_scriptpubkey, option),
-       (1, channel_type, option),
-       (2, require_confirmed_inputs, option),
-});
+               Ok(AcceptChannel {
+                       common_fields: CommonAcceptChannelFields {
+                           temporary_channel_id,
+                           dust_limit_satoshis,
+                           max_htlc_value_in_flight_msat,
+                           htlc_minimum_msat,
+                           minimum_depth,
+                           to_self_delay,
+                           max_accepted_htlcs,
+                           funding_pubkey,
+                           revocation_basepoint,
+                           payment_basepoint,
+                           delayed_payment_basepoint,
+                           htlc_basepoint,
+                           first_per_commitment_point,
+                           shutdown_scriptpubkey,
+                           channel_type,
+                       },
+                   channel_reserve_satoshis,
+               #[cfg(taproot)]
+                       next_local_nonce,
+               })
+       }
+}
+
+impl Writeable for AcceptChannelV2 {
+    fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
+       self.common_fields.temporary_channel_id.write(w)?;
+       self.funding_satoshis.write(w)?;
+       self.common_fields.dust_limit_satoshis.write(w)?;
+       self.common_fields.max_htlc_value_in_flight_msat.write(w)?;
+       self.common_fields.htlc_minimum_msat.write(w)?;
+       self.common_fields.minimum_depth.write(w)?;
+       self.common_fields.to_self_delay.write(w)?;
+       self.common_fields.max_accepted_htlcs.write(w)?;
+       self.common_fields.funding_pubkey.write(w)?;
+       self.common_fields.revocation_basepoint.write(w)?;
+       self.common_fields.payment_basepoint.write(w)?;
+       self.common_fields.delayed_payment_basepoint.write(w)?;
+       self.common_fields.htlc_basepoint.write(w)?;
+       self.common_fields.first_per_commitment_point.write(w)?;
+       self.second_per_commitment_point.write(w)?;
+
+        encode_tlv_stream!(w, {
+                       (0, self.common_fields.shutdown_scriptpubkey.as_ref().map(|s| WithoutLength(s)), option), // Don't encode length twice.
+                       (1, self.common_fields.channel_type, option),
+                       (2, self.require_confirmed_inputs, option),
+        });
+        Ok(())
+    }
+}
+
+impl Readable for AcceptChannelV2 {
+       fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
+               let temporary_channel_id: ChannelId = Readable::read(r)?;
+               let funding_satoshis: u64 = Readable::read(r)?;
+               let dust_limit_satoshis: u64 = Readable::read(r)?;
+       let max_htlc_value_in_flight_msat: u64 = Readable::read(r)?;
+       let htlc_minimum_msat: u64 = Readable::read(r)?;
+       let minimum_depth: u32 = Readable::read(r)?;
+       let to_self_delay: u16 = Readable::read(r)?;
+       let max_accepted_htlcs: u16 = Readable::read(r)?;
+       let funding_pubkey: PublicKey = Readable::read(r)?;
+       let revocation_basepoint: PublicKey = Readable::read(r)?;
+       let payment_basepoint: PublicKey = Readable::read(r)?;
+       let delayed_payment_basepoint: PublicKey = Readable::read(r)?;
+       let htlc_basepoint: PublicKey = Readable::read(r)?;
+       let first_per_commitment_point: PublicKey = Readable::read(r)?;
+               let second_per_commitment_point: PublicKey = Readable::read(r)?;
+
+               let mut shutdown_scriptpubkey: Option<ScriptBuf> = None;
+               let mut channel_type: Option<ChannelTypeFeatures> = None;
+               let mut require_confirmed_inputs: Option<()> = None;
+               decode_tlv_stream!(r, {
+                       (0, shutdown_scriptpubkey, (option, encoding: (ScriptBuf, WithoutLength))),
+                       (1, channel_type, option),
+                       (2, require_confirmed_inputs, option),
+               });
+
+               Ok(AcceptChannelV2 {
+                       common_fields: CommonAcceptChannelFields {
+                           temporary_channel_id,
+                           dust_limit_satoshis,
+                           max_htlc_value_in_flight_msat,
+                           htlc_minimum_msat,
+                           minimum_depth,
+                           to_self_delay,
+                           max_accepted_htlcs,
+                           funding_pubkey,
+                           revocation_basepoint,
+                           payment_basepoint,
+                           delayed_payment_basepoint,
+                           htlc_basepoint,
+                           first_per_commitment_point,
+                           shutdown_scriptpubkey,
+                           channel_type,
+                       },
+                   funding_satoshis,
+                   second_per_commitment_point,
+                   require_confirmed_inputs,
+               })
+       }
+}
 
 impl_writeable_msg!(Stfu, {
        channel_id,
@@ -2095,55 +2153,176 @@ impl Readable for Init {
        }
 }
 
-impl_writeable_msg!(OpenChannel, {
-       chain_hash,
-       temporary_channel_id,
-       funding_satoshis,
-       push_msat,
-       dust_limit_satoshis,
-       max_htlc_value_in_flight_msat,
-       channel_reserve_satoshis,
-       htlc_minimum_msat,
-       feerate_per_kw,
-       to_self_delay,
-       max_accepted_htlcs,
-       funding_pubkey,
-       revocation_basepoint,
-       payment_point,
-       delayed_payment_basepoint,
-       htlc_basepoint,
-       first_per_commitment_point,
-       channel_flags,
-}, {
-       (0, shutdown_scriptpubkey, (option, encoding: (ScriptBuf, WithoutLength))), // Don't encode length twice.
-       (1, channel_type, option),
-});
+impl Writeable for OpenChannel {
+    fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
+       self.common_fields.chain_hash.write(w)?;
+       self.common_fields.temporary_channel_id.write(w)?;
+       self.common_fields.funding_satoshis.write(w)?;
+               self.push_msat.write(w)?;
+               self.common_fields.dust_limit_satoshis.write(w)?;
+               self.common_fields.max_htlc_value_in_flight_msat.write(w)?;
+               self.channel_reserve_satoshis.write(w)?;
+               self.common_fields.htlc_minimum_msat.write(w)?;
+               self.common_fields.commitment_feerate_sat_per_1000_weight.write(w)?;
+               self.common_fields.to_self_delay.write(w)?;
+               self.common_fields.max_accepted_htlcs.write(w)?;
+               self.common_fields.funding_pubkey.write(w)?;
+               self.common_fields.revocation_basepoint.write(w)?;
+               self.common_fields.payment_basepoint.write(w)?;
+               self.common_fields.delayed_payment_basepoint.write(w)?;
+               self.common_fields.htlc_basepoint.write(w)?;
+               self.common_fields.first_per_commitment_point.write(w)?;
+               self.common_fields.channel_flags.write(w)?;
+        encode_tlv_stream!(w, {
+                       (0, self.common_fields.shutdown_scriptpubkey.as_ref().map(|s| WithoutLength(s)), option), // Don't encode length twice.
+                       (1, self.common_fields.channel_type, option),
+        });
+        Ok(())
+    }
+}
 
-impl_writeable_msg!(OpenChannelV2, {
-       chain_hash,
-       temporary_channel_id,
-       funding_feerate_sat_per_1000_weight,
-       commitment_feerate_sat_per_1000_weight,
-       funding_satoshis,
-       dust_limit_satoshis,
-       max_htlc_value_in_flight_msat,
-       htlc_minimum_msat,
-       to_self_delay,
-       max_accepted_htlcs,
-       locktime,
-       funding_pubkey,
-       revocation_basepoint,
-       payment_basepoint,
-       delayed_payment_basepoint,
-       htlc_basepoint,
-       first_per_commitment_point,
-       second_per_commitment_point,
-       channel_flags,
-}, {
-       (0, shutdown_scriptpubkey, option),
-       (1, channel_type, option),
-       (2, require_confirmed_inputs, option),
-});
+impl Readable for OpenChannel {
+       fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
+               let chain_hash: ChainHash = Readable::read(r)?;
+               let temporary_channel_id: ChannelId = Readable::read(r)?;
+               let funding_satoshis: u64 = Readable::read(r)?;
+               let push_msat: u64 = Readable::read(r)?;
+               let dust_limit_satoshis: u64 = Readable::read(r)?;
+               let max_htlc_value_in_flight_msat: u64 = Readable::read(r)?;
+               let channel_reserve_satoshis: u64 = Readable::read(r)?;
+               let htlc_minimum_msat: u64 = Readable::read(r)?;
+               let commitment_feerate_sat_per_1000_weight: u32 = Readable::read(r)?;
+               let to_self_delay: u16 = Readable::read(r)?;
+               let max_accepted_htlcs: u16 = Readable::read(r)?;
+               let funding_pubkey: PublicKey = Readable::read(r)?;
+               let revocation_basepoint: PublicKey = Readable::read(r)?;
+               let payment_basepoint: PublicKey = Readable::read(r)?;
+               let delayed_payment_basepoint: PublicKey = Readable::read(r)?;
+               let htlc_basepoint: PublicKey = Readable::read(r)?;
+               let first_per_commitment_point: PublicKey = Readable::read(r)?;
+               let channel_flags: u8 = Readable::read(r)?;
+
+               let mut shutdown_scriptpubkey: Option<ScriptBuf> = None;
+               let mut channel_type: Option<ChannelTypeFeatures> = None;
+               decode_tlv_stream!(r, {
+                       (0, shutdown_scriptpubkey, (option, encoding: (ScriptBuf, WithoutLength))),
+                       (1, channel_type, option),
+               });
+               Ok(OpenChannel {
+                       common_fields: CommonOpenChannelFields {
+                           chain_hash,
+                           temporary_channel_id,
+                           funding_satoshis,
+                           dust_limit_satoshis,
+                           max_htlc_value_in_flight_msat,
+                           htlc_minimum_msat,
+                           commitment_feerate_sat_per_1000_weight,
+                           to_self_delay,
+                           max_accepted_htlcs,
+                           funding_pubkey,
+                           revocation_basepoint,
+                           payment_basepoint,
+                           delayed_payment_basepoint,
+                           htlc_basepoint,
+                           first_per_commitment_point,
+                           channel_flags,
+                           shutdown_scriptpubkey,
+                           channel_type,
+                       },
+                   push_msat,
+                   channel_reserve_satoshis,
+               })
+       }
+}
+
+impl Writeable for OpenChannelV2 {
+    fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
+               self.common_fields.chain_hash.write(w)?;
+               self.common_fields.temporary_channel_id.write(w)?;
+               self.funding_feerate_sat_per_1000_weight.write(w)?;
+               self.common_fields.commitment_feerate_sat_per_1000_weight.write(w)?;
+               self.common_fields.funding_satoshis.write(w)?;
+               self.common_fields.dust_limit_satoshis.write(w)?;
+               self.common_fields.max_htlc_value_in_flight_msat.write(w)?;
+               self.common_fields.htlc_minimum_msat.write(w)?;
+               self.common_fields.to_self_delay.write(w)?;
+               self.common_fields.max_accepted_htlcs.write(w)?;
+               self.locktime.write(w)?;
+               self.common_fields.funding_pubkey.write(w)?;
+               self.common_fields.revocation_basepoint.write(w)?;
+               self.common_fields.payment_basepoint.write(w)?;
+               self.common_fields.delayed_payment_basepoint.write(w)?;
+               self.common_fields.htlc_basepoint.write(w)?;
+               self.common_fields.first_per_commitment_point.write(w)?;
+               self.second_per_commitment_point.write(w)?;
+               self.common_fields.channel_flags.write(w)?;
+        encode_tlv_stream!(w, {
+                       (0, self.common_fields.shutdown_scriptpubkey.as_ref().map(|s| WithoutLength(s)), option), // Don't encode length twice.
+                       (1, self.common_fields.channel_type, option),
+                       (2, self.require_confirmed_inputs, option),
+        });
+               Ok(())
+    }
+}
+
+impl Readable for OpenChannelV2 {
+       fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
+               let chain_hash: ChainHash = Readable::read(r)?;
+               let temporary_channel_id: ChannelId = Readable::read(r)?;
+               let funding_feerate_sat_per_1000_weight: u32 = Readable::read(r)?;
+               let commitment_feerate_sat_per_1000_weight: u32 = Readable::read(r)?;
+               let funding_satoshis: u64 = Readable::read(r)?;
+               let dust_limit_satoshis: u64 = Readable::read(r)?;
+               let max_htlc_value_in_flight_msat: u64 = Readable::read(r)?;
+               let htlc_minimum_msat: u64 = Readable::read(r)?;
+               let to_self_delay: u16 = Readable::read(r)?;
+               let max_accepted_htlcs: u16 = Readable::read(r)?;
+               let locktime: u32 = Readable::read(r)?;
+               let funding_pubkey: PublicKey = Readable::read(r)?;
+               let revocation_basepoint: PublicKey = Readable::read(r)?;
+               let payment_basepoint: PublicKey = Readable::read(r)?;
+               let delayed_payment_basepoint: PublicKey = Readable::read(r)?;
+               let htlc_basepoint: PublicKey = Readable::read(r)?;
+               let first_per_commitment_point: PublicKey = Readable::read(r)?;
+               let second_per_commitment_point: PublicKey = Readable::read(r)?;
+               let channel_flags: u8 = Readable::read(r)?;
+
+               let mut shutdown_scriptpubkey: Option<ScriptBuf> = None;
+               let mut channel_type: Option<ChannelTypeFeatures> = None;
+               let mut require_confirmed_inputs: Option<()> = None;
+               decode_tlv_stream!(r, {
+                       (0, shutdown_scriptpubkey, (option, encoding: (ScriptBuf, WithoutLength))),
+                       (1, channel_type, option),
+                       (2, require_confirmed_inputs, option),
+               });
+               Ok(OpenChannelV2 {
+                       common_fields: CommonOpenChannelFields {
+                           chain_hash,
+                           temporary_channel_id,
+                           funding_satoshis,
+                           dust_limit_satoshis,
+                           max_htlc_value_in_flight_msat,
+                           htlc_minimum_msat,
+                           commitment_feerate_sat_per_1000_weight,
+                           to_self_delay,
+                           max_accepted_htlcs,
+                           funding_pubkey,
+                           revocation_basepoint,
+                           payment_basepoint,
+                           delayed_payment_basepoint,
+                           htlc_basepoint,
+                           first_per_commitment_point,
+                           channel_flags,
+                           shutdown_scriptpubkey,
+                           channel_type,
+                       },
+                   funding_feerate_sat_per_1000_weight,
+                   locktime,
+                   second_per_commitment_point,
+                   require_confirmed_inputs,
+               })
+       }
+}
 
 #[cfg(not(taproot))]
 impl_writeable_msg!(RevokeAndACK, {
@@ -2854,7 +3033,7 @@ mod tests {
        use crate::ln::{PaymentPreimage, PaymentHash, PaymentSecret};
        use crate::ln::ChannelId;
        use crate::ln::features::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, NodeFeatures};
-       use crate::ln::msgs::{self, FinalOnionHopData, OnionErrorPacket};
+       use crate::ln::msgs::{self, FinalOnionHopData, OnionErrorPacket, CommonOpenChannelFields, CommonAcceptChannelFields};
        use crate::ln::msgs::SocketAddress;
        use crate::routing::gossip::{NodeAlias, NodeId};
        use crate::util::ser::{Writeable, Readable, ReadableArgs, Hostname, TransactionU16LenLimited};
@@ -3206,26 +3385,28 @@ mod tests {
                let (_, pubkey_5) = get_keys_from!("0505050505050505050505050505050505050505050505050505050505050505", secp_ctx);
                let (_, pubkey_6) = get_keys_from!("0606060606060606060606060606060606060606060606060606060606060606", secp_ctx);
                let open_channel = msgs::OpenChannel {
-                       chain_hash: ChainHash::using_genesis_block(Network::Bitcoin),
-                       temporary_channel_id: ChannelId::from_bytes([2; 32]),
-                       funding_satoshis: 1311768467284833366,
+                       common_fields: CommonOpenChannelFields {
+                               chain_hash: ChainHash::using_genesis_block(Network::Bitcoin),
+                               temporary_channel_id: ChannelId::from_bytes([2; 32]),
+                               funding_satoshis: 1311768467284833366,
+                               dust_limit_satoshis: 3608586615801332854,
+                               max_htlc_value_in_flight_msat: 8517154655701053848,
+                               htlc_minimum_msat: 2316138423780173,
+                               commitment_feerate_sat_per_1000_weight: 821716,
+                               to_self_delay: 49340,
+                               max_accepted_htlcs: 49340,
+                               funding_pubkey: pubkey_1,
+                               revocation_basepoint: pubkey_2,
+                               payment_basepoint: pubkey_3,
+                               delayed_payment_basepoint: pubkey_4,
+                               htlc_basepoint: pubkey_5,
+                               first_per_commitment_point: pubkey_6,
+                               channel_flags: if random_bit { 1 << 5 } else { 0 },
+                               shutdown_scriptpubkey: if shutdown { Some(Address::p2pkh(&::bitcoin::PublicKey{compressed: true, inner: pubkey_1}, Network::Testnet).script_pubkey()) } else { None },
+                               channel_type: if incl_chan_type { Some(ChannelTypeFeatures::empty()) } else { None },
+                       },
                        push_msat: 2536655962884945560,
-                       dust_limit_satoshis: 3608586615801332854,
-                       max_htlc_value_in_flight_msat: 8517154655701053848,
                        channel_reserve_satoshis: 8665828695742877976,
-                       htlc_minimum_msat: 2316138423780173,
-                       feerate_per_kw: 821716,
-                       to_self_delay: 49340,
-                       max_accepted_htlcs: 49340,
-                       funding_pubkey: pubkey_1,
-                       revocation_basepoint: pubkey_2,
-                       payment_point: pubkey_3,
-                       delayed_payment_basepoint: pubkey_4,
-                       htlc_basepoint: pubkey_5,
-                       first_per_commitment_point: pubkey_6,
-                       channel_flags: if random_bit { 1 << 5 } else { 0 },
-                       shutdown_scriptpubkey: if shutdown { Some(Address::p2pkh(&::bitcoin::PublicKey{compressed: true, inner: pubkey_1}, Network::Testnet).script_pubkey()) } else { None },
-                       channel_type: if incl_chan_type { Some(ChannelTypeFeatures::empty()) } else { None },
                };
                let encoded_value = open_channel.encode();
                let mut target_value = Vec::new();
@@ -3267,27 +3448,29 @@ mod tests {
                let (_, pubkey_6) = get_keys_from!("0606060606060606060606060606060606060606060606060606060606060606", secp_ctx);
                let (_, pubkey_7) = get_keys_from!("0707070707070707070707070707070707070707070707070707070707070707", secp_ctx);
                let open_channelv2 = msgs::OpenChannelV2 {
-                       chain_hash: ChainHash::using_genesis_block(Network::Bitcoin),
-                       temporary_channel_id: ChannelId::from_bytes([2; 32]),
+                       common_fields: CommonOpenChannelFields {
+                               chain_hash: ChainHash::using_genesis_block(Network::Bitcoin),
+                               temporary_channel_id: ChannelId::from_bytes([2; 32]),
+                               commitment_feerate_sat_per_1000_weight: 821716,
+                               funding_satoshis: 1311768467284833366,
+                               dust_limit_satoshis: 3608586615801332854,
+                               max_htlc_value_in_flight_msat: 8517154655701053848,
+                               htlc_minimum_msat: 2316138423780173,
+                               to_self_delay: 49340,
+                               max_accepted_htlcs: 49340,
+                               funding_pubkey: pubkey_1,
+                               revocation_basepoint: pubkey_2,
+                               payment_basepoint: pubkey_3,
+                               delayed_payment_basepoint: pubkey_4,
+                               htlc_basepoint: pubkey_5,
+                               first_per_commitment_point: pubkey_6,
+                               channel_flags: if random_bit { 1 << 5 } else { 0 },
+                               shutdown_scriptpubkey: if shutdown { Some(Address::p2pkh(&::bitcoin::PublicKey{compressed: true, inner: pubkey_1}, Network::Testnet).script_pubkey()) } else { None },
+                               channel_type: if incl_chan_type { Some(ChannelTypeFeatures::empty()) } else { None },
+                       },
                        funding_feerate_sat_per_1000_weight: 821716,
-                       commitment_feerate_sat_per_1000_weight: 821716,
-                       funding_satoshis: 1311768467284833366,
-                       dust_limit_satoshis: 3608586615801332854,
-                       max_htlc_value_in_flight_msat: 8517154655701053848,
-                       htlc_minimum_msat: 2316138423780173,
-                       to_self_delay: 49340,
-                       max_accepted_htlcs: 49340,
                        locktime: 305419896,
-                       funding_pubkey: pubkey_1,
-                       revocation_basepoint: pubkey_2,
-                       payment_basepoint: pubkey_3,
-                       delayed_payment_basepoint: pubkey_4,
-                       htlc_basepoint: pubkey_5,
-                       first_per_commitment_point: pubkey_6,
                        second_per_commitment_point: pubkey_7,
-                       channel_flags: if random_bit { 1 << 5 } else { 0 },
-                       shutdown_scriptpubkey: if shutdown { Some(Address::p2pkh(&::bitcoin::PublicKey{compressed: true, inner: pubkey_1}, Network::Testnet).script_pubkey()) } else { None },
-                       channel_type: if incl_chan_type { Some(ChannelTypeFeatures::empty()) } else { None },
                        require_confirmed_inputs: if require_confirmed_inputs { Some(()) } else { None },
                };
                let encoded_value = open_channelv2.encode();
@@ -3317,7 +3500,6 @@ mod tests {
                        target_value.append(&mut <Vec<u8>>::from_hex("00").unwrap());
                }
                if shutdown {
-                       target_value.append(&mut <Vec<u8>>::from_hex("001b").unwrap()); // Type 0 + Length 27
                        target_value.append(&mut <Vec<u8>>::from_hex("001976a91479b000887626b294a914501a4cd226b58b23598388ac").unwrap());
                }
                if incl_chan_type {
@@ -3358,22 +3540,24 @@ mod tests {
                let (_, pubkey_5) = get_keys_from!("0505050505050505050505050505050505050505050505050505050505050505", secp_ctx);
                let (_, pubkey_6) = get_keys_from!("0606060606060606060606060606060606060606060606060606060606060606", secp_ctx);
                let accept_channel = msgs::AcceptChannel {
-                       temporary_channel_id: ChannelId::from_bytes([2; 32]),
-                       dust_limit_satoshis: 1311768467284833366,
-                       max_htlc_value_in_flight_msat: 2536655962884945560,
+                       common_fields: CommonAcceptChannelFields {
+                               temporary_channel_id: ChannelId::from_bytes([2; 32]),
+                               dust_limit_satoshis: 1311768467284833366,
+                               max_htlc_value_in_flight_msat: 2536655962884945560,
+                               htlc_minimum_msat: 2316138423780173,
+                               minimum_depth: 821716,
+                               to_self_delay: 49340,
+                               max_accepted_htlcs: 49340,
+                               funding_pubkey: pubkey_1,
+                               revocation_basepoint: pubkey_2,
+                               payment_basepoint: pubkey_3,
+                               delayed_payment_basepoint: pubkey_4,
+                               htlc_basepoint: pubkey_5,
+                               first_per_commitment_point: pubkey_6,
+                               shutdown_scriptpubkey: if shutdown { Some(Address::p2pkh(&::bitcoin::PublicKey{compressed: true, inner: pubkey_1}, Network::Testnet).script_pubkey()) } else { None },
+                               channel_type: None,
+                       },
                        channel_reserve_satoshis: 3608586615801332854,
-                       htlc_minimum_msat: 2316138423780173,
-                       minimum_depth: 821716,
-                       to_self_delay: 49340,
-                       max_accepted_htlcs: 49340,
-                       funding_pubkey: pubkey_1,
-                       revocation_basepoint: pubkey_2,
-                       payment_point: pubkey_3,
-                       delayed_payment_basepoint: pubkey_4,
-                       htlc_basepoint: pubkey_5,
-                       first_per_commitment_point: pubkey_6,
-                       shutdown_scriptpubkey: if shutdown { Some(Address::p2pkh(&::bitcoin::PublicKey{compressed: true, inner: pubkey_1}, Network::Testnet).script_pubkey()) } else { None },
-                       channel_type: None,
                        #[cfg(taproot)]
                        next_local_nonce: None,
                };
@@ -3401,23 +3585,25 @@ mod tests {
                let (_, pubkey_6) = get_keys_from!("0606060606060606060606060606060606060606060606060606060606060606", secp_ctx);
                let (_, pubkey_7) = get_keys_from!("0707070707070707070707070707070707070707070707070707070707070707", secp_ctx);
                let accept_channelv2 = msgs::AcceptChannelV2 {
-                       temporary_channel_id: ChannelId::from_bytes([2; 32]),
+                       common_fields: CommonAcceptChannelFields {
+                               temporary_channel_id: ChannelId::from_bytes([2; 32]),
+                               dust_limit_satoshis: 1311768467284833366,
+                               max_htlc_value_in_flight_msat: 2536655962884945560,
+                               htlc_minimum_msat: 2316138423780173,
+                               minimum_depth: 821716,
+                               to_self_delay: 49340,
+                               max_accepted_htlcs: 49340,
+                               funding_pubkey: pubkey_1,
+                               revocation_basepoint: pubkey_2,
+                               payment_basepoint: pubkey_3,
+                               delayed_payment_basepoint: pubkey_4,
+                               htlc_basepoint: pubkey_5,
+                               first_per_commitment_point: pubkey_6,
+                               shutdown_scriptpubkey: if shutdown { Some(Address::p2pkh(&::bitcoin::PublicKey{compressed: true, inner: pubkey_1}, Network::Testnet).script_pubkey()) } else { None },
+                               channel_type: None,
+                       },
                        funding_satoshis: 1311768467284833366,
-                       dust_limit_satoshis: 1311768467284833366,
-                       max_htlc_value_in_flight_msat: 2536655962884945560,
-                       htlc_minimum_msat: 2316138423780173,
-                       minimum_depth: 821716,
-                       to_self_delay: 49340,
-                       max_accepted_htlcs: 49340,
-                       funding_pubkey: pubkey_1,
-                       revocation_basepoint: pubkey_2,
-                       payment_basepoint: pubkey_3,
-                       delayed_payment_basepoint: pubkey_4,
-                       htlc_basepoint: pubkey_5,
-                       first_per_commitment_point: pubkey_6,
                        second_per_commitment_point: pubkey_7,
-                       shutdown_scriptpubkey: if shutdown { Some(Address::p2pkh(&::bitcoin::PublicKey{compressed: true, inner: pubkey_1}, Network::Testnet).script_pubkey()) } else { None },
-                       channel_type: None,
                        require_confirmed_inputs: None,
                };
                let encoded_value = accept_channelv2.encode();
@@ -3437,7 +3623,6 @@ mod tests {
                target_value.append(&mut <Vec<u8>>::from_hex("03f006a18d5653c4edf5391ff23a61f03ff83d237e880ee61187fa9f379a028e0a").unwrap()); // first_per_commitment_point
                target_value.append(&mut <Vec<u8>>::from_hex("02989c0b76cb563971fdc9bef31ec06c3560f3249d6ee9e5d83c57625596e05f6f").unwrap()); // second_per_commitment_point
                if shutdown {
-                       target_value.append(&mut <Vec<u8>>::from_hex("001b").unwrap()); // Type 0 + Length 27
                        target_value.append(&mut <Vec<u8>>::from_hex("001976a91479b000887626b294a914501a4cd226b58b23598388ac").unwrap());
                }
                assert_eq!(encoded_value, target_value);