Address custom HTLC TLV fixups
[rust-lightning] / lightning / src / ln / msgs.rs
index 4b2eb9674fa8acefa0afba97245ca4674d49e577..515dcbba2d2e136846697dc990d582270e07e1d4 100644 (file)
 //! raw socket events into your non-internet-facing system and then send routing events back to
 //! track the network on the less-secure system.
 
+use bitcoin::blockdata::constants::ChainHash;
 use bitcoin::secp256k1::PublicKey;
 use bitcoin::secp256k1::ecdsa::Signature;
-use bitcoin::secp256k1;
+use bitcoin::{secp256k1, Witness};
 use bitcoin::blockdata::script::Script;
 use bitcoin::hash_types::{Txid, BlockHash};
 
@@ -42,7 +43,7 @@ use crate::io_extras::read_to_end;
 
 use crate::events::{MessageSendEventsProvider, OnionMessageProvider};
 use crate::util::logger;
-use crate::util::ser::{LengthReadable, Readable, ReadableArgs, Writeable, Writer, WithoutLength, FixedLengthReader, HighZeroBytesDroppedBigSize, Hostname};
+use crate::util::ser::{LengthReadable, Readable, ReadableArgs, Writeable, Writer, WithoutLength, FixedLengthReader, HighZeroBytesDroppedBigSize, Hostname, TransactionU16LenLimited, BigSize};
 
 use crate::ln::{PaymentPreimage, PaymentHash, PaymentSecret};
 
@@ -88,6 +89,10 @@ pub enum DecodeError {
 pub struct Init {
        /// The relevant features which the sender supports.
        pub features: InitFeatures,
+       /// Indicates chains the sender is interested in.
+       ///
+       /// If there are no common chains, the connection will be closed.
+       pub networks: Option<Vec<ChainHash>>,
        /// The receipient's network address.
        ///
        /// This adds the option to report a remote IP address back to a connecting peer using the init
@@ -158,6 +163,8 @@ pub struct Pong {
 
 /// An [`open_channel`] message to be sent to or received from a peer.
 ///
+/// Used in V1 channel establishment
+///
 /// [`open_channel`]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#the-open_channel-message
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct OpenChannel {
@@ -199,8 +206,8 @@ pub struct OpenChannel {
        pub first_per_commitment_point: PublicKey,
        /// The channel flags to be used
        pub channel_flags: u8,
-       /// Optionally, a request to pre-set the to-sender output's `scriptPubkey` for when we collaboratively close
-       pub shutdown_scriptpubkey: OptionalField<Script>,
+       /// A request to pre-set the to-sender output's `scriptPubkey` for when we collaboratively close
+       pub shutdown_scriptpubkey: Option<Script>,
        /// The channel type that this channel will represent
        ///
        /// If this is `None`, we derive the channel type from the intersection of our
@@ -208,8 +215,69 @@ pub struct OpenChannel {
        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, PartialEq, Eq)]
+pub struct OpenChannelV2 {
+       /// The genesis hash of the blockchain where the channel is to be opened
+       pub chain_hash: BlockHash,
+       /// A temporary channel ID derived using a zeroed out value for the channel acceptor's revocation basepoint
+       pub temporary_channel_id: [u8; 32],
+       /// 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
+       pub funding_satoshis: u64,
+       /// The threshold below which outputs on transactions broadcast by the channel initiator will be
+       /// omitted
+       pub dust_limit_satoshis: u64,
+       /// The maximum inbound HTLC value in flight towards channel initiator, in milli-satoshi
+       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 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
+       pub revocation_basepoint: PublicKey,
+       /// A payment key to channel initiator for transactions broadcast by counterparty
+       pub payment_basepoint: PublicKey,
+       /// Used to derive a payment key to channel initiator for transactions broadcast by channel
+       /// initiator
+       pub delayed_payment_basepoint: PublicKey,
+       /// Used to derive an HTLC payment key to channel initiator
+       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
+       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<Script>,
+       /// 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.
+       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.
 ///
+/// 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, PartialEq, Eq)]
 pub struct AcceptChannel {
@@ -241,8 +309,8 @@ pub struct AcceptChannel {
        pub htlc_basepoint: PublicKey,
        /// The first to-be-broadcast-by-sender transaction's per commitment point
        pub first_per_commitment_point: PublicKey,
-       /// Optionally, a request to pre-set the to-sender output's scriptPubkey for when we collaboratively close
-       pub shutdown_scriptpubkey: OptionalField<Script>,
+       /// A request to pre-set the to-sender output's scriptPubkey for when we collaboratively close
+       pub shutdown_scriptpubkey: Option<Script>,
        /// The channel type that this channel will represent.
        ///
        /// If this is `None`, we derive the channel type from the intersection of
@@ -254,8 +322,63 @@ pub struct AcceptChannel {
        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, PartialEq, Eq)]
+pub struct AcceptChannelV2 {
+       /// The same `temporary_channel_id` received from the initiator's `open_channel2` message.
+       pub temporary_channel_id: [u8; 32],
+       /// 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
+       pub max_htlc_value_in_flight_msat: u64,
+       /// The minimum HTLC size incoming to channel acceptor, 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 channel acceptor
+       pub max_accepted_htlcs: u16,
+       /// The channel acceptor'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 channel acceptor for transactions broadcast by counterparty
+       pub payment_basepoint: PublicKey,
+       /// Used to derive a payment key to channel acceptor for transactions broadcast by channel
+       /// acceptor
+       pub delayed_payment_basepoint: PublicKey,
+       /// Used to derive an HTLC payment key to channel acceptor for transactions broadcast by counterparty
+       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<Script>,
+       /// 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.
+       ///
+       /// This is required to match the equivalent field in [`OpenChannelV2::channel_type`].
+       pub channel_type: Option<ChannelTypeFeatures>,
+       /// Optionally, a requirement that only confirmed inputs can be added
+       pub require_confirmed_inputs: Option<()>,
+}
+
 /// A [`funding_created`] message to be sent to or received from a peer.
 ///
+/// Used in V1 channel establishment
+///
 /// [`funding_created`]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#the-funding_created-message
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct FundingCreated {
@@ -277,6 +400,8 @@ pub struct FundingCreated {
 
 /// A [`funding_signed`] message to be sent to or received from a peer.
 ///
+/// Used in V1 channel establishment
+///
 /// [`funding_signed`]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#the-funding_signed-message
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct FundingSigned {
@@ -305,6 +430,128 @@ pub struct ChannelReady {
        pub short_channel_id_alias: Option<u64>,
 }
 
+/// A tx_add_input message for adding an input during interactive transaction construction
+///
+// TODO(dual_funding): Add spec link for `tx_add_input`.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct TxAddInput {
+       /// The channel ID
+       pub channel_id: [u8; 32],
+       /// A randomly chosen unique identifier for this input, which is even for initiators and odd for
+       /// non-initiators.
+       pub serial_id: u64,
+       /// Serialized transaction that contains the output this input spends to verify that it is non
+       /// malleable.
+       pub prevtx: TransactionU16LenLimited,
+       /// The index of the output being spent
+       pub prevtx_out: u32,
+       /// The sequence number of this input
+       pub sequence: u32,
+}
+
+/// A tx_add_output message for adding an output during interactive transaction construction.
+///
+// TODO(dual_funding): Add spec link for `tx_add_output`.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct TxAddOutput {
+       /// The channel ID
+       pub channel_id: [u8; 32],
+       /// A randomly chosen unique identifier for this output, which is even for initiators and odd for
+       /// non-initiators.
+       pub serial_id: u64,
+       /// The satoshi value of the output
+       pub sats: u64,
+       /// The scriptPubKey for the output
+       pub script: Script,
+}
+
+/// A tx_remove_input message for removing an input during interactive transaction construction.
+///
+// TODO(dual_funding): Add spec link for `tx_remove_input`.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct TxRemoveInput {
+       /// The channel ID
+       pub channel_id: [u8; 32],
+       /// The serial ID of the input to be removed
+       pub serial_id: u64,
+}
+
+/// A tx_remove_output message for removing an output during interactive transaction construction.
+///
+// TODO(dual_funding): Add spec link for `tx_remove_output`.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct TxRemoveOutput {
+       /// The channel ID
+       pub channel_id: [u8; 32],
+       /// The serial ID of the output to be removed
+       pub serial_id: u64,
+}
+
+/// A tx_complete message signalling the conclusion of a peer's transaction contributions during
+/// interactive transaction construction.
+///
+// TODO(dual_funding): Add spec link for `tx_complete`.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct TxComplete {
+       /// The channel ID
+       pub channel_id: [u8; 32],
+}
+
+/// A tx_signatures message containing the sender's signatures for a transaction constructed with
+/// interactive transaction construction.
+///
+// TODO(dual_funding): Add spec link for `tx_signatures`.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct TxSignatures {
+       /// The channel ID
+       pub channel_id: [u8; 32],
+       /// The TXID
+       pub tx_hash: Txid,
+       /// The list of witnesses
+       pub witnesses: Vec<Witness>,
+}
+
+/// A tx_init_rbf message which initiates a replacement of the transaction after it's been
+/// completed.
+///
+// TODO(dual_funding): Add spec link for `tx_init_rbf`.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct TxInitRbf {
+       /// The channel ID
+       pub channel_id: [u8; 32],
+       /// The locktime of the transaction
+       pub locktime: u32,
+       /// The feerate of the transaction
+       pub feerate_sat_per_1000_weight: u32,
+       /// The number of satoshis the sender will contribute to or, if negative, remove from
+       /// (e.g. splice-out) the funding output of the transaction
+       pub funding_output_contribution: Option<i64>,
+}
+
+/// A tx_ack_rbf message which acknowledges replacement of the transaction after it's been
+/// completed.
+///
+// TODO(dual_funding): Add spec link for `tx_ack_rbf`.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct TxAckRbf {
+       /// The channel ID
+       pub channel_id: [u8; 32],
+       /// The number of satoshis the sender will contribute to or, if negative, remove from
+       /// (e.g. splice-out) the funding output of the transaction
+       pub funding_output_contribution: Option<i64>,
+}
+
+/// A tx_abort message which signals the cancellation of an in-progress transaction negotiation.
+///
+// TODO(dual_funding): Add spec link for `tx_abort`.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct TxAbort {
+       /// The channel ID
+       pub channel_id: [u8; 32],
+       /// Message data
+       pub data: Vec<u8>,
+}
+
 /// A [`shutdown`] message to be sent to or received from a peer.
 ///
 /// [`shutdown`]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#closing-initiation-shutdown
@@ -363,6 +610,11 @@ pub struct UpdateAddHTLC {
        pub payment_hash: PaymentHash,
        /// The expiry height of the HTLC
        pub cltv_expiry: u32,
+       /// The extra fee skimmed by the sender of this message. See
+       /// [`ChannelConfig::accept_underpaying_htlcs`].
+       ///
+       /// [`ChannelConfig::accept_underpaying_htlcs`]: crate::util::config::ChannelConfig::accept_underpaying_htlcs
+       pub skimmed_fee_msat: Option<u64>,
        pub(crate) onion_routing_packet: OnionPacket,
 }
 
@@ -458,20 +710,6 @@ pub struct UpdateFee {
        pub feerate_per_kw: u32,
 }
 
-#[derive(Clone, Debug, PartialEq, Eq)]
-/// Proof that the sender knows the per-commitment secret of the previous commitment transaction.
-///
-/// This is used to convince the recipient that the channel is at a certain commitment
-/// number even if they lost that data due to a local failure. Of course, the peer may lie
-/// and even later commitments may have been revoked.
-pub struct DataLossProtect {
-       /// Proof that the sender knows the per-commitment secret of a specific commitment transaction
-       /// belonging to the recipient
-       pub your_last_per_commitment_secret: [u8; 32],
-       /// The sender's per-commitment point for their current commitment transaction
-       pub my_current_per_commitment_point: PublicKey,
-}
-
 /// A [`channel_reestablish`] message to be sent to or received from a peer.
 ///
 /// [`channel_reestablish`]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#message-retransmission
@@ -483,8 +721,13 @@ pub struct ChannelReestablish {
        pub next_local_commitment_number: u64,
        /// The next commitment number for the recipient
        pub next_remote_commitment_number: u64,
-       /// Optionally, a field proving that next_remote_commitment_number-1 has been revoked
-       pub data_loss_protect: OptionalField<DataLossProtect>,
+       /// Proof that the sender knows the per-commitment secret of a specific commitment transaction
+       /// belonging to the recipient
+       pub your_last_per_commitment_secret: [u8; 32],
+       /// The sender's per-commitment point for their current commitment transaction
+       pub my_current_per_commitment_point: PublicKey,
+       /// The next funding transaction ID
+       pub next_funding_txid: Option<Txid>,
 }
 
 /// An [`announcement_signatures`] message to be sent to or received from a peer.
@@ -730,7 +973,11 @@ pub struct UnsignedChannelAnnouncement {
        pub bitcoin_key_1: NodeId,
        /// The funding key for the second node
        pub bitcoin_key_2: NodeId,
-       pub(crate) excess_data: Vec<u8>,
+       /// Excess data which was signed as a part of the message which we do not (yet) understand how
+       /// to decode.
+       ///
+       /// This is stored to ensure forward-compatibility as new fields are added to the lightning gossip protocol.
+       pub excess_data: Vec<u8>,
 }
 /// A [`channel_announcement`] message to be sent to or received from a peer.
 ///
@@ -904,6 +1151,11 @@ pub enum ErrorAction {
                /// An error message which we should make an effort to send before we disconnect.
                msg: Option<ErrorMessage>
        },
+       /// The peer did something incorrect. Tell them without closing any channels and disconnect them.
+       DisconnectPeerWithWarning {
+               /// A warning message which we should make an effort to send before we disconnect.
+               msg: WarningMessage,
+       },
        /// The peer did something harmless that we weren't able to process, just log and ignore
        // New code should *not* use this. New code must use IgnoreAndLog, below!
        IgnoreError,
@@ -957,20 +1209,6 @@ pub struct CommitmentUpdate {
        pub commitment_signed: CommitmentSigned,
 }
 
-/// Messages could have optional fields to use with extended features
-/// As we wish to serialize these differently from `Option<T>`s (`Options` get a tag byte, but
-/// [`OptionalField`] simply gets `Present` if there are enough bytes to read into it), we have a
-/// separate enum type for them.
-///
-/// This is not exported to bindings users due to a free generic in `T`
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub enum OptionalField<T> {
-       /// Optional field is included in message
-       Present(T),
-       /// Optional field is absent in message
-       Absent
-}
-
 /// A trait to describe an object which can receive channel messages.
 ///
 /// Messages MAY be called in parallel when they originate from different `their_node_ids`, however
@@ -979,8 +1217,12 @@ pub trait ChannelMessageHandler : MessageSendEventsProvider {
        // Channel init:
        /// Handle an incoming `open_channel` message from the given peer.
        fn handle_open_channel(&self, their_node_id: &PublicKey, msg: &OpenChannel);
+       /// Handle an incoming `open_channel2` message from the given peer.
+       fn handle_open_channel_v2(&self, their_node_id: &PublicKey, msg: &OpenChannelV2);
        /// Handle an incoming `accept_channel` message from the given peer.
        fn handle_accept_channel(&self, their_node_id: &PublicKey, msg: &AcceptChannel);
+       /// Handle an incoming `accept_channel2` message from the given peer.
+       fn handle_accept_channel_v2(&self, their_node_id: &PublicKey, msg: &AcceptChannelV2);
        /// Handle an incoming `funding_created` message from the given peer.
        fn handle_funding_created(&self, their_node_id: &PublicKey, msg: &FundingCreated);
        /// Handle an incoming `funding_signed` message from the given peer.
@@ -994,6 +1236,26 @@ pub trait ChannelMessageHandler : MessageSendEventsProvider {
        /// Handle an incoming `closing_signed` message from the given peer.
        fn handle_closing_signed(&self, their_node_id: &PublicKey, msg: &ClosingSigned);
 
+       // Interactive channel construction
+       /// Handle an incoming `tx_add_input message` from the given peer.
+       fn handle_tx_add_input(&self, their_node_id: &PublicKey, msg: &TxAddInput);
+       /// Handle an incoming `tx_add_output` message from the given peer.
+       fn handle_tx_add_output(&self, their_node_id: &PublicKey, msg: &TxAddOutput);
+       /// Handle an incoming `tx_remove_input` message from the given peer.
+       fn handle_tx_remove_input(&self, their_node_id: &PublicKey, msg: &TxRemoveInput);
+       /// Handle an incoming `tx_remove_output` message from the given peer.
+       fn handle_tx_remove_output(&self, their_node_id: &PublicKey, msg: &TxRemoveOutput);
+       /// Handle an incoming `tx_complete message` from the given peer.
+       fn handle_tx_complete(&self, their_node_id: &PublicKey, msg: &TxComplete);
+       /// Handle an incoming `tx_signatures` message from the given peer.
+       fn handle_tx_signatures(&self, their_node_id: &PublicKey, msg: &TxSignatures);
+       /// Handle an incoming `tx_init_rbf` message from the given peer.
+       fn handle_tx_init_rbf(&self, their_node_id: &PublicKey, msg: &TxInitRbf);
+       /// Handle an incoming `tx_ack_rbf` message from the given peer.
+       fn handle_tx_ack_rbf(&self, their_node_id: &PublicKey, msg: &TxAckRbf);
+       /// Handle an incoming `tx_abort message` from the given peer.
+       fn handle_tx_abort(&self, their_node_id: &PublicKey, msg: &TxAbort);
+
        // HTLC handling:
        /// Handle an incoming `update_add_htlc` message from the given peer.
        fn handle_update_add_htlc(&self, their_node_id: &PublicKey, msg: &UpdateAddHTLC);
@@ -1047,6 +1309,12 @@ pub trait ChannelMessageHandler : MessageSendEventsProvider {
        ///
        /// Note that this method is called before [`Self::peer_connected`].
        fn provided_init_features(&self, their_node_id: &PublicKey) -> InitFeatures;
+
+       /// Gets the genesis hashes for this `ChannelMessageHandler` indicating which chains it supports.
+       ///
+       /// If it's `None`, then no particular network chain hash compatibility will be enforced when
+       /// connecting to peers.
+       fn get_genesis_hashes(&self) -> Option<Vec<ChainHash>>;
 }
 
 /// A trait to describe an object which can receive routing messages.
@@ -1155,30 +1423,45 @@ mod fuzzy_internal_msgs {
        // These types aren't intended to be pub, but are exposed for direct fuzzing (as we deserialize
        // them from untrusted input):
        #[derive(Clone)]
-       pub(crate) struct FinalOnionHopData {
-               pub(crate) payment_secret: PaymentSecret,
+       pub struct FinalOnionHopData {
+               pub payment_secret: PaymentSecret,
                /// The total value, in msat, of the payment as received by the ultimate recipient.
                /// Message serialization may panic if this value is more than 21 million Bitcoin.
-               pub(crate) total_msat: u64,
+               pub total_msat: u64,
        }
 
-       pub(crate) enum OnionHopDataFormat {
-               NonFinalNode {
+       pub enum InboundOnionPayload {
+               Forward {
                        short_channel_id: u64,
+                       /// The value, in msat, of the payment after this hop's fee is deducted.
+                       amt_to_forward: u64,
+                       outgoing_cltv_value: u32,
                },
-               FinalNode {
+               Receive {
                        payment_data: Option<FinalOnionHopData>,
                        payment_metadata: Option<Vec<u8>>,
                        keysend_preimage: Option<PaymentPreimage>,
+                       custom_tlvs: Vec<(u64, Vec<u8>)>,
+                       amt_msat: u64,
+                       outgoing_cltv_value: u32,
                },
        }
 
-       pub struct OnionHopData {
-               pub(crate) format: OnionHopDataFormat,
-               /// The value, in msat, of the payment after this hop's fee is deducted.
-               /// Message serialization may panic if this value is more than 21 million Bitcoin.
-               pub(crate) amt_to_forward: u64,
-               pub(crate) outgoing_cltv_value: u32,
+       pub(crate) enum OutboundOnionPayload {
+               Forward {
+                       short_channel_id: u64,
+                       /// The value, in msat, of the payment after this hop's fee is deducted.
+                       amt_to_forward: u64,
+                       outgoing_cltv_value: u32,
+               },
+               Receive {
+                       payment_data: Option<FinalOnionHopData>,
+                       payment_metadata: Option<Vec<u8>>,
+                       keysend_preimage: Option<PaymentPreimage>,
+                       custom_tlvs: Vec<(u64, Vec<u8>)>,
+                       amt_msat: u64,
+                       outgoing_cltv_value: u32,
+               },
        }
 
        pub struct DecodedOnionErrorPacket {
@@ -1266,52 +1549,6 @@ impl From<io::Error> for DecodeError {
        }
 }
 
-impl Writeable for OptionalField<Script> {
-       fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
-               match *self {
-                       OptionalField::Present(ref script) => {
-                               // Note that Writeable for script includes the 16-bit length tag for us
-                               script.write(w)?;
-                       },
-                       OptionalField::Absent => {}
-               }
-               Ok(())
-       }
-}
-
-impl Readable for OptionalField<Script> {
-       fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
-               match <u16 as Readable>::read(r) {
-                       Ok(len) => {
-                               let mut buf = vec![0; len as usize];
-                               r.read_exact(&mut buf)?;
-                               Ok(OptionalField::Present(Script::from(buf)))
-                       },
-                       Err(DecodeError::ShortRead) => Ok(OptionalField::Absent),
-                       Err(e) => Err(e)
-               }
-       }
-}
-
-impl Writeable for OptionalField<u64> {
-       fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
-               match *self {
-                       OptionalField::Present(ref value) => {
-                               value.write(w)?;
-                       },
-                       OptionalField::Absent => {}
-               }
-               Ok(())
-       }
-}
-
-impl Readable for OptionalField<u64> {
-       fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
-               let value: u64 = Readable::read(r)?;
-               Ok(OptionalField::Present(value))
-       }
-}
-
 #[cfg(not(taproot))]
 impl_writeable_msg!(AcceptChannel, {
        temporary_channel_id,
@@ -1328,8 +1565,8 @@ impl_writeable_msg!(AcceptChannel, {
        delayed_payment_basepoint,
        htlc_basepoint,
        first_per_commitment_point,
-       shutdown_scriptpubkey
 }, {
+       (0, shutdown_scriptpubkey, (option, encoding: (Script, WithoutLength))), // Don't encode length twice.
        (1, channel_type, option),
 });
 
@@ -1349,12 +1586,88 @@ impl_writeable_msg!(AcceptChannel, {
        delayed_payment_basepoint,
        htlc_basepoint,
        first_per_commitment_point,
-       shutdown_scriptpubkey
 }, {
+       (0, shutdown_scriptpubkey, (option, encoding: (Script, WithoutLength))), // Don't encode length twice.
        (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),
+});
+
+impl_writeable_msg!(TxAddInput, {
+       channel_id,
+       serial_id,
+       prevtx,
+       prevtx_out,
+       sequence,
+}, {});
+
+impl_writeable_msg!(TxAddOutput, {
+       channel_id,
+       serial_id,
+       sats,
+       script,
+}, {});
+
+impl_writeable_msg!(TxRemoveInput, {
+       channel_id,
+       serial_id,
+}, {});
+
+impl_writeable_msg!(TxRemoveOutput, {
+       channel_id,
+       serial_id,
+}, {});
+
+impl_writeable_msg!(TxComplete, {
+       channel_id,
+}, {});
+
+impl_writeable_msg!(TxSignatures, {
+       channel_id,
+       tx_hash,
+       witnesses,
+}, {});
+
+impl_writeable_msg!(TxInitRbf, {
+       channel_id,
+       locktime,
+       feerate_sat_per_1000_weight,
+}, {
+       (0, funding_output_contribution, option),
+});
+
+impl_writeable_msg!(TxAckRbf, {
+       channel_id,
+}, {
+       (0, funding_output_contribution, option),
+});
+
+impl_writeable_msg!(TxAbort, {
+       channel_id,
+       data,
+}, {});
+
 impl_writeable_msg!(AnnouncementSignatures, {
        channel_id,
        short_channel_id,
@@ -1362,42 +1675,15 @@ impl_writeable_msg!(AnnouncementSignatures, {
        bitcoin_signature
 }, {});
 
-impl Writeable for ChannelReestablish {
-       fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
-               self.channel_id.write(w)?;
-               self.next_local_commitment_number.write(w)?;
-               self.next_remote_commitment_number.write(w)?;
-               match self.data_loss_protect {
-                       OptionalField::Present(ref data_loss_protect) => {
-                               (*data_loss_protect).your_last_per_commitment_secret.write(w)?;
-                               (*data_loss_protect).my_current_per_commitment_point.write(w)?;
-                       },
-                       OptionalField::Absent => {}
-               }
-               Ok(())
-       }
-}
-
-impl Readable for ChannelReestablish{
-       fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
-               Ok(Self {
-                       channel_id: Readable::read(r)?,
-                       next_local_commitment_number: Readable::read(r)?,
-                       next_remote_commitment_number: Readable::read(r)?,
-                       data_loss_protect: {
-                               match <[u8; 32] as Readable>::read(r) {
-                                       Ok(your_last_per_commitment_secret) =>
-                                               OptionalField::Present(DataLossProtect {
-                                                       your_last_per_commitment_secret,
-                                                       my_current_per_commitment_point: Readable::read(r)?,
-                                               }),
-                                       Err(DecodeError::ShortRead) => OptionalField::Absent,
-                                       Err(e) => return Err(e)
-                               }
-                       }
-               })
-       }
-}
+impl_writeable_msg!(ChannelReestablish, {
+       channel_id,
+       next_local_commitment_number,
+       next_remote_commitment_number,
+       your_last_per_commitment_secret,
+       my_current_per_commitment_point,
+}, {
+       (0, next_funding_txid, option),
+});
 
 impl_writeable_msg!(ClosingSigned,
        { channel_id, fee_satoshis, signature },
@@ -1477,7 +1763,8 @@ impl Writeable for Init {
                self.features.write_up_to_13(w)?;
                self.features.write(w)?;
                encode_tlv_stream!(w, {
-                       (3, self.remote_network_address, option)
+                       (1, self.networks.as_ref().map(|n| WithoutLength(n)), option),
+                       (3, self.remote_network_address, option),
                });
                Ok(())
        }
@@ -1488,11 +1775,14 @@ impl Readable for Init {
                let global_features: InitFeatures = Readable::read(r)?;
                let features: InitFeatures = Readable::read(r)?;
                let mut remote_network_address: Option<NetAddress> = None;
+               let mut networks: Option<WithoutLength<Vec<ChainHash>>> = None;
                decode_tlv_stream!(r, {
+                       (1, networks, option),
                        (3, remote_network_address, option)
                });
                Ok(Init {
-                       features: features.or(global_features),
+                       features: features | global_features,
+                       networks: networks.map(|n| n.0),
                        remote_network_address,
                })
        }
@@ -1517,11 +1807,37 @@ impl_writeable_msg!(OpenChannel, {
        htlc_basepoint,
        first_per_commitment_point,
        channel_flags,
-       shutdown_scriptpubkey
 }, {
+       (0, shutdown_scriptpubkey, (option, encoding: (Script, WithoutLength))), // Don't encode length twice.
        (1, channel_type, option),
 });
 
+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),
+});
+
 #[cfg(not(taproot))]
 impl_writeable_msg!(RevokeAndACK, {
        channel_id,
@@ -1611,8 +1927,10 @@ impl_writeable_msg!(UpdateAddHTLC, {
        amount_msat,
        payment_hash,
        cltv_expiry,
-       onion_routing_packet
-}, {});
+       onion_routing_packet,
+}, {
+       (65537, skimmed_fee_msat, option)
+});
 
 impl Readable for OnionMessage {
        fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
@@ -1652,31 +1970,39 @@ impl Readable for FinalOnionHopData {
        }
 }
 
-impl Writeable for OnionHopData {
+impl Writeable for OutboundOnionPayload {
        fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
-               match self.format {
-                       OnionHopDataFormat::NonFinalNode { short_channel_id } => {
+               match self {
+                       Self::Forward { short_channel_id, amt_to_forward, outgoing_cltv_value } => {
                                _encode_varint_length_prefixed_tlv!(w, {
-                                       (2, HighZeroBytesDroppedBigSize(self.amt_to_forward), required),
-                                       (4, HighZeroBytesDroppedBigSize(self.outgoing_cltv_value), required),
+                                       (2, HighZeroBytesDroppedBigSize(*amt_to_forward), required),
+                                       (4, HighZeroBytesDroppedBigSize(*outgoing_cltv_value), required),
                                        (6, short_channel_id, required)
                                });
                        },
-                       OnionHopDataFormat::FinalNode { ref payment_data, ref payment_metadata, ref keysend_preimage } => {
+                       Self::Receive {
+                               ref payment_data, ref payment_metadata, ref keysend_preimage, amt_msat,
+                               outgoing_cltv_value, ref custom_tlvs,
+                       } => {
+                               // We need to update [`ln::outbound_payment::RecipientOnionFields::with_custom_tlvs`]
+                               // to reject any reserved types in the experimental range if new ones are ever
+                               // standardized.
+                               let keysend_tlv = keysend_preimage.map(|preimage| (5482373484, preimage.encode()));
+                               let mut custom_tlvs: Vec<&(u64, Vec<u8>)> = custom_tlvs.iter().chain(keysend_tlv.iter()).collect();
+                               custom_tlvs.sort_unstable_by_key(|(typ, _)| *typ);
                                _encode_varint_length_prefixed_tlv!(w, {
-                                       (2, HighZeroBytesDroppedBigSize(self.amt_to_forward), required),
-                                       (4, HighZeroBytesDroppedBigSize(self.outgoing_cltv_value), required),
+                                       (2, HighZeroBytesDroppedBigSize(*amt_msat), required),
+                                       (4, HighZeroBytesDroppedBigSize(*outgoing_cltv_value), required),
                                        (8, payment_data, option),
-                                       (16, payment_metadata.as_ref().map(|m| WithoutLength(m)), option),
-                                       (5482373484, keysend_preimage, option)
-                               });
+                                       (16, payment_metadata.as_ref().map(|m| WithoutLength(m)), option)
+                               }, custom_tlvs.iter());
                        },
                }
                Ok(())
        }
 }
 
-impl Readable for OnionHopData {
+impl Readable for InboundOnionPayload {
        fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
                let mut amt = HighZeroBytesDroppedBigSize(0u64);
                let mut cltv_value = HighZeroBytesDroppedBigSize(0u32);
@@ -1684,7 +2010,11 @@ impl Readable for OnionHopData {
                let mut payment_data: Option<FinalOnionHopData> = None;
                let mut payment_metadata: Option<WithoutLength<Vec<u8>>> = None;
                let mut keysend_preimage: Option<PaymentPreimage> = None;
-               read_tlv_fields!(r, {
+               let mut custom_tlvs = Vec::new();
+
+               let tlv_len = BigSize::read(r)?;
+               let rd = FixedLengthReader::new(r, tlv_len.0);
+               decode_tlv_stream_with_custom_tlv_decode!(rd, {
                        (2, amt, required),
                        (4, cltv_value, required),
                        (6, short_id, option),
@@ -1692,41 +2022,44 @@ impl Readable for OnionHopData {
                        (16, payment_metadata, option),
                        // See https://github.com/lightning/blips/blob/master/blip-0003.md
                        (5482373484, keysend_preimage, option)
+               }, |msg_type: u64, msg_reader: &mut FixedLengthReader<_>| -> Result<bool, DecodeError> {
+                       if msg_type < 1 << 16 { return Ok(false) }
+                       let mut value = Vec::new();
+                       msg_reader.read_to_end(&mut value)?;
+                       custom_tlvs.push((msg_type, value));
+                       Ok(true)
                });
 
-               let format = if let Some(short_channel_id) = short_id {
-                       if payment_data.is_some() { return Err(DecodeError::InvalidValue); }
+               if amt.0 > MAX_VALUE_MSAT { return Err(DecodeError::InvalidValue) }
+               if let Some(short_channel_id) = short_id {
+                       if payment_data.is_some() { return Err(DecodeError::InvalidValue) }
                        if payment_metadata.is_some() { return Err(DecodeError::InvalidValue); }
-                       OnionHopDataFormat::NonFinalNode {
+                       Ok(Self::Forward {
                                short_channel_id,
-                       }
+                               amt_to_forward: amt.0,
+                               outgoing_cltv_value: cltv_value.0,
+                       })
                } else {
                        if let Some(data) = &payment_data {
                                if data.total_msat > MAX_VALUE_MSAT {
                                        return Err(DecodeError::InvalidValue);
                                }
                        }
-                       OnionHopDataFormat::FinalNode {
+                       Ok(Self::Receive {
                                payment_data,
                                payment_metadata: payment_metadata.map(|w| w.0),
                                keysend_preimage,
-                       }
-               };
-
-               if amt.0 > MAX_VALUE_MSAT {
-                       return Err(DecodeError::InvalidValue);
+                               amt_msat: amt.0,
+                               outgoing_cltv_value: cltv_value.0,
+                               custom_tlvs,
+                       })
                }
-               Ok(OnionHopData {
-                       format,
-                       amt_to_forward: amt.0,
-                       outgoing_cltv_value: cltv_value.0,
-               })
        }
 }
 
 // ReadableArgs because we need onion_utils::decode_next_hop to accommodate payment packets and
 // onion message packets.
-impl ReadableArgs<()> for OnionHopData {
+impl ReadableArgs<()> for InboundOnionPayload {
        fn read<R: Read>(r: &mut R, _arg: ()) -> Result<Self, DecodeError> {
                <Self as Readable>::read(r)
        }
@@ -2139,13 +2472,14 @@ impl_writeable_msg!(GossipTimestampFilter, {
 
 #[cfg(test)]
 mod tests {
+       use bitcoin::blockdata::constants::ChainHash;
+       use bitcoin::{Transaction, PackedLockTime, TxIn, Script, Sequence, Witness, TxOut};
        use hex;
        use crate::ln::{PaymentPreimage, PaymentHash, PaymentSecret};
        use crate::ln::features::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, NodeFeatures};
-       use crate::ln::msgs;
-       use crate::ln::msgs::{FinalOnionHopData, OptionalField, OnionErrorPacket, OnionHopDataFormat};
+       use crate::ln::msgs::{self, FinalOnionHopData, OnionErrorPacket};
        use crate::routing::gossip::{NodeAlias, NodeId};
-       use crate::util::ser::{Writeable, Readable, Hostname};
+       use crate::util::ser::{Writeable, Readable, Hostname, TransactionU16LenLimited};
 
        use bitcoin::hashes::hex::FromHex;
        use bitcoin::util::address::Address;
@@ -2160,25 +2494,41 @@ mod tests {
        use crate::io::{self, Cursor};
        use crate::prelude::*;
        use core::convert::TryFrom;
+       use core::str::FromStr;
+
+       use crate::chain::transaction::OutPoint;
 
        #[test]
-       fn encoding_channel_reestablish_no_secret() {
+       fn encoding_channel_reestablish() {
+               let public_key = {
+                       let secp_ctx = Secp256k1::new();
+                       PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&hex::decode("0101010101010101010101010101010101010101010101010101010101010101").unwrap()[..]).unwrap())
+               };
+
                let cr = msgs::ChannelReestablish {
                        channel_id: [4, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0],
                        next_local_commitment_number: 3,
                        next_remote_commitment_number: 4,
-                       data_loss_protect: OptionalField::Absent,
+                       your_last_per_commitment_secret: [9;32],
+                       my_current_per_commitment_point: public_key,
+                       next_funding_txid: None,
                };
 
                let encoded_value = cr.encode();
                assert_eq!(
                        encoded_value,
-                       vec![4, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4]
+                       vec![
+                               4, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, // channel_id
+                               0, 0, 0, 0, 0, 0, 0, 3, // next_local_commitment_number
+                               0, 0, 0, 0, 0, 0, 0, 4, // next_remote_commitment_number
+                               9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // your_last_per_commitment_secret
+                               3, 27, 132, 197, 86, 123, 18, 100, 64, 153, 93, 62, 213, 170, 186, 5, 101, 215, 30, 24, 52, 96, 72, 25, 255, 156, 23, 245, 233, 213, 221, 7, 143, // my_current_per_commitment_point
+                       ]
                );
        }
 
        #[test]
-       fn encoding_channel_reestablish_with_secret() {
+       fn encoding_channel_reestablish_with_next_funding_txid() {
                let public_key = {
                        let secp_ctx = Secp256k1::new();
                        PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&hex::decode("0101010101010101010101010101010101010101010101010101010101010101").unwrap()[..]).unwrap())
@@ -2188,13 +2538,26 @@ mod tests {
                        channel_id: [4, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0],
                        next_local_commitment_number: 3,
                        next_remote_commitment_number: 4,
-                       data_loss_protect: OptionalField::Present(msgs::DataLossProtect { your_last_per_commitment_secret: [9;32], my_current_per_commitment_point: public_key}),
+                       your_last_per_commitment_secret: [9;32],
+                       my_current_per_commitment_point: public_key,
+                       next_funding_txid: Some(Txid::from_hash(bitcoin::hashes::Hash::from_slice(&[
+                               48, 167, 250, 69, 152, 48, 103, 172, 164, 99, 59, 19, 23, 11, 92, 84, 15, 80, 4, 12, 98, 82, 75, 31, 201, 11, 91, 23, 98, 23, 53, 124,
+                       ]).unwrap())),
                };
 
                let encoded_value = cr.encode();
                assert_eq!(
                        encoded_value,
-                       vec![4, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 3, 27, 132, 197, 86, 123, 18, 100, 64, 153, 93, 62, 213, 170, 186, 5, 101, 215, 30, 24, 52, 96, 72, 25, 255, 156, 23, 245, 233, 213, 221, 7, 143]
+                       vec![
+                               4, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, // channel_id
+                               0, 0, 0, 0, 0, 0, 0, 3, // next_local_commitment_number
+                               0, 0, 0, 0, 0, 0, 0, 4, // next_remote_commitment_number
+                               9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // your_last_per_commitment_secret
+                               3, 27, 132, 197, 86, 123, 18, 100, 64, 153, 93, 62, 213, 170, 186, 5, 101, 215, 30, 24, 52, 96, 72, 25, 255, 156, 23, 245, 233, 213, 221, 7, 143, // my_current_per_commitment_point
+                               0, // Type (next_funding_txid)
+                               32, // Length
+                               48, 167, 250, 69, 152, 48, 103, 172, 164, 99, 59, 19, 23, 11, 92, 84, 15, 80, 4, 12, 98, 82, 75, 31, 201, 11, 91, 23, 98, 23, 53, 124, // Value
+                       ]
                );
        }
 
@@ -2477,7 +2840,7 @@ mod tests {
                        htlc_basepoint: pubkey_5,
                        first_per_commitment_point: pubkey_6,
                        channel_flags: if random_bit { 1 << 5 } else { 0 },
-                       shutdown_scriptpubkey: if shutdown { OptionalField::Present(Address::p2pkh(&::bitcoin::PublicKey{compressed: true, inner: pubkey_1}, Network::Testnet).script_pubkey()) } else { OptionalField::Absent },
+                       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();
@@ -2510,6 +2873,98 @@ mod tests {
                do_encoding_open_channel(true, true, true);
        }
 
+       fn do_encoding_open_channelv2(random_bit: bool, shutdown: bool, incl_chan_type: bool, require_confirmed_inputs: bool) {
+               let secp_ctx = Secp256k1::new();
+               let (_, pubkey_1) = get_keys_from!("0101010101010101010101010101010101010101010101010101010101010101", secp_ctx);
+               let (_, pubkey_2) = get_keys_from!("0202020202020202020202020202020202020202020202020202020202020202", secp_ctx);
+               let (_, pubkey_3) = get_keys_from!("0303030303030303030303030303030303030303030303030303030303030303", secp_ctx);
+               let (_, pubkey_4) = get_keys_from!("0404040404040404040404040404040404040404040404040404040404040404", secp_ctx);
+               let (_, pubkey_5) = get_keys_from!("0505050505050505050505050505050505050505050505050505050505050505", secp_ctx);
+               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: BlockHash::from_hex("6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000").unwrap(),
+                       temporary_channel_id: [2; 32],
+                       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();
+               let mut target_value = Vec::new();
+               target_value.append(&mut hex::decode("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f").unwrap());
+               target_value.append(&mut hex::decode("0202020202020202020202020202020202020202020202020202020202020202").unwrap());
+               target_value.append(&mut hex::decode("000c89d4").unwrap());
+               target_value.append(&mut hex::decode("000c89d4").unwrap());
+               target_value.append(&mut hex::decode("1234567890123456").unwrap());
+               target_value.append(&mut hex::decode("3214466870114476").unwrap());
+               target_value.append(&mut hex::decode("7633030896203198").unwrap());
+               target_value.append(&mut hex::decode("00083a840000034d").unwrap());
+               target_value.append(&mut hex::decode("c0bc").unwrap());
+               target_value.append(&mut hex::decode("c0bc").unwrap());
+               target_value.append(&mut hex::decode("12345678").unwrap());
+               target_value.append(&mut hex::decode("031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f").unwrap());
+               target_value.append(&mut hex::decode("024d4b6cd1361032ca9bd2aeb9d900aa4d45d9ead80ac9423374c451a7254d0766").unwrap());
+               target_value.append(&mut hex::decode("02531fe6068134503d2723133227c867ac8fa6c83c537e9a44c3c5bdbdcb1fe337").unwrap());
+               target_value.append(&mut hex::decode("03462779ad4aad39514614751a71085f2f10e1c7a593e4e030efb5b8721ce55b0b").unwrap());
+               target_value.append(&mut hex::decode("0362c0a046dacce86ddd0343c6d3c7c79c2208ba0d9c9cf24a6d046d21d21f90f7").unwrap());
+               target_value.append(&mut hex::decode("03f006a18d5653c4edf5391ff23a61f03ff83d237e880ee61187fa9f379a028e0a").unwrap());
+               target_value.append(&mut hex::decode("02989c0b76cb563971fdc9bef31ec06c3560f3249d6ee9e5d83c57625596e05f6f").unwrap());
+
+               if random_bit {
+                       target_value.append(&mut hex::decode("20").unwrap());
+               } else {
+                       target_value.append(&mut hex::decode("00").unwrap());
+               }
+               if shutdown {
+                       target_value.append(&mut hex::decode("001b").unwrap()); // Type 0 + Length 27
+                       target_value.append(&mut hex::decode("001976a91479b000887626b294a914501a4cd226b58b23598388ac").unwrap());
+               }
+               if incl_chan_type {
+                       target_value.append(&mut hex::decode("0100").unwrap());
+               }
+               if require_confirmed_inputs {
+                       target_value.append(&mut hex::decode("0200").unwrap());
+               }
+               assert_eq!(encoded_value, target_value);
+       }
+
+       #[test]
+       fn encoding_open_channelv2() {
+               do_encoding_open_channelv2(false, false, false, false);
+               do_encoding_open_channelv2(false, false, false, true);
+               do_encoding_open_channelv2(false, false, true, false);
+               do_encoding_open_channelv2(false, false, true, true);
+               do_encoding_open_channelv2(false, true, false, false);
+               do_encoding_open_channelv2(false, true, false, true);
+               do_encoding_open_channelv2(false, true, true, false);
+               do_encoding_open_channelv2(false, true, true, true);
+               do_encoding_open_channelv2(true, false, false, false);
+               do_encoding_open_channelv2(true, false, false, true);
+               do_encoding_open_channelv2(true, false, true, false);
+               do_encoding_open_channelv2(true, false, true, true);
+               do_encoding_open_channelv2(true, true, false, false);
+               do_encoding_open_channelv2(true, true, false, true);
+               do_encoding_open_channelv2(true, true, true, false);
+               do_encoding_open_channelv2(true, true, true, true);
+       }
+
        fn do_encoding_accept_channel(shutdown: bool) {
                let secp_ctx = Secp256k1::new();
                let (_, pubkey_1) = get_keys_from!("0101010101010101010101010101010101010101010101010101010101010101", secp_ctx);
@@ -2533,7 +2988,7 @@ mod tests {
                        delayed_payment_basepoint: pubkey_4,
                        htlc_basepoint: pubkey_5,
                        first_per_commitment_point: pubkey_6,
-                       shutdown_scriptpubkey: if shutdown { OptionalField::Present(Address::p2pkh(&::bitcoin::PublicKey{compressed: true, inner: pubkey_1}, Network::Testnet).script_pubkey()) } else { OptionalField::Absent },
+                       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,
@@ -2552,6 +3007,64 @@ mod tests {
                do_encoding_accept_channel(true);
        }
 
+       fn do_encoding_accept_channelv2(shutdown: bool) {
+               let secp_ctx = Secp256k1::new();
+               let (_, pubkey_1) = get_keys_from!("0101010101010101010101010101010101010101010101010101010101010101", secp_ctx);
+               let (_, pubkey_2) = get_keys_from!("0202020202020202020202020202020202020202020202020202020202020202", secp_ctx);
+               let (_, pubkey_3) = get_keys_from!("0303030303030303030303030303030303030303030303030303030303030303", secp_ctx);
+               let (_, pubkey_4) = get_keys_from!("0404040404040404040404040404040404040404040404040404040404040404", secp_ctx);
+               let (_, pubkey_5) = get_keys_from!("0505050505050505050505050505050505050505050505050505050505050505", secp_ctx);
+               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: [2; 32],
+                       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();
+               let mut target_value = hex::decode("0202020202020202020202020202020202020202020202020202020202020202").unwrap(); // temporary_channel_id
+               target_value.append(&mut hex::decode("1234567890123456").unwrap()); // funding_satoshis
+               target_value.append(&mut hex::decode("1234567890123456").unwrap()); // dust_limit_satoshis
+               target_value.append(&mut hex::decode("2334032891223698").unwrap()); // max_htlc_value_in_flight_msat
+               target_value.append(&mut hex::decode("00083a840000034d").unwrap()); // htlc_minimum_msat
+               target_value.append(&mut hex::decode("000c89d4").unwrap()); //  minimum_depth
+               target_value.append(&mut hex::decode("c0bc").unwrap()); // to_self_delay
+               target_value.append(&mut hex::decode("c0bc").unwrap()); // max_accepted_htlcs
+               target_value.append(&mut hex::decode("031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f").unwrap()); // funding_pubkey
+               target_value.append(&mut hex::decode("024d4b6cd1361032ca9bd2aeb9d900aa4d45d9ead80ac9423374c451a7254d0766").unwrap()); // revocation_basepoint
+               target_value.append(&mut hex::decode("02531fe6068134503d2723133227c867ac8fa6c83c537e9a44c3c5bdbdcb1fe337").unwrap()); // payment_basepoint
+               target_value.append(&mut hex::decode("03462779ad4aad39514614751a71085f2f10e1c7a593e4e030efb5b8721ce55b0b").unwrap()); // delayed_payment_basepoint
+               target_value.append(&mut hex::decode("0362c0a046dacce86ddd0343c6d3c7c79c2208ba0d9c9cf24a6d046d21d21f90f7").unwrap()); // htlc_basepoint
+               target_value.append(&mut hex::decode("03f006a18d5653c4edf5391ff23a61f03ff83d237e880ee61187fa9f379a028e0a").unwrap()); // first_per_commitment_point
+               target_value.append(&mut hex::decode("02989c0b76cb563971fdc9bef31ec06c3560f3249d6ee9e5d83c57625596e05f6f").unwrap()); // second_per_commitment_point
+               if shutdown {
+                       target_value.append(&mut hex::decode("001b").unwrap()); // Type 0 + Length 27
+                       target_value.append(&mut hex::decode("001976a91479b000887626b294a914501a4cd226b58b23598388ac").unwrap());
+               }
+               assert_eq!(encoded_value, target_value);
+       }
+
+       #[test]
+       fn encoding_accept_channelv2() {
+               do_encoding_accept_channelv2(false);
+               do_encoding_accept_channelv2(true);
+       }
+
        #[test]
        fn encoding_funding_created() {
                let secp_ctx = Secp256k1::new();
@@ -2602,6 +3115,180 @@ mod tests {
                assert_eq!(encoded_value, target_value);
        }
 
+       #[test]
+       fn encoding_tx_add_input() {
+               let tx_add_input = msgs::TxAddInput {
+                       channel_id: [2; 32],
+                       serial_id: 4886718345,
+                       prevtx: TransactionU16LenLimited::new(Transaction {
+                               version: 2,
+                               lock_time: PackedLockTime(0),
+                               input: vec![TxIn {
+                                       previous_output: OutPoint { txid: Txid::from_hex("305bab643ee297b8b6b76b320792c8223d55082122cb606bf89382146ced9c77").unwrap(), index: 2 }.into_bitcoin_outpoint(),
+                                       script_sig: Script::new(),
+                                       sequence: Sequence(0xfffffffd),
+                                       witness: Witness::from_vec(vec![
+                                               hex::decode("304402206af85b7dd67450ad12c979302fac49dfacbc6a8620f49c5da2b5721cf9565ca502207002b32fed9ce1bf095f57aeb10c36928ac60b12e723d97d2964a54640ceefa701").unwrap(),
+                                               hex::decode("0301ab7dc16488303549bfcdd80f6ae5ee4c20bf97ab5410bbd6b1bfa85dcd6944").unwrap()]),
+                               }],
+                               output: vec![
+                                       TxOut {
+                                               value: 12704566,
+                                               script_pubkey: Address::from_str("bc1qzlffunw52jav8vwdu5x3jfk6sr8u22rmq3xzw2").unwrap().script_pubkey(),
+                                       },
+                                       TxOut {
+                                               value: 245148,
+                                               script_pubkey: Address::from_str("bc1qxmk834g5marzm227dgqvynd23y2nvt2ztwcw2z").unwrap().script_pubkey(),
+                                       },
+                               ],
+                       }).unwrap(),
+                       prevtx_out: 305419896,
+                       sequence: 305419896,
+               };
+               let encoded_value = tx_add_input.encode();
+               let target_value = hex::decode("0202020202020202020202020202020202020202020202020202020202020202000000012345678900de02000000000101779ced6c148293f86b60cb222108553d22c89207326bb7b6b897e23e64ab5b300200000000fdffffff0236dbc1000000000016001417d29e4dd454bac3b1cde50d1926da80cfc5287b9cbd03000000000016001436ec78d514df462da95e6a00c24daa8915362d420247304402206af85b7dd67450ad12c979302fac49dfacbc6a8620f49c5da2b5721cf9565ca502207002b32fed9ce1bf095f57aeb10c36928ac60b12e723d97d2964a54640ceefa701210301ab7dc16488303549bfcdd80f6ae5ee4c20bf97ab5410bbd6b1bfa85dcd6944000000001234567812345678").unwrap();
+               assert_eq!(encoded_value, target_value);
+       }
+
+       #[test]
+       fn encoding_tx_add_output() {
+               let tx_add_output = msgs::TxAddOutput {
+                       channel_id: [2; 32],
+                       serial_id: 4886718345,
+                       sats: 4886718345,
+                       script: Address::from_str("bc1qxmk834g5marzm227dgqvynd23y2nvt2ztwcw2z").unwrap().script_pubkey(),
+               };
+               let encoded_value = tx_add_output.encode();
+               let target_value = hex::decode("0202020202020202020202020202020202020202020202020202020202020202000000012345678900000001234567890016001436ec78d514df462da95e6a00c24daa8915362d42").unwrap();
+               assert_eq!(encoded_value, target_value);
+       }
+
+       #[test]
+       fn encoding_tx_remove_input() {
+               let tx_remove_input = msgs::TxRemoveInput {
+                       channel_id: [2; 32],
+                       serial_id: 4886718345,
+               };
+               let encoded_value = tx_remove_input.encode();
+               let target_value = hex::decode("02020202020202020202020202020202020202020202020202020202020202020000000123456789").unwrap();
+               assert_eq!(encoded_value, target_value);
+       }
+
+       #[test]
+       fn encoding_tx_remove_output() {
+               let tx_remove_output = msgs::TxRemoveOutput {
+                       channel_id: [2; 32],
+                       serial_id: 4886718345,
+               };
+               let encoded_value = tx_remove_output.encode();
+               let target_value = hex::decode("02020202020202020202020202020202020202020202020202020202020202020000000123456789").unwrap();
+               assert_eq!(encoded_value, target_value);
+       }
+
+       #[test]
+       fn encoding_tx_complete() {
+               let tx_complete = msgs::TxComplete {
+                       channel_id: [2; 32],
+               };
+               let encoded_value = tx_complete.encode();
+               let target_value = hex::decode("0202020202020202020202020202020202020202020202020202020202020202").unwrap();
+               assert_eq!(encoded_value, target_value);
+       }
+
+       #[test]
+       fn encoding_tx_signatures() {
+               let tx_signatures = msgs::TxSignatures {
+                       channel_id: [2; 32],
+                       tx_hash: Txid::from_hex("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap(),
+                       witnesses: vec![
+                               Witness::from_vec(vec![
+                                       hex::decode("304402206af85b7dd67450ad12c979302fac49dfacbc6a8620f49c5da2b5721cf9565ca502207002b32fed9ce1bf095f57aeb10c36928ac60b12e723d97d2964a54640ceefa701").unwrap(),
+                                       hex::decode("0301ab7dc16488303549bfcdd80f6ae5ee4c20bf97ab5410bbd6b1bfa85dcd6944").unwrap()]),
+                               Witness::from_vec(vec![
+                                       hex::decode("3045022100ee00dbf4a862463e837d7c08509de814d620e4d9830fa84818713e0fa358f145022021c3c7060c4d53fe84fd165d60208451108a778c13b92ca4c6bad439236126cc01").unwrap(),
+                                       hex::decode("028fbbf0b16f5ba5bcb5dd37cd4047ce6f726a21c06682f9ec2f52b057de1dbdb5").unwrap()]),
+                       ],
+               };
+               let encoded_value = tx_signatures.encode();
+               let mut target_value = hex::decode("0202020202020202020202020202020202020202020202020202020202020202").unwrap(); // channel_id
+               target_value.append(&mut hex::decode("6e96fe9f8b0ddcd729ba03cfafa5a27b050b39d354dd980814268dfa9a44d4c2").unwrap()); // tx_hash (sha256) (big endian byte order)
+               target_value.append(&mut hex::decode("0002").unwrap()); // num_witnesses (u16)
+               // Witness 1
+               target_value.append(&mut hex::decode("006b").unwrap()); // len of witness_data
+               target_value.append(&mut hex::decode("02").unwrap()); // num_witness_elements (VarInt)
+               target_value.append(&mut hex::decode("47").unwrap()); // len of witness element data (VarInt)
+               target_value.append(&mut hex::decode("304402206af85b7dd67450ad12c979302fac49dfacbc6a8620f49c5da2b5721cf9565ca502207002b32fed9ce1bf095f57aeb10c36928ac60b12e723d97d2964a54640ceefa701").unwrap());
+               target_value.append(&mut hex::decode("21").unwrap()); // len of witness element data (VarInt)
+               target_value.append(&mut hex::decode("0301ab7dc16488303549bfcdd80f6ae5ee4c20bf97ab5410bbd6b1bfa85dcd6944").unwrap());
+               // Witness 2
+               target_value.append(&mut hex::decode("006c").unwrap()); // len of witness_data
+               target_value.append(&mut hex::decode("02").unwrap()); // num_witness_elements (VarInt)
+               target_value.append(&mut hex::decode("48").unwrap()); // len of witness element data (VarInt)
+               target_value.append(&mut hex::decode("3045022100ee00dbf4a862463e837d7c08509de814d620e4d9830fa84818713e0fa358f145022021c3c7060c4d53fe84fd165d60208451108a778c13b92ca4c6bad439236126cc01").unwrap());
+               target_value.append(&mut hex::decode("21").unwrap()); // len of witness element data (VarInt)
+               target_value.append(&mut hex::decode("028fbbf0b16f5ba5bcb5dd37cd4047ce6f726a21c06682f9ec2f52b057de1dbdb5").unwrap());
+               assert_eq!(encoded_value, target_value);
+       }
+
+       fn do_encoding_tx_init_rbf(funding_value_with_hex_target: Option<(i64, &str)>) {
+               let tx_init_rbf = msgs::TxInitRbf {
+                       channel_id: [2; 32],
+                       locktime: 305419896,
+                       feerate_sat_per_1000_weight: 20190119,
+                       funding_output_contribution: if let Some((value, _)) = funding_value_with_hex_target { Some(value) } else { None },
+               };
+               let encoded_value = tx_init_rbf.encode();
+               let mut target_value = hex::decode("0202020202020202020202020202020202020202020202020202020202020202").unwrap(); // channel_id
+               target_value.append(&mut hex::decode("12345678").unwrap()); // locktime
+               target_value.append(&mut hex::decode("013413a7").unwrap()); // feerate_sat_per_1000_weight
+               if let Some((_, target)) = funding_value_with_hex_target {
+                       target_value.push(0x00); // Type
+                       target_value.push(target.len() as u8 / 2); // Length
+                       target_value.append(&mut hex::decode(target).unwrap()); // Value (i64)
+               }
+               assert_eq!(encoded_value, target_value);
+       }
+
+       #[test]
+       fn encoding_tx_init_rbf() {
+               do_encoding_tx_init_rbf(Some((1311768467284833366, "1234567890123456")));
+               do_encoding_tx_init_rbf(Some((13117684672, "000000030DDFFBC0")));
+               do_encoding_tx_init_rbf(None);
+       }
+
+       fn do_encoding_tx_ack_rbf(funding_value_with_hex_target: Option<(i64, &str)>) {
+               let tx_ack_rbf = msgs::TxAckRbf {
+                       channel_id: [2; 32],
+                       funding_output_contribution: if let Some((value, _)) = funding_value_with_hex_target { Some(value) } else { None },
+               };
+               let encoded_value = tx_ack_rbf.encode();
+               let mut target_value = hex::decode("0202020202020202020202020202020202020202020202020202020202020202").unwrap();
+               if let Some((_, target)) = funding_value_with_hex_target {
+                       target_value.push(0x00); // Type
+                       target_value.push(target.len() as u8 / 2); // Length
+                       target_value.append(&mut hex::decode(target).unwrap()); // Value (i64)
+               }
+               assert_eq!(encoded_value, target_value);
+       }
+
+       #[test]
+       fn encoding_tx_ack_rbf() {
+               do_encoding_tx_ack_rbf(Some((1311768467284833366, "1234567890123456")));
+               do_encoding_tx_ack_rbf(Some((13117684672, "000000030DDFFBC0")));
+               do_encoding_tx_ack_rbf(None);
+       }
+
+       #[test]
+       fn encoding_tx_abort() {
+               let tx_abort = msgs::TxAbort {
+                       channel_id: [2; 32],
+                       data: hex::decode("54686520717569636B2062726F776E20666F78206A756D7073206F76657220746865206C617A7920646F672E").unwrap(),
+               };
+               let encoded_value = tx_abort.encode();
+               let target_value = hex::decode("0202020202020202020202020202020202020202020202020202020202020202002C54686520717569636B2062726F776E20666F78206A756D7073206F76657220746865206C617A7920646F672E").unwrap();
+               assert_eq!(encoded_value, target_value);
+       }
+
        fn do_encoding_shutdown(script_type: u8) {
                let secp_ctx = Secp256k1::new();
                let (_, pubkey_1) = get_keys_from!("0101010101010101010101010101010101010101010101010101010101010101", secp_ctx);
@@ -2684,7 +3371,8 @@ mod tests {
                        amount_msat: 3608586615801332854,
                        payment_hash: PaymentHash([1; 32]),
                        cltv_expiry: 821716,
-                       onion_routing_packet
+                       onion_routing_packet,
+                       skimmed_fee_msat: None,
                };
                let encoded_value = update_add_htlc.encode();
                let target_value = hex::decode("020202020202020202020202020202020202020202020202020202020202020200083a840000034d32144668701144760101010101010101010101010101010101010101010101010101010101010101000c89d4ff031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010202020202020202020202020202020202020202020202020202020202020202").unwrap();
@@ -2793,27 +3481,36 @@ mod tests {
 
        #[test]
        fn encoding_init() {
+               let mainnet_hash = ChainHash::from_hex("6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000").unwrap();
                assert_eq!(msgs::Init {
                        features: InitFeatures::from_le_bytes(vec![0xFF, 0xFF, 0xFF]),
+                       networks: Some(vec![mainnet_hash]),
                        remote_network_address: None,
-               }.encode(), hex::decode("00023fff0003ffffff").unwrap());
+               }.encode(), hex::decode("00023fff0003ffffff01206fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000").unwrap());
                assert_eq!(msgs::Init {
                        features: InitFeatures::from_le_bytes(vec![0xFF]),
+                       networks: None,
                        remote_network_address: None,
                }.encode(), hex::decode("0001ff0001ff").unwrap());
                assert_eq!(msgs::Init {
                        features: InitFeatures::from_le_bytes(vec![]),
+                       networks: Some(vec![mainnet_hash]),
                        remote_network_address: None,
-               }.encode(), hex::decode("00000000").unwrap());
-
+               }.encode(), hex::decode("0000000001206fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000").unwrap());
+               assert_eq!(msgs::Init {
+                       features: InitFeatures::from_le_bytes(vec![]),
+                       networks: Some(vec![ChainHash::from(&[1; 32][..]), ChainHash::from(&[2; 32][..])]),
+                       remote_network_address: None,
+               }.encode(), hex::decode("00000000014001010101010101010101010101010101010101010101010101010101010101010202020202020202020202020202020202020202020202020202020202020202").unwrap());
                let init_msg = msgs::Init { features: InitFeatures::from_le_bytes(vec![]),
+                       networks: Some(vec![mainnet_hash]),
                        remote_network_address: Some(msgs::NetAddress::IPv4 {
                                addr: [127, 0, 0, 1],
                                port: 1000,
                        }),
                };
                let encoded_value = init_msg.encode();
-               let target_value = hex::decode("000000000307017f00000103e8").unwrap();
+               let target_value = hex::decode("0000000001206fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d61900000000000307017f00000103e8").unwrap();
                assert_eq!(encoded_value, target_value);
                assert_eq!(msgs::Init::read(&mut Cursor::new(&target_value)).unwrap(), init_msg);
        }
@@ -2863,75 +3560,144 @@ mod tests {
 
        #[test]
        fn encoding_nonfinal_onion_hop_data() {
-               let mut msg = msgs::OnionHopData {
-                       format: OnionHopDataFormat::NonFinalNode {
-                               short_channel_id: 0xdeadbeef1bad1dea,
-                       },
+               let outbound_msg = msgs::OutboundOnionPayload::Forward {
+                       short_channel_id: 0xdeadbeef1bad1dea,
                        amt_to_forward: 0x0badf00d01020304,
                        outgoing_cltv_value: 0xffffffff,
                };
-               let encoded_value = msg.encode();
+               let encoded_value = outbound_msg.encode();
                let target_value = hex::decode("1a02080badf00d010203040404ffffffff0608deadbeef1bad1dea").unwrap();
                assert_eq!(encoded_value, target_value);
-               msg = Readable::read(&mut Cursor::new(&target_value[..])).unwrap();
-               if let OnionHopDataFormat::NonFinalNode { short_channel_id } = msg.format {
+
+               let inbound_msg = Readable::read(&mut Cursor::new(&target_value[..])).unwrap();
+               if let msgs::InboundOnionPayload::Forward { short_channel_id, amt_to_forward, outgoing_cltv_value } = inbound_msg {
                        assert_eq!(short_channel_id, 0xdeadbeef1bad1dea);
+                       assert_eq!(amt_to_forward, 0x0badf00d01020304);
+                       assert_eq!(outgoing_cltv_value, 0xffffffff);
                } else { panic!(); }
-               assert_eq!(msg.amt_to_forward, 0x0badf00d01020304);
-               assert_eq!(msg.outgoing_cltv_value, 0xffffffff);
        }
 
        #[test]
        fn encoding_final_onion_hop_data() {
-               let mut msg = msgs::OnionHopData {
-                       format: OnionHopDataFormat::FinalNode {
-                               payment_data: None,
-                               payment_metadata: None,
-                               keysend_preimage: None,
-                       },
-                       amt_to_forward: 0x0badf00d01020304,
+               let outbound_msg = msgs::OutboundOnionPayload::Receive {
+                       payment_data: None,
+                       payment_metadata: None,
+                       keysend_preimage: None,
+                       amt_msat: 0x0badf00d01020304,
                        outgoing_cltv_value: 0xffffffff,
+                       custom_tlvs: vec![],
                };
-               let encoded_value = msg.encode();
+               let encoded_value = outbound_msg.encode();
                let target_value = hex::decode("1002080badf00d010203040404ffffffff").unwrap();
                assert_eq!(encoded_value, target_value);
-               msg = Readable::read(&mut Cursor::new(&target_value[..])).unwrap();
-               if let OnionHopDataFormat::FinalNode { payment_data: None, .. } = msg.format { } else { panic!(); }
-               assert_eq!(msg.amt_to_forward, 0x0badf00d01020304);
-               assert_eq!(msg.outgoing_cltv_value, 0xffffffff);
+
+               let inbound_msg = Readable::read(&mut Cursor::new(&target_value[..])).unwrap();
+               if let msgs::InboundOnionPayload::Receive { payment_data: None, amt_msat, outgoing_cltv_value, .. } = inbound_msg {
+                       assert_eq!(amt_msat, 0x0badf00d01020304);
+                       assert_eq!(outgoing_cltv_value, 0xffffffff);
+               } else { panic!(); }
        }
 
        #[test]
        fn encoding_final_onion_hop_data_with_secret() {
                let expected_payment_secret = PaymentSecret([0x42u8; 32]);
-               let mut msg = msgs::OnionHopData {
-                       format: OnionHopDataFormat::FinalNode {
-                               payment_data: Some(FinalOnionHopData {
-                                       payment_secret: expected_payment_secret,
-                                       total_msat: 0x1badca1f
-                               }),
-                               payment_metadata: None,
-                               keysend_preimage: None,
-                       },
-                       amt_to_forward: 0x0badf00d01020304,
+               let outbound_msg = msgs::OutboundOnionPayload::Receive {
+                       payment_data: Some(FinalOnionHopData {
+                               payment_secret: expected_payment_secret,
+                               total_msat: 0x1badca1f
+                       }),
+                       payment_metadata: None,
+                       keysend_preimage: None,
+                       amt_msat: 0x0badf00d01020304,
                        outgoing_cltv_value: 0xffffffff,
+                       custom_tlvs: vec![],
                };
-               let encoded_value = msg.encode();
+               let encoded_value = outbound_msg.encode();
                let target_value = hex::decode("3602080badf00d010203040404ffffffff082442424242424242424242424242424242424242424242424242424242424242421badca1f").unwrap();
                assert_eq!(encoded_value, target_value);
-               msg = Readable::read(&mut Cursor::new(&target_value[..])).unwrap();
-               if let OnionHopDataFormat::FinalNode {
+
+               let inbound_msg = Readable::read(&mut Cursor::new(&target_value[..])).unwrap();
+               if let msgs::InboundOnionPayload::Receive {
                        payment_data: Some(FinalOnionHopData {
                                payment_secret,
                                total_msat: 0x1badca1f
                        }),
+                       amt_msat, outgoing_cltv_value,
                        payment_metadata: None,
                        keysend_preimage: None,
-               } = msg.format {
+                       custom_tlvs,
+               } = inbound_msg  {
                        assert_eq!(payment_secret, expected_payment_secret);
+                       assert_eq!(amt_msat, 0x0badf00d01020304);
+                       assert_eq!(outgoing_cltv_value, 0xffffffff);
+                       assert_eq!(custom_tlvs, vec![]);
+               } else { panic!(); }
+       }
+
+       #[test]
+       fn encoding_final_onion_hop_data_with_bad_custom_tlvs() {
+               // If custom TLVs have type number within the range reserved for protocol, treat them as if
+               // they're unknown
+               let bad_type_range_tlvs = vec![
+                       ((1 << 16) - 4, vec![42]),
+                       ((1 << 16) - 2, vec![42; 32]),
+               ];
+               let mut msg = msgs::OutboundOnionPayload::Receive {
+                       payment_data: None,
+                       payment_metadata: None,
+                       keysend_preimage: None,
+                       custom_tlvs: bad_type_range_tlvs,
+                       amt_msat: 0x0badf00d01020304,
+                       outgoing_cltv_value: 0xffffffff,
+               };
+               let encoded_value = msg.encode();
+               assert!(msgs::InboundOnionPayload::read(&mut Cursor::new(&encoded_value[..])).is_err());
+               let good_type_range_tlvs = vec![
+                       ((1 << 16) - 3, vec![42]),
+                       ((1 << 16) - 1, vec![42; 32]),
+               ];
+               if let msgs::OutboundOnionPayload::Receive { ref mut custom_tlvs, .. } = msg {
+                       *custom_tlvs = good_type_range_tlvs.clone();
+               }
+               let encoded_value = msg.encode();
+               let inbound_msg = Readable::read(&mut Cursor::new(&encoded_value[..])).unwrap();
+               match inbound_msg {
+                       msgs::InboundOnionPayload::Receive { custom_tlvs, .. } => assert!(custom_tlvs.is_empty()),
+                       _ => panic!(),
+               }
+       }
+
+       #[test]
+       fn encoding_final_onion_hop_data_with_custom_tlvs() {
+               let expected_custom_tlvs = vec![
+                       (5482373483, vec![0x12, 0x34]),
+                       (5482373487, vec![0x42u8; 8]),
+               ];
+               let msg = msgs::OutboundOnionPayload::Receive {
+                       payment_data: None,
+                       payment_metadata: None,
+                       keysend_preimage: None,
+                       custom_tlvs: expected_custom_tlvs.clone(),
+                       amt_msat: 0x0badf00d01020304,
+                       outgoing_cltv_value: 0xffffffff,
+               };
+               let encoded_value = msg.encode();
+               let target_value = hex::decode("2e02080badf00d010203040404ffffffffff0000000146c6616b021234ff0000000146c6616f084242424242424242").unwrap();
+               assert_eq!(encoded_value, target_value);
+               let inbound_msg: msgs::InboundOnionPayload = Readable::read(&mut Cursor::new(&target_value[..])).unwrap();
+               if let msgs::InboundOnionPayload::Receive {
+                       payment_data: None,
+                       payment_metadata: None,
+                       keysend_preimage: None,
+                       custom_tlvs,
+                       amt_msat,
+                       outgoing_cltv_value,
+                       ..
+               } = inbound_msg {
+                       assert_eq!(custom_tlvs, expected_custom_tlvs);
+                       assert_eq!(amt_msat, 0x0badf00d01020304);
+                       assert_eq!(outgoing_cltv_value, 0xffffffff);
                } else { panic!(); }
-               assert_eq!(msg.amt_to_forward, 0x0badf00d01020304);
-               assert_eq!(msg.outgoing_cltv_value, 0xffffffff);
        }
 
        #[test]
@@ -3081,25 +3847,23 @@ mod tests {
                // payload length to be encoded over multiple bytes rather than a single u8.
                let big_payload = encode_big_payload().unwrap();
                let mut rd = Cursor::new(&big_payload[..]);
-               <msgs::OnionHopData as Readable>::read(&mut rd).unwrap();
+               <msgs::InboundOnionPayload as Readable>::read(&mut rd).unwrap();
        }
        // see above test, needs to be a separate method for use of the serialization macros.
        fn encode_big_payload() -> Result<Vec<u8>, io::Error> {
                use crate::util::ser::HighZeroBytesDroppedBigSize;
-               let payload = msgs::OnionHopData {
-                       format: OnionHopDataFormat::NonFinalNode {
-                               short_channel_id: 0xdeadbeef1bad1dea,
-                       },
+               let payload = msgs::OutboundOnionPayload::Forward {
+                       short_channel_id: 0xdeadbeef1bad1dea,
                        amt_to_forward: 1000,
                        outgoing_cltv_value: 0xffffffff,
                };
                let mut encoded_payload = Vec::new();
                let test_bytes = vec![42u8; 1000];
-               if let OnionHopDataFormat::NonFinalNode { short_channel_id } = payload.format {
+               if let msgs::OutboundOnionPayload::Forward { short_channel_id, amt_to_forward, outgoing_cltv_value } = payload {
                        _encode_varint_length_prefixed_tlv!(&mut encoded_payload, {
-                               (1, test_bytes, vec_type),
-                               (2, HighZeroBytesDroppedBigSize(payload.amt_to_forward), required),
-                               (4, HighZeroBytesDroppedBigSize(payload.outgoing_cltv_value), required),
+                               (1, test_bytes, required_vec),
+                               (2, HighZeroBytesDroppedBigSize(amt_to_forward), required),
+                               (4, HighZeroBytesDroppedBigSize(outgoing_cltv_value), required),
                                (6, short_channel_id, required)
                        });
                }