Check `max_total_routing_fee` is reduced in `mpp_retry` test
[rust-lightning] / lightning / src / ln / msgs.rs
index 8b5a6ac6fd24e32f4ba2dcc25c3715eb86531b30..c617d97fe52705c8673c6f4a68f331bb8ed644a6 100644 (file)
 //! For a normal node you probably don't need to use anything here, however, if you wish to split a
 //! node into an internet-facing route/message socket handling daemon and a separate daemon (or
 //! server entirely) which handles only channel-related messages you may wish to implement
-//! ChannelMessageHandler yourself and use it to re-serialize messages and pass them across
+//! [`ChannelMessageHandler`] yourself and use it to re-serialize messages and pass them across
 //! daemons/servers.
 //!
 //! Note that if you go with such an architecture (instead of passing raw socket events to a
 //! non-internet-facing system) you trust the frontend internet-facing system to not lie about the
-//! source node_id of the message, however this does allow you to significantly reduce bandwidth
+//! source `node_id` of the message, however this does allow you to significantly reduce bandwidth
 //! between the systems as routing messages can represent a significant chunk of bandwidth usage
 //! (especially for non-channel-publicly-announcing nodes). As an alternate design which avoids
 //! this issue, if you have sufficient bidirectional bandwidth between your systems, you may send
 //! 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};
 
+use crate::blinded_path::payment::ReceiveTlvs;
+use crate::ln::{ChannelId, PaymentPreimage, PaymentHash, PaymentSecret};
 use crate::ln::features::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, NodeFeatures};
 use crate::ln::onion_utils;
 use crate::onion_message;
+use crate::sign::{NodeSigner, Recipient};
 
 use crate::prelude::*;
+use core::convert::TryFrom;
 use core::fmt;
 use core::fmt::Debug;
-use crate::io::{self, Read};
+use core::ops::Deref;
+use core::str::FromStr;
+use crate::io::{self, Cursor, Read};
 use crate::io_extras::read_to_end;
 
-use crate::util::events::{MessageSendEventsProvider, OnionMessageProvider};
+use crate::events::{MessageSendEventsProvider, OnionMessageProvider};
+use crate::util::chacha20poly1305rfc::ChaChaPolyReadAdapter;
 use crate::util::logger;
-use crate::util::ser::{BigSize, LengthReadable, Readable, ReadableArgs, Writeable, Writer, FixedLengthReader, HighZeroBytesDroppedBigSize, Hostname};
+use crate::util::ser::{LengthReadable, LengthReadableArgs, Readable, ReadableArgs, Writeable, Writer, WithoutLength, FixedLengthReader, HighZeroBytesDroppedBigSize, Hostname, TransactionU16LenLimited, BigSize};
+use crate::util::base32;
 
-use crate::ln::{PaymentPreimage, PaymentHash, PaymentSecret};
+use crate::routing::gossip::{NodeAlias, NodeId};
 
 /// 21 million * 10^8 * 1000
 pub(crate) const MAX_VALUE_MSAT: u64 = 21_000_000_0000_0000_000;
 
+#[cfg(taproot)]
+/// A partial signature that also contains the Musig2 nonce its signer used
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct PartialSignatureWithNonce(pub musig2::types::PartialSignature, pub musig2::types::PublicNonce);
+
 /// An error in decoding a message or struct.
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub enum DecodeError {
        /// A version byte specified something we don't know how to handle.
-       /// Includes unknown realm byte in an OnionHopData packet
+       ///
+       /// Includes unknown realm byte in an onion hop data packet.
        UnknownVersion,
-       /// Unknown feature mandating we fail to parse message (eg TLV with an even, unknown type)
+       /// Unknown feature mandating we fail to parse message (e.g., TLV with an even, unknown type)
        UnknownRequiredFeature,
-       /// Value was invalid, eg a byte which was supposed to be a bool was something other than a 0
+       /// Value was invalid.
+       ///
+       /// For example, a byte which was supposed to be a bool was something other than a 0
        /// or 1, a public key/private key/signature was invalid, text wasn't UTF-8, TLV was
-       /// syntactically incorrect, etc
+       /// syntactically incorrect, etc.
        InvalidValue,
-       /// Buffer too short
+       /// The buffer to be read was too short.
        ShortRead,
-       /// A length descriptor in the packet didn't describe the later data correctly
+       /// A length descriptor in the packet didn't describe the later data correctly.
        BadLengthDescriptor,
-       /// Error from std::io
+       /// Error from [`std::io`].
        Io(io::ErrorKind),
        /// The message included zlib-compressed values, which we don't support.
        UnsupportedCompression,
 }
 
-/// An init message to be sent or received from a peer
+/// An [`init`] message to be sent to or received from a peer.
+///
+/// [`init`]: https://github.com/lightning/bolts/blob/master/01-messaging.md#the-init-message
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct Init {
-       /// The relevant features which the sender supports
+       /// The relevant features which the sender supports.
        pub features: InitFeatures,
-       /// The receipient's network address. This adds the option to report a remote IP address
-       /// back to a connecting peer using the init message. A node can decide to use that information
-       /// to discover a potential update to its public IPv4 address (NAT) and use
-       /// that for a node_announcement update message containing the new address.
-       pub remote_network_address: Option<NetAddress>,
+       /// 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
+       /// message. A node can decide to use that information to discover a potential update to its
+       /// public IPv4 address (NAT) and use that for a [`NodeAnnouncement`] update message containing
+       /// the new address.
+       pub remote_network_address: Option<SocketAddress>,
 }
 
-/// An error message to be sent or received from a peer
+/// An [`error`] message to be sent to or received from a peer.
+///
+/// [`error`]: https://github.com/lightning/bolts/blob/master/01-messaging.md#the-error-and-warning-messages
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct ErrorMessage {
        /// The channel ID involved in the error.
        ///
        /// All-0s indicates a general error unrelated to a specific channel, after which all channels
        /// with the sending peer should be closed.
-       pub channel_id: [u8; 32],
+       pub channel_id: ChannelId,
        /// A possibly human-readable error description.
-       /// The string should be sanitized before it is used (e.g. emitted to logs or printed to
-       /// stdout). Otherwise, a well crafted error message may trigger a security vulnerability in
+       ///
+       /// The string should be sanitized before it is used (e.g., emitted to logs or printed to
+       /// `stdout`). Otherwise, a well crafted error message may trigger a security vulnerability in
        /// the terminal emulator or the logging subsystem.
        pub data: String,
 }
 
-/// A warning message to be sent or received from a peer
+/// A [`warning`] message to be sent to or received from a peer.
+///
+/// [`warning`]: https://github.com/lightning/bolts/blob/master/01-messaging.md#the-error-and-warning-messages
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct WarningMessage {
        /// The channel ID involved in the warning.
        ///
        /// All-0s indicates a warning unrelated to a specific channel.
-       pub channel_id: [u8; 32],
+       pub channel_id: ChannelId,
        /// A possibly human-readable warning description.
+       ///
        /// The string should be sanitized before it is used (e.g. emitted to logs or printed to
        /// stdout). Otherwise, a well crafted error message may trigger a security vulnerability in
        /// the terminal emulator or the logging subsystem.
        pub data: String,
 }
 
-/// A ping message to be sent or received from a peer
+/// A [`ping`] message to be sent to or received from a peer.
+///
+/// [`ping`]: https://github.com/lightning/bolts/blob/master/01-messaging.md#the-ping-and-pong-messages
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct Ping {
-       /// The desired response length
+       /// The desired response length.
        pub ponglen: u16,
        /// The ping packet size.
+       ///
        /// This field is not sent on the wire. byteslen zeros are sent.
        pub byteslen: u16,
 }
 
-/// A pong message to be sent or received from a peer
+/// A [`pong`] message to be sent to or received from a peer.
+///
+/// [`pong`]: https://github.com/lightning/bolts/blob/master/01-messaging.md#the-ping-and-pong-messages
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct Pong {
        /// The pong packet size.
+       ///
        /// This field is not sent on the wire. byteslen zeros are sent.
        pub byteslen: u16,
 }
 
-/// An open_channel message to be sent or received from a peer
+/// 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 {
        /// The genesis hash of the blockchain where the channel is to be opened
        pub chain_hash: BlockHash,
        /// A temporary channel ID, until the funding outpoint is announced
-       pub temporary_channel_id: [u8; 32],
+       pub temporary_channel_id: ChannelId,
        /// The channel value
        pub funding_satoshis: u64,
        /// The amount to push to the counterparty as part of the open, in milli-satoshi
@@ -149,9 +190,11 @@ pub struct OpenChannel {
        pub channel_reserve_satoshis: u64,
        /// The minimum HTLC size incoming to sender, in milli-satoshi
        pub htlc_minimum_msat: u64,
-       /// The feerate per 1000-weight of sender generated transactions, until updated by update_fee
+       /// The feerate per 1000-weight of sender generated transactions, until updated by
+       /// [`UpdateFee`]
        pub feerate_per_kw: u32,
-       /// The number of blocks which the counterparty will have to wait to claim on-chain funds if they broadcast a commitment transaction
+       /// The number of blocks which the counterparty will have to wait to claim on-chain funds if
+       /// they broadcast a commitment transaction
        pub to_self_delay: u16,
        /// The maximum number of inbound HTLCs towards sender
        pub max_accepted_htlcs: u16,
@@ -167,21 +210,85 @@ pub struct OpenChannel {
        pub htlc_basepoint: PublicKey,
        /// The first to-be-broadcast-by-sender transaction's per commitment point
        pub first_per_commitment_point: PublicKey,
+       /// The channel flags to be used
+       pub channel_flags: u8,
+       /// A request to pre-set the to-sender output's `scriptPubkey` for when we collaboratively close
+       pub shutdown_scriptpubkey: Option<Script>,
+       /// The channel type that this channel will represent
+       ///
+       /// If this is `None`, we derive the channel type from the intersection of our
+       /// feature bits with our counterparty's feature bits from the [`Init`] message.
+       pub channel_type: Option<ChannelTypeFeatures>,
+}
+
+/// An open_channel2 message to be sent by or received from the channel initiator.
+///
+/// Used in V2 channel establishment
+///
+// TODO(dual_funding): Add spec link for `open_channel2`.
+#[derive(Clone, Debug, 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: ChannelId,
+       /// The feerate for the funding transaction set by the channel initiator
+       pub funding_feerate_sat_per_1000_weight: u32,
+       /// The feerate for the commitment transaction set by the channel initiator
+       pub commitment_feerate_sat_per_1000_weight: u32,
+       /// Part of the channel value contributed by the channel initiator
+       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-sender output's scriptPubkey for when we collaboratively close
-       pub shutdown_scriptpubkey: OptionalField<Script>,
+       /// 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 or received from a peer
+/// 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 {
        /// A temporary channel ID, until the funding outpoint is announced
-       pub temporary_channel_id: [u8; 32],
+       pub temporary_channel_id: ChannelId,
        /// The threshold below which outputs on transactions broadcast by sender will be omitted
        pub dust_limit_satoshis: u64,
        /// The maximum inbound HTLC value in flight towards sender, in milli-satoshi
@@ -208,61 +315,264 @@ 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
+       /// our feature bits with our counterparty's feature bits from the [`Init`] message.
+       /// This is required to match the equivalent field in [`OpenChannel::channel_type`].
+       pub channel_type: Option<ChannelTypeFeatures>,
+       #[cfg(taproot)]
+       /// Next nonce the channel initiator should use to create a funding output signature against
+       pub next_local_nonce: Option<musig2::types::PublicNonce>,
+}
+
+/// An accept_channel2 message to be sent by or received from the channel accepter.
+///
+/// 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: ChannelId,
+       /// Part of the channel value contributed by the channel acceptor
+       pub funding_satoshis: u64,
+       /// The threshold below which outputs on transactions broadcast by the channel acceptor will be
+       /// omitted
+       pub dust_limit_satoshis: u64,
+       /// The maximum inbound HTLC value in flight towards channel acceptor, in milli-satoshi
+       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 [`OpenChannel::channel_type`].
+       /// 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 or received from a peer
+/// 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 {
        /// A temporary channel ID, until the funding is established
-       pub temporary_channel_id: [u8; 32],
+       pub temporary_channel_id: ChannelId,
        /// The funding transaction ID
        pub funding_txid: Txid,
        /// The specific output index funding this channel
        pub funding_output_index: u16,
        /// The signature of the channel initiator (funder) on the initial commitment transaction
        pub signature: Signature,
+       #[cfg(taproot)]
+       /// The partial signature of the channel initiator (funder)
+       pub partial_signature_with_nonce: Option<PartialSignatureWithNonce>,
+       #[cfg(taproot)]
+       /// Next nonce the channel acceptor should use to finalize the funding output signature
+       pub next_local_nonce: Option<musig2::types::PublicNonce>
 }
 
-/// A funding_signed message to be sent or received from a peer
+/// 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 {
        /// The channel ID
-       pub channel_id: [u8; 32],
+       pub channel_id: ChannelId,
        /// The signature of the channel acceptor (fundee) on the initial commitment transaction
        pub signature: Signature,
+       #[cfg(taproot)]
+       /// The partial signature of the channel acceptor (fundee)
+       pub partial_signature_with_nonce: Option<PartialSignatureWithNonce>,
 }
 
-/// A channel_ready message to be sent or received from a peer
+/// A [`channel_ready`] message to be sent to or received from a peer.
+///
+/// [`channel_ready`]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#the-channel_ready-message
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct ChannelReady {
        /// The channel ID
-       pub channel_id: [u8; 32],
+       pub channel_id: ChannelId,
        /// The per-commitment point of the second commitment transaction
        pub next_per_commitment_point: PublicKey,
-       /// If set, provides a short_channel_id alias for this channel. The sender will accept payments
-       /// to be forwarded over this SCID and forward them to this messages' recipient.
+       /// If set, provides a `short_channel_id` alias for this channel.
+       ///
+       /// The sender will accept payments to be forwarded over this SCID and forward them to this
+       /// messages' recipient.
        pub short_channel_id_alias: Option<u64>,
 }
 
-/// A shutdown message to be sent or received from a peer
+/// 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: ChannelId,
+       /// 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: ChannelId,
+       /// 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: ChannelId,
+       /// 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: ChannelId,
+       /// 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: ChannelId,
+}
+
+/// 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: ChannelId,
+       /// 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: ChannelId,
+       /// 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: ChannelId,
+       /// 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: ChannelId,
+       /// 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
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct Shutdown {
        /// The channel ID
-       pub channel_id: [u8; 32],
+       pub channel_id: ChannelId,
        /// The destination of this peer's funds on closing.
-       /// Must be in one of these forms: p2pkh, p2sh, p2wpkh, p2wsh.
+       ///
+       /// Must be in one of these forms: P2PKH, P2SH, P2WPKH, P2WSH, P2TR.
        pub scriptpubkey: Script,
 }
 
 /// The minimum and maximum fees which the sender is willing to place on the closing transaction.
+///
 /// This is provided in [`ClosingSigned`] by both sides to indicate the fee range they are willing
 /// to use.
 #[derive(Clone, Debug, PartialEq, Eq)]
@@ -275,11 +585,13 @@ pub struct ClosingSignedFeeRange {
        pub max_fee_satoshis: u64,
 }
 
-/// A closing_signed message to be sent or received from a peer
+/// A [`closing_signed`] message to be sent to or received from a peer.
+///
+/// [`closing_signed`]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#closing-negotiation-closing_signed
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct ClosingSigned {
        /// The channel ID
-       pub channel_id: [u8; 32],
+       pub channel_id: ChannelId,
        /// The proposed total fee for the closing transaction
        pub fee_satoshis: u64,
        /// A signature on the closing transaction
@@ -289,11 +601,13 @@ pub struct ClosingSigned {
        pub fee_range: Option<ClosingSignedFeeRange>,
 }
 
-/// An update_add_htlc message to be sent or received from a peer
+/// An [`update_add_htlc`] message to be sent to or received from a peer.
+///
+/// [`update_add_htlc`]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#adding-an-htlc-update_add_htlc
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct UpdateAddHTLC {
        /// The channel ID
-       pub channel_id: [u8; 32],
+       pub channel_id: ChannelId,
        /// The HTLC ID
        pub htlc_id: u64,
        /// The HTLC value in milli-satoshi
@@ -302,10 +616,17 @@ 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,
 }
 
- /// An onion message to be sent or received from a peer
+ /// An onion message to be sent to or received from a peer.
+ ///
+ // TODO: update with link to OM when they are merged into the BOLTs
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct OnionMessage {
        /// Used in decrypting the onion packet's payload.
@@ -313,32 +634,38 @@ pub struct OnionMessage {
        pub(crate) onion_routing_packet: onion_message::Packet,
 }
 
-/// An update_fulfill_htlc message to be sent or received from a peer
+/// An [`update_fulfill_htlc`] message to be sent to or received from a peer.
+///
+/// [`update_fulfill_htlc`]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#removing-an-htlc-update_fulfill_htlc-update_fail_htlc-and-update_fail_malformed_htlc
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct UpdateFulfillHTLC {
        /// The channel ID
-       pub channel_id: [u8; 32],
+       pub channel_id: ChannelId,
        /// The HTLC ID
        pub htlc_id: u64,
        /// The pre-image of the payment hash, allowing HTLC redemption
        pub payment_preimage: PaymentPreimage,
 }
 
-/// An update_fail_htlc message to be sent or received from a peer
+/// An [`update_fail_htlc`] message to be sent to or received from a peer.
+///
+/// [`update_fail_htlc`]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#removing-an-htlc-update_fulfill_htlc-update_fail_htlc-and-update_fail_malformed_htlc
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct UpdateFailHTLC {
        /// The channel ID
-       pub channel_id: [u8; 32],
+       pub channel_id: ChannelId,
        /// The HTLC ID
        pub htlc_id: u64,
        pub(crate) reason: OnionErrorPacket,
 }
 
-/// An update_fail_malformed_htlc message to be sent or received from a peer
+/// An [`update_fail_malformed_htlc`] message to be sent to or received from a peer.
+///
+/// [`update_fail_malformed_htlc`]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#removing-an-htlc-update_fulfill_htlc-update_fail_htlc-and-update_fail_malformed_htlc
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct UpdateFailMalformedHTLC {
        /// The channel ID
-       pub channel_id: [u8; 32],
+       pub channel_id: ChannelId,
        /// The HTLC ID
        pub htlc_id: u64,
        pub(crate) sha256_of_onion: [u8; 32],
@@ -346,68 +673,76 @@ pub struct UpdateFailMalformedHTLC {
        pub failure_code: u16,
 }
 
-/// A commitment_signed message to be sent or received from a peer
+/// A [`commitment_signed`] message to be sent to or received from a peer.
+///
+/// [`commitment_signed`]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#committing-updates-so-far-commitment_signed
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct CommitmentSigned {
        /// The channel ID
-       pub channel_id: [u8; 32],
+       pub channel_id: ChannelId,
        /// A signature on the commitment transaction
        pub signature: Signature,
        /// Signatures on the HTLC transactions
        pub htlc_signatures: Vec<Signature>,
+       #[cfg(taproot)]
+       /// The partial Taproot signature on the commitment transaction
+       pub partial_signature_with_nonce: Option<PartialSignatureWithNonce>,
 }
 
-/// A revoke_and_ack message to be sent or received from a peer
+/// A [`revoke_and_ack`] message to be sent to or received from a peer.
+///
+/// [`revoke_and_ack`]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#completing-the-transition-to-the-updated-state-revoke_and_ack
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct RevokeAndACK {
        /// The channel ID
-       pub channel_id: [u8; 32],
+       pub channel_id: ChannelId,
        /// The secret corresponding to the per-commitment point
        pub per_commitment_secret: [u8; 32],
        /// The next sender-broadcast commitment transaction's per-commitment point
        pub next_per_commitment_point: PublicKey,
+       #[cfg(taproot)]
+       /// Musig nonce the recipient should use in their next commitment signature message
+       pub next_local_nonce: Option<musig2::types::PublicNonce>
 }
 
-/// An update_fee message to be sent or received from a peer
+/// An [`update_fee`] message to be sent to or received from a peer
+///
+/// [`update_fee`]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#updating-fees-update_fee
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct UpdateFee {
        /// The channel ID
-       pub channel_id: [u8; 32],
+       pub channel_id: ChannelId,
        /// Fee rate per 1000-weight of the transaction
        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 or received from a peer
+/// 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
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct ChannelReestablish {
        /// The channel ID
-       pub channel_id: [u8; 32],
+       pub channel_id: ChannelId,
        /// The next commitment number for the sender
        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 or received from a peer
+/// An [`announcement_signatures`] message to be sent to or received from a peer.
+///
+/// [`announcement_signatures`]: https://github.com/lightning/bolts/blob/master/07-routing-gossip.md#the-announcement_signatures-message
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct AnnouncementSignatures {
        /// The channel ID
-       pub channel_id: [u8; 32],
+       pub channel_id: ChannelId,
        /// The short channel ID
        pub short_channel_id: u64,
        /// A signature by the node key
@@ -416,18 +751,18 @@ pub struct AnnouncementSignatures {
        pub bitcoin_signature: Signature,
 }
 
-/// An address which can be used to connect to a remote peer
+/// An address which can be used to connect to a remote peer.
 #[derive(Clone, Debug, PartialEq, Eq)]
-pub enum NetAddress {
-       /// An IPv4 address/port on which the peer is listening.
-       IPv4 {
+pub enum SocketAddress {
+       /// An IPv4 address and port on which the peer is listening.
+       TcpIpV4 {
                /// The 4-byte IPv4 address
                addr: [u8; 4],
                /// The port on which the node is listening
                port: u16,
        },
-       /// An IPv6 address/port on which the peer is listening.
-       IPv6 {
+       /// An IPv6 address and port on which the peer is listening.
+       TcpIpV6 {
                /// The 16-byte IPv6 address
                addr: [u8; 16],
                /// The port on which the node is listening
@@ -439,7 +774,8 @@ pub enum NetAddress {
        /// addresses. Thus, the details are not parsed here.
        OnionV2([u8; 12]),
        /// A new-style Tor onion address/port on which the peer is listening.
-       /// To create the human-readable "hostname", concatenate ed25519_pubkey, checksum, and version,
+       ///
+       /// To create the human-readable "hostname", concatenate the ED25519 pubkey, checksum, and version,
        /// wrap as base32 and append ".onion".
        OnionV3 {
                /// The ed25519 long-term public key of the peer
@@ -459,28 +795,28 @@ pub enum NetAddress {
                port: u16,
        },
 }
-impl NetAddress {
-       /// Gets the ID of this address type. Addresses in node_announcement messages should be sorted
+impl SocketAddress {
+       /// Gets the ID of this address type. Addresses in [`NodeAnnouncement`] messages should be sorted
        /// by this.
        pub(crate) fn get_id(&self) -> u8 {
                match self {
-                       &NetAddress::IPv4 {..} => { 1 },
-                       &NetAddress::IPv6 {..} => { 2 },
-                       &NetAddress::OnionV2(_) => { 3 },
-                       &NetAddress::OnionV3 {..} => { 4 },
-                       &NetAddress::Hostname {..} => { 5 },
+                       &SocketAddress::TcpIpV4 {..} => { 1 },
+                       &SocketAddress::TcpIpV6 {..} => { 2 },
+                       &SocketAddress::OnionV2(_) => { 3 },
+                       &SocketAddress::OnionV3 {..} => { 4 },
+                       &SocketAddress::Hostname {..} => { 5 },
                }
        }
 
        /// Strict byte-length of address descriptor, 1-byte type not recorded
        fn len(&self) -> u16 {
                match self {
-                       &NetAddress::IPv4 { .. } => { 6 },
-                       &NetAddress::IPv6 { .. } => { 18 },
-                       &NetAddress::OnionV2(_) => { 12 },
-                       &NetAddress::OnionV3 { .. } => { 37 },
+                       &SocketAddress::TcpIpV4 { .. } => { 6 },
+                       &SocketAddress::TcpIpV6 { .. } => { 18 },
+                       &SocketAddress::OnionV2(_) => { 12 },
+                       &SocketAddress::OnionV3 { .. } => { 37 },
                        // Consists of 1-byte hostname length, hostname bytes, and 2-byte port.
-                       &NetAddress::Hostname { ref hostname, .. } => { u16::from(hostname.len()) + 3 },
+                       &SocketAddress::Hostname { ref hostname, .. } => { u16::from(hostname.len()) + 3 },
                }
        }
 
@@ -490,31 +826,31 @@ impl NetAddress {
        pub(crate) const MAX_LEN: u16 = 258;
 }
 
-impl Writeable for NetAddress {
+impl Writeable for SocketAddress {
        fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
                match self {
-                       &NetAddress::IPv4 { ref addr, ref port } => {
+                       &SocketAddress::TcpIpV4 { ref addr, ref port } => {
                                1u8.write(writer)?;
                                addr.write(writer)?;
                                port.write(writer)?;
                        },
-                       &NetAddress::IPv6 { ref addr, ref port } => {
+                       &SocketAddress::TcpIpV6 { ref addr, ref port } => {
                                2u8.write(writer)?;
                                addr.write(writer)?;
                                port.write(writer)?;
                        },
-                       &NetAddress::OnionV2(bytes) => {
+                       &SocketAddress::OnionV2(bytes) => {
                                3u8.write(writer)?;
                                bytes.write(writer)?;
                        },
-                       &NetAddress::OnionV3 { ref ed25519_pubkey, ref checksum, ref version, ref port } => {
+                       &SocketAddress::OnionV3 { ref ed25519_pubkey, ref checksum, ref version, ref port } => {
                                4u8.write(writer)?;
                                ed25519_pubkey.write(writer)?;
                                checksum.write(writer)?;
                                version.write(writer)?;
                                port.write(writer)?;
                        },
-                       &NetAddress::Hostname { ref hostname, ref port } => {
+                       &SocketAddress::Hostname { ref hostname, ref port } => {
                                5u8.write(writer)?;
                                hostname.write(writer)?;
                                port.write(writer)?;
@@ -524,25 +860,25 @@ impl Writeable for NetAddress {
        }
 }
 
-impl Readable for Result<NetAddress, u8> {
-       fn read<R: Read>(reader: &mut R) -> Result<Result<NetAddress, u8>, DecodeError> {
+impl Readable for Result<SocketAddress, u8> {
+       fn read<R: Read>(reader: &mut R) -> Result<Result<SocketAddress, u8>, DecodeError> {
                let byte = <u8 as Readable>::read(reader)?;
                match byte {
                        1 => {
-                               Ok(Ok(NetAddress::IPv4 {
+                               Ok(Ok(SocketAddress::TcpIpV4 {
                                        addr: Readable::read(reader)?,
                                        port: Readable::read(reader)?,
                                }))
                        },
                        2 => {
-                               Ok(Ok(NetAddress::IPv6 {
+                               Ok(Ok(SocketAddress::TcpIpV6 {
                                        addr: Readable::read(reader)?,
                                        port: Readable::read(reader)?,
                                }))
                        },
-                       3 => Ok(Ok(NetAddress::OnionV2(Readable::read(reader)?))),
+                       3 => Ok(Ok(SocketAddress::OnionV2(Readable::read(reader)?))),
                        4 => {
-                               Ok(Ok(NetAddress::OnionV3 {
+                               Ok(Ok(SocketAddress::OnionV3 {
                                        ed25519_pubkey: Readable::read(reader)?,
                                        checksum: Readable::read(reader)?,
                                        version: Readable::read(reader)?,
@@ -550,7 +886,7 @@ impl Readable for Result<NetAddress, u8> {
                                }))
                        },
                        5 => {
-                               Ok(Ok(NetAddress::Hostname {
+                               Ok(Ok(SocketAddress::Hostname {
                                        hostname: Readable::read(reader)?,
                                        port: Readable::read(reader)?,
                                }))
@@ -560,8 +896,8 @@ impl Readable for Result<NetAddress, u8> {
        }
 }
 
-impl Readable for NetAddress {
-       fn read<R: Read>(reader: &mut R) -> Result<NetAddress, DecodeError> {
+impl Readable for SocketAddress {
+       fn read<R: Read>(reader: &mut R) -> Result<SocketAddress, DecodeError> {
                match Readable::read(reader) {
                        Ok(Ok(res)) => Ok(res),
                        Ok(Err(_)) => Err(DecodeError::UnknownVersion),
@@ -570,29 +906,151 @@ impl Readable for NetAddress {
        }
 }
 
+/// [`SocketAddress`] error variants
+#[derive(Debug, Eq, PartialEq, Clone)]
+pub enum SocketAddressParseError {
+       /// Socket address (IPv4/IPv6) parsing error
+       SocketAddrParse,
+       /// Invalid input format
+       InvalidInput,
+       /// Invalid port
+       InvalidPort,
+       /// Invalid onion v3 address
+       InvalidOnionV3,
+}
+
+impl fmt::Display for SocketAddressParseError {
+       fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+               match self {
+                       SocketAddressParseError::SocketAddrParse => write!(f, "Socket address (IPv4/IPv6) parsing error"),
+                       SocketAddressParseError::InvalidInput => write!(f, "Invalid input format. \
+                               Expected: \"<ipv4>:<port>\", \"[<ipv6>]:<port>\", \"<onion address>.onion:<port>\" or \"<hostname>:<port>\""),
+                       SocketAddressParseError::InvalidPort => write!(f, "Invalid port"),
+                       SocketAddressParseError::InvalidOnionV3 => write!(f, "Invalid onion v3 address"),
+               }
+       }
+}
+
+#[cfg(feature = "std")]
+impl From<std::net::SocketAddrV4> for SocketAddress {
+               fn from(addr: std::net::SocketAddrV4) -> Self {
+                       SocketAddress::TcpIpV4 { addr: addr.ip().octets(), port: addr.port() }
+               }
+}
+
+#[cfg(feature = "std")]
+impl From<std::net::SocketAddrV6> for SocketAddress {
+               fn from(addr: std::net::SocketAddrV6) -> Self {
+                       SocketAddress::TcpIpV6 { addr: addr.ip().octets(), port: addr.port() }
+               }
+}
+
+#[cfg(feature = "std")]
+impl From<std::net::SocketAddr> for SocketAddress {
+               fn from(addr: std::net::SocketAddr) -> Self {
+                       match addr {
+                               std::net::SocketAddr::V4(addr) => addr.into(),
+                               std::net::SocketAddr::V6(addr) => addr.into(),
+                       }
+               }
+}
+
+fn parse_onion_address(host: &str, port: u16) -> Result<SocketAddress, SocketAddressParseError> {
+       if host.ends_with(".onion") {
+               let domain = &host[..host.len() - ".onion".len()];
+               if domain.len() != 56 {
+                       return Err(SocketAddressParseError::InvalidOnionV3);
+               }
+               let onion =  base32::Alphabet::RFC4648 { padding: false }.decode(&domain).map_err(|_| SocketAddressParseError::InvalidOnionV3)?;
+               if onion.len() != 35 {
+                       return Err(SocketAddressParseError::InvalidOnionV3);
+               }
+               let version = onion[0];
+               let first_checksum_flag = onion[1];
+               let second_checksum_flag = onion[2];
+               let mut ed25519_pubkey = [0; 32];
+               ed25519_pubkey.copy_from_slice(&onion[3..35]);
+               let checksum = u16::from_be_bytes([first_checksum_flag, second_checksum_flag]);
+               return Ok(SocketAddress::OnionV3 { ed25519_pubkey, checksum, version, port });
+
+       } else {
+               return Err(SocketAddressParseError::InvalidInput);
+       }
+}
 
-/// The unsigned part of a node_announcement
+#[cfg(feature = "std")]
+impl FromStr for SocketAddress {
+       type Err = SocketAddressParseError;
+
+       fn from_str(s: &str) -> Result<Self, Self::Err> {
+               match std::net::SocketAddr::from_str(s) {
+                       Ok(addr) => Ok(addr.into()),
+                       Err(_) => {
+                               let trimmed_input = match s.rfind(":") {
+                                       Some(pos) => pos,
+                                       None => return Err(SocketAddressParseError::InvalidInput),
+                               };
+                               let host = &s[..trimmed_input];
+                               let port: u16 = s[trimmed_input + 1..].parse().map_err(|_| SocketAddressParseError::InvalidPort)?;
+                               if host.ends_with(".onion") {
+                                       return parse_onion_address(host, port);
+                               };
+                               if let Ok(hostname) = Hostname::try_from(s[..trimmed_input].to_string()) {
+                                       return Ok(SocketAddress::Hostname { hostname, port });
+                               };
+                               return Err(SocketAddressParseError::SocketAddrParse)
+                       },
+               }
+       }
+}
+
+/// Represents the set of gossip messages that require a signature from a node's identity key.
+pub enum UnsignedGossipMessage<'a> {
+       /// An unsigned channel announcement.
+       ChannelAnnouncement(&'a UnsignedChannelAnnouncement),
+       /// An unsigned channel update.
+       ChannelUpdate(&'a UnsignedChannelUpdate),
+       /// An unsigned node announcement.
+       NodeAnnouncement(&'a UnsignedNodeAnnouncement)
+}
+
+impl<'a> Writeable for UnsignedGossipMessage<'a> {
+       fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
+               match self {
+                       UnsignedGossipMessage::ChannelAnnouncement(ref msg) => msg.write(writer),
+                       UnsignedGossipMessage::ChannelUpdate(ref msg) => msg.write(writer),
+                       UnsignedGossipMessage::NodeAnnouncement(ref msg) => msg.write(writer),
+               }
+       }
+}
+
+/// The unsigned part of a [`node_announcement`] message.
+///
+/// [`node_announcement`]: https://github.com/lightning/bolts/blob/master/07-routing-gossip.md#the-node_announcement-message
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct UnsignedNodeAnnouncement {
        /// The advertised features
        pub features: NodeFeatures,
        /// A strictly monotonic announcement counter, with gaps allowed
        pub timestamp: u32,
-       /// The node_id this announcement originated from (don't rebroadcast the node_announcement back
+       /// The `node_id` this announcement originated from (don't rebroadcast the `node_announcement` back
        /// to this node).
-       pub node_id: PublicKey,
+       pub node_id: NodeId,
        /// An RGB color for UI purposes
        pub rgb: [u8; 3],
-       /// An alias, for UI purposes.  This should be sanitized before use.  There is no guarantee
-       /// of uniqueness.
-       pub alias: [u8; 32],
+       /// An alias, for UI purposes.
+       ///
+       /// This should be sanitized before use. There is no guarantee of uniqueness.
+       pub alias: NodeAlias,
        /// List of addresses on which this node is reachable
-       pub addresses: Vec<NetAddress>,
+       pub addresses: Vec<SocketAddress>,
        pub(crate) excess_address_data: Vec<u8>,
        pub(crate) excess_data: Vec<u8>,
 }
 #[derive(Clone, Debug, PartialEq, Eq)]
-/// A node_announcement message to be sent or received from a peer
+/// A [`node_announcement`] message to be sent to or received from a peer.
+///
+/// [`node_announcement`]: https://github.com/lightning/bolts/blob/master/07-routing-gossip.md#the-node_announcement-message
 pub struct NodeAnnouncement {
        /// The signature by the node key
        pub signature: Signature,
@@ -600,7 +1058,9 @@ pub struct NodeAnnouncement {
        pub contents: UnsignedNodeAnnouncement,
 }
 
-/// The unsigned part of a channel_announcement
+/// The unsigned part of a [`channel_announcement`] message.
+///
+/// [`channel_announcement`]: https://github.com/lightning/bolts/blob/master/07-routing-gossip.md#the-channel_announcement-message
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct UnsignedChannelAnnouncement {
        /// The advertised channel features
@@ -609,17 +1069,23 @@ pub struct UnsignedChannelAnnouncement {
        pub chain_hash: BlockHash,
        /// The short channel ID
        pub short_channel_id: u64,
-       /// One of the two node_ids which are endpoints of this channel
-       pub node_id_1: PublicKey,
-       /// The other of the two node_ids which are endpoints of this channel
-       pub node_id_2: PublicKey,
+       /// One of the two `node_id`s which are endpoints of this channel
+       pub node_id_1: NodeId,
+       /// The other of the two `node_id`s which are endpoints of this channel
+       pub node_id_2: NodeId,
        /// The funding key for the first node
-       pub bitcoin_key_1: PublicKey,
+       pub bitcoin_key_1: NodeId,
        /// The funding key for the second node
-       pub bitcoin_key_2: PublicKey,
-       pub(crate) excess_data: Vec<u8>,
+       pub bitcoin_key_2: NodeId,
+       /// 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 or received from a peer
+/// A [`channel_announcement`] message to be sent to or received from a peer.
+///
+/// [`channel_announcement`]: https://github.com/lightning/bolts/blob/master/07-routing-gossip.md#the-channel_announcement-message
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct ChannelAnnouncement {
        /// Authentication of the announcement by the first public node
@@ -634,7 +1100,9 @@ pub struct ChannelAnnouncement {
        pub contents: UnsignedChannelAnnouncement,
 }
 
-/// The unsigned part of a channel_update
+/// The unsigned part of a [`channel_update`] message.
+///
+/// [`channel_update`]: https://github.com/lightning/bolts/blob/master/07-routing-gossip.md#the-channel_update-message
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct UnsignedChannelUpdate {
        /// The genesis hash of the blockchain where the channel is to be opened
@@ -647,27 +1115,32 @@ pub struct UnsignedChannelUpdate {
        pub flags: u8,
        /// The number of blocks such that if:
        /// `incoming_htlc.cltv_expiry < outgoing_htlc.cltv_expiry + cltv_expiry_delta`
-       /// then we need to fail the HTLC backwards. When forwarding an HTLC, cltv_expiry_delta determines
-       /// the outgoing HTLC's minimum cltv_expiry value -- so, if an incoming HTLC comes in with a
-       /// cltv_expiry of 100000, and the node we're forwarding to has a cltv_expiry_delta value of 10,
-       /// then we'll check that the outgoing HTLC's cltv_expiry value is at least 100010 before
+       /// then we need to fail the HTLC backwards. When forwarding an HTLC, `cltv_expiry_delta` determines
+       /// the outgoing HTLC's minimum `cltv_expiry` value -- so, if an incoming HTLC comes in with a
+       /// `cltv_expiry` of 100000, and the node we're forwarding to has a `cltv_expiry_delta` value of 10,
+       /// then we'll check that the outgoing HTLC's `cltv_expiry` value is at least 100010 before
        /// forwarding. Note that the HTLC sender is the one who originally sets this value when
        /// constructing the route.
        pub cltv_expiry_delta: u16,
        /// The minimum HTLC size incoming to sender, in milli-satoshi
        pub htlc_minimum_msat: u64,
-       /// The maximum HTLC value incoming to sender, in milli-satoshi. Used to be optional.
+       /// The maximum HTLC value incoming to sender, in milli-satoshi.
+       ///
+       /// This used to be optional.
        pub htlc_maximum_msat: u64,
        /// The base HTLC fee charged by sender, in milli-satoshi
        pub fee_base_msat: u32,
        /// The amount to fee multiplier, in micro-satoshi
        pub fee_proportional_millionths: u32,
        /// 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
+       /// 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_update message to be sent or received from a peer
+/// A [`channel_update`] message to be sent to or received from a peer.
+///
+/// [`channel_update`]: https://github.com/lightning/bolts/blob/master/07-routing-gossip.md#the-channel_update-message
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct ChannelUpdate {
        /// A signature of the channel update
@@ -676,10 +1149,12 @@ pub struct ChannelUpdate {
        pub contents: UnsignedChannelUpdate,
 }
 
-/// A query_channel_range message is used to query a peer for channel
+/// A [`query_channel_range`] message is used to query a peer for channel
 /// UTXOs in a range of blocks. The recipient of a query makes a best
-/// effort to reply to the query using one or more reply_channel_range
+/// effort to reply to the query using one or more [`ReplyChannelRange`]
 /// messages.
+///
+/// [`query_channel_range`]: https://github.com/lightning/bolts/blob/master/07-routing-gossip.md#the-query_channel_range-and-reply_channel_range-messages
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct QueryChannelRange {
        /// The genesis hash of the blockchain being queried
@@ -690,13 +1165,17 @@ pub struct QueryChannelRange {
        pub number_of_blocks: u32,
 }
 
-/// A reply_channel_range message is a reply to a query_channel_range
-/// message. Multiple reply_channel_range messages can be sent in reply
-/// to a single query_channel_range message. The query recipient makes a
+/// A [`reply_channel_range`] message is a reply to a [`QueryChannelRange`]
+/// message.
+///
+/// Multiple `reply_channel_range` messages can be sent in reply
+/// to a single [`QueryChannelRange`] message. The query recipient makes a
 /// best effort to respond based on their local network view which may
-/// not be a perfect view of the network. The short_channel_ids in the
-/// reply are encoded. We only support encoding_type=0 uncompressed
-/// serialization and do not support encoding_type=1 zlib serialization.
+/// not be a perfect view of the network. The `short_channel_id`s in the
+/// reply are encoded. We only support `encoding_type=0` uncompressed
+/// serialization and do not support `encoding_type=1` zlib serialization.
+///
+/// [`reply_channel_range`]: https://github.com/lightning/bolts/blob/master/07-routing-gossip.md#the-query_channel_range-and-reply_channel_range-messages
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct ReplyChannelRange {
        /// The genesis hash of the blockchain being queried
@@ -707,18 +1186,21 @@ pub struct ReplyChannelRange {
        pub number_of_blocks: u32,
        /// True when this is the final reply for a query
        pub sync_complete: bool,
-       /// The short_channel_ids in the channel range
+       /// The `short_channel_id`s in the channel range
        pub short_channel_ids: Vec<u64>,
 }
 
-/// A query_short_channel_ids message is used to query a peer for
-/// routing gossip messages related to one or more short_channel_ids.
+/// A [`query_short_channel_ids`] message is used to query a peer for
+/// routing gossip messages related to one or more `short_channel_id`s.
+///
 /// The query recipient will reply with the latest, if available,
-/// channel_announcement, channel_update and node_announcement messages
-/// it maintains for the requested short_channel_ids followed by a
-/// reply_short_channel_ids_end message. The short_channel_ids sent in
-/// this query are encoded. We only support encoding_type=0 uncompressed
-/// serialization and do not support encoding_type=1 zlib serialization.
+/// [`ChannelAnnouncement`], [`ChannelUpdate`] and [`NodeAnnouncement`] messages
+/// it maintains for the requested `short_channel_id`s followed by a
+/// [`ReplyShortChannelIdsEnd`] message. The `short_channel_id`s sent in
+/// this query are encoded. We only support `encoding_type=0` uncompressed
+/// serialization and do not support `encoding_type=1` zlib serialization.
+///
+/// [`query_short_channel_ids`]: https://github.com/lightning/bolts/blob/master/07-routing-gossip.md#the-query_short_channel_idsreply_short_channel_ids_end-messages
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct QueryShortChannelIds {
        /// The genesis hash of the blockchain being queried
@@ -727,22 +1209,26 @@ pub struct QueryShortChannelIds {
        pub short_channel_ids: Vec<u64>,
 }
 
-/// A reply_short_channel_ids_end message is sent as a reply to a
-/// query_short_channel_ids message. The query recipient makes a best
+/// A [`reply_short_channel_ids_end`] message is sent as a reply to a
+/// message. The query recipient makes a best
 /// effort to respond based on their local network view which may not be
 /// a perfect view of the network.
+///
+/// [`reply_short_channel_ids_end`]: https://github.com/lightning/bolts/blob/master/07-routing-gossip.md#the-query_short_channel_idsreply_short_channel_ids_end-messages
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct ReplyShortChannelIdsEnd {
        /// The genesis hash of the blockchain that was queried
        pub chain_hash: BlockHash,
        /// Indicates if the query recipient maintains up-to-date channel
-       /// information for the chain_hash
+       /// information for the `chain_hash`
        pub full_information: bool,
 }
 
-/// A gossip_timestamp_filter message is used by a node to request
+/// A [`gossip_timestamp_filter`] message is used by a node to request
 /// gossip relay for messages in the requested time range when the
-/// gossip_queries feature has been negotiated.
+/// `gossip_queries` feature has been negotiated.
+///
+/// [`gossip_timestamp_filter`]: https://github.com/lightning/bolts/blob/master/07-routing-gossip.md#the-gossip_timestamp_filter-message
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct GossipTimestampFilter {
        /// The genesis hash of the blockchain for channel and node information
@@ -754,19 +1240,26 @@ pub struct GossipTimestampFilter {
 }
 
 /// Encoding type for data compression of collections in gossip queries.
-/// We do not support encoding_type=1 zlib serialization defined in BOLT #7.
+///
+/// We do not support `encoding_type=1` zlib serialization [defined in BOLT
+/// #7](https://github.com/lightning/bolts/blob/master/07-routing-gossip.md#query-messages).
 enum EncodingType {
        Uncompressed = 0x00,
 }
 
-/// Used to put an error message in a LightningError
-#[derive(Clone, Debug)]
+/// Used to put an error message in a [`LightningError`].
+#[derive(Clone, Debug, PartialEq)]
 pub enum ErrorAction {
        /// The peer took some action which made us think they were useless. Disconnect them.
        DisconnectPeer {
                /// 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,
@@ -802,105 +1295,110 @@ pub struct LightningError {
        pub action: ErrorAction,
 }
 
-/// Struct used to return values from revoke_and_ack messages, containing a bunch of commitment
+/// Struct used to return values from [`RevokeAndACK`] messages, containing a bunch of commitment
 /// transaction updates if they were pending.
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct CommitmentUpdate {
-       /// update_add_htlc messages which should be sent
+       /// `update_add_htlc` messages which should be sent
        pub update_add_htlcs: Vec<UpdateAddHTLC>,
-       /// update_fulfill_htlc messages which should be sent
+       /// `update_fulfill_htlc` messages which should be sent
        pub update_fulfill_htlcs: Vec<UpdateFulfillHTLC>,
-       /// update_fail_htlc messages which should be sent
+       /// `update_fail_htlc` messages which should be sent
        pub update_fail_htlcs: Vec<UpdateFailHTLC>,
-       /// update_fail_malformed_htlc messages which should be sent
+       /// `update_fail_malformed_htlc` messages which should be sent
        pub update_fail_malformed_htlcs: Vec<UpdateFailMalformedHTLC>,
-       /// An update_fee message which should be sent
+       /// An `update_fee` message which should be sent
        pub update_fee: Option<UpdateFee>,
-       /// Finally, the commitment_signed message which should be sent
+       /// A `commitment_signed` message which should be sent
        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
-/// OptionalFeild simply gets Present if there are enough bytes to read into it), we have a
-/// separate enum type for them.
-/// (C-not exported) 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
-/// they MUST NOT be called in parallel when the two calls have the same their_node_id.
+/// Messages MAY be called in parallel when they originate from different `their_node_ids`, however
+/// they MUST NOT be called in parallel when the two calls have the same `their_node_id`.
 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, their_features: InitFeatures, msg: &OpenChannel);
-       /// Handle an incoming accept_channel message from the given peer.
-       fn handle_accept_channel(&self, their_node_id: &PublicKey, their_features: InitFeatures, msg: &AcceptChannel);
-       /// Handle an incoming funding_created message from the given peer.
+       // 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.
+       /// Handle an incoming `funding_signed` message from the given peer.
        fn handle_funding_signed(&self, their_node_id: &PublicKey, msg: &FundingSigned);
-       /// Handle an incoming channel_ready message from the given peer.
+       /// Handle an incoming `channel_ready` message from the given peer.
        fn handle_channel_ready(&self, their_node_id: &PublicKey, msg: &ChannelReady);
 
-       // Channl close:
-       /// Handle an incoming shutdown message from the given peer.
-       fn handle_shutdown(&self, their_node_id: &PublicKey, their_features: &InitFeatures, msg: &Shutdown);
-       /// Handle an incoming closing_signed message from the given peer.
+       // Channel close:
+       /// Handle an incoming `shutdown` message from the given peer.
+       fn handle_shutdown(&self, their_node_id: &PublicKey, msg: &Shutdown);
+       /// 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.
+       /// Handle an incoming `update_add_htlc` message from the given peer.
        fn handle_update_add_htlc(&self, their_node_id: &PublicKey, msg: &UpdateAddHTLC);
-       /// Handle an incoming update_fulfill_htlc message from the given peer.
+       /// Handle an incoming `update_fulfill_htlc` message from the given peer.
        fn handle_update_fulfill_htlc(&self, their_node_id: &PublicKey, msg: &UpdateFulfillHTLC);
-       /// Handle an incoming update_fail_htlc message from the given peer.
+       /// Handle an incoming `update_fail_htlc` message from the given peer.
        fn handle_update_fail_htlc(&self, their_node_id: &PublicKey, msg: &UpdateFailHTLC);
-       /// Handle an incoming update_fail_malformed_htlc message from the given peer.
+       /// Handle an incoming `update_fail_malformed_htlc` message from the given peer.
        fn handle_update_fail_malformed_htlc(&self, their_node_id: &PublicKey, msg: &UpdateFailMalformedHTLC);
-       /// Handle an incoming commitment_signed message from the given peer.
+       /// Handle an incoming `commitment_signed` message from the given peer.
        fn handle_commitment_signed(&self, their_node_id: &PublicKey, msg: &CommitmentSigned);
-       /// Handle an incoming revoke_and_ack message from the given peer.
+       /// Handle an incoming `revoke_and_ack` message from the given peer.
        fn handle_revoke_and_ack(&self, their_node_id: &PublicKey, msg: &RevokeAndACK);
 
-       /// Handle an incoming update_fee message from the given peer.
+       /// Handle an incoming `update_fee` message from the given peer.
        fn handle_update_fee(&self, their_node_id: &PublicKey, msg: &UpdateFee);
 
        // Channel-to-announce:
-       /// Handle an incoming announcement_signatures message from the given peer.
+       /// Handle an incoming `announcement_signatures` message from the given peer.
        fn handle_announcement_signatures(&self, their_node_id: &PublicKey, msg: &AnnouncementSignatures);
 
        // Connection loss/reestablish:
-       /// Indicates a connection to the peer failed/an existing connection was lost. If no connection
-       /// is believed to be possible in the future (eg they're sending us messages we don't
-       /// understand or indicate they require unknown feature bits), no_connection_possible is set
-       /// and any outstanding channels should be failed.
-       ///
-       /// Note that in some rare cases this may be called without a corresponding
-       /// [`Self::peer_connected`].
-       fn peer_disconnected(&self, their_node_id: &PublicKey, no_connection_possible: bool);
+       /// Indicates a connection to the peer failed/an existing connection was lost.
+       fn peer_disconnected(&self, their_node_id: &PublicKey);
 
-       /// Handle a peer reconnecting, possibly generating channel_reestablish message(s).
+       /// Handle a peer reconnecting, possibly generating `channel_reestablish` message(s).
        ///
        /// May return an `Err(())` if the features the peer supports are not sufficient to communicate
        /// with us. Implementors should be somewhat conservative about doing so, however, as other
        /// message handlers may still wish to communicate with this peer.
-       fn peer_connected(&self, their_node_id: &PublicKey, msg: &Init) -> Result<(), ()>;
-       /// Handle an incoming channel_reestablish message from the given peer.
+       fn peer_connected(&self, their_node_id: &PublicKey, msg: &Init, inbound: bool) -> Result<(), ()>;
+       /// Handle an incoming `channel_reestablish` message from the given peer.
        fn handle_channel_reestablish(&self, their_node_id: &PublicKey, msg: &ChannelReestablish);
 
-       /// Handle an incoming channel update from the given peer.
+       /// Handle an incoming `channel_update` message from the given peer.
        fn handle_channel_update(&self, their_node_id: &PublicKey, msg: &ChannelUpdate);
 
        // Error:
-       /// Handle an incoming error message from the given peer.
+       /// Handle an incoming `error` message from the given peer.
        fn handle_error(&self, their_node_id: &PublicKey, msg: &ErrorMessage);
 
        // Handler information:
@@ -915,34 +1413,40 @@ 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.
 ///
 /// # Implementor DoS Warnings
 ///
-/// For `gossip_queries` messages there are potential DoS vectors when handling
-/// inbound queries. Implementors using an on-disk network graph should be aware of
+/// For messages enabled with the `gossip_queries` feature there are potential DoS vectors when
+/// handling inbound queries. Implementors using an on-disk network graph should be aware of
 /// repeated disk I/O for queries accessing different parts of the network graph.
 pub trait RoutingMessageHandler : MessageSendEventsProvider {
-       /// Handle an incoming node_announcement message, returning true if it should be forwarded on,
-       /// false or returning an Err otherwise.
+       /// Handle an incoming `node_announcement` message, returning `true` if it should be forwarded on,
+       /// `false` or returning an `Err` otherwise.
        fn handle_node_announcement(&self, msg: &NodeAnnouncement) -> Result<bool, LightningError>;
-       /// Handle a channel_announcement message, returning true if it should be forwarded on, false
-       /// or returning an Err otherwise.
+       /// Handle a `channel_announcement` message, returning `true` if it should be forwarded on, `false`
+       /// or returning an `Err` otherwise.
        fn handle_channel_announcement(&self, msg: &ChannelAnnouncement) -> Result<bool, LightningError>;
-       /// Handle an incoming channel_update message, returning true if it should be forwarded on,
-       /// false or returning an Err otherwise.
+       /// Handle an incoming `channel_update` message, returning true if it should be forwarded on,
+       /// `false` or returning an `Err` otherwise.
        fn handle_channel_update(&self, msg: &ChannelUpdate) -> Result<bool, LightningError>;
        /// Gets channel announcements and updates required to dump our routing table to a remote node,
-       /// starting at the short_channel_id indicated by starting_point and including announcements
+       /// starting at the `short_channel_id` indicated by `starting_point` and including announcements
        /// for a single channel.
        fn get_next_channel_announcement(&self, starting_point: u64) -> Option<(ChannelAnnouncement, Option<ChannelUpdate>, Option<ChannelUpdate>)>;
        /// Gets a node announcement required to dump our routing table to a remote node, starting at
        /// the node *after* the provided pubkey and including up to one announcement immediately
-       /// higher (as defined by <PublicKey as Ord>::cmp) than starting_point.
-       /// If None is provided for starting_point, we start at the first node.
-       fn get_next_node_announcement(&self, starting_point: Option<&PublicKey>) -> Option<NodeAnnouncement>;
+       /// higher (as defined by `<PublicKey as Ord>::cmp`) than `starting_point`.
+       /// If `None` is provided for `starting_point`, we start at the first node.
+       fn get_next_node_announcement(&self, starting_point: Option<&NodeId>) -> Option<NodeAnnouncement>;
        /// Called when a connection is established with a peer. This can be used to
        /// perform routing table synchronization using a strategy defined by the
        /// implementor.
@@ -950,7 +1454,7 @@ pub trait RoutingMessageHandler : MessageSendEventsProvider {
        /// May return an `Err(())` if the features the peer supports are not sufficient to communicate
        /// with us. Implementors should be somewhat conservative about doing so, however, as other
        /// message handlers may still wish to communicate with this peer.
-       fn peer_connected(&self, their_node_id: &PublicKey, init: &Init) -> Result<(), ()>;
+       fn peer_connected(&self, their_node_id: &PublicKey, init: &Init, inbound: bool) -> Result<(), ()>;
        /// Handles the reply of a query we initiated to learn about channels
        /// for a given range of blocks. We can expect to receive one or more
        /// replies to a single query.
@@ -960,13 +1464,20 @@ pub trait RoutingMessageHandler : MessageSendEventsProvider {
        /// a node has completed its best effort to send us the pertaining routing
        /// gossip messages.
        fn handle_reply_short_channel_ids_end(&self, their_node_id: &PublicKey, msg: ReplyShortChannelIdsEnd) -> Result<(), LightningError>;
-       /// Handles when a peer asks us to send a list of short_channel_ids
+       /// Handles when a peer asks us to send a list of `short_channel_id`s
        /// for the requested range of blocks.
        fn handle_query_channel_range(&self, their_node_id: &PublicKey, msg: QueryChannelRange) -> Result<(), LightningError>;
        /// Handles when a peer asks us to send routing gossip messages for a
-       /// list of short_channel_ids.
+       /// list of `short_channel_id`s.
        fn handle_query_short_channel_ids(&self, their_node_id: &PublicKey, msg: QueryShortChannelIds) -> Result<(), LightningError>;
 
+       // Handler queueing status:
+       /// Indicates that there are a large number of [`ChannelAnnouncement`] (or other) messages
+       /// pending some async action. While there is no guarantee of the rate of future messages, the
+       /// caller should seek to reduce the rate of new gossip messages handled, especially
+       /// [`ChannelAnnouncement`]s.
+       fn processing_queue_high(&self) -> bool;
+
        // Handler information:
        /// Gets the node feature flags which this handler itself supports. All available handlers are
        /// queried similarly and their feature flags are OR'd together to form the [`NodeFeatures`]
@@ -982,7 +1493,7 @@ pub trait RoutingMessageHandler : MessageSendEventsProvider {
 
 /// A trait to describe an object that can receive onion messages.
 pub trait OnionMessageHandler : OnionMessageProvider {
-       /// Handle an incoming onion_message message from the given peer.
+       /// Handle an incoming `onion_message` message from the given peer.
        fn handle_onion_message(&self, peer_node_id: &PublicKey, msg: &OnionMessage);
        /// Called when a connection is established with a peer. Can be used to track which peers
        /// advertise onion message support and are online.
@@ -990,13 +1501,10 @@ pub trait OnionMessageHandler : OnionMessageProvider {
        /// May return an `Err(())` if the features the peer supports are not sufficient to communicate
        /// with us. Implementors should be somewhat conservative about doing so, however, as other
        /// message handlers may still wish to communicate with this peer.
-       fn peer_connected(&self, their_node_id: &PublicKey, init: &Init) -> Result<(), ()>;
+       fn peer_connected(&self, their_node_id: &PublicKey, init: &Init, inbound: bool) -> Result<(), ()>;
        /// Indicates a connection to the peer failed/an existing connection was lost. Allows handlers to
        /// drop and refuse to forward onion messages to this peer.
-       ///
-       /// Note that in some rare cases this may be called without a corresponding
-       /// [`Self::peer_connected`].
-       fn peer_disconnected(&self, their_node_id: &PublicKey, no_connection_possible: bool);
+       fn peer_disconnected(&self, their_node_id: &PublicKey);
 
        // Handler information:
        /// Gets the node feature flags which this handler itself supports. All available handlers are
@@ -1013,39 +1521,72 @@ pub trait OnionMessageHandler : OnionMessageProvider {
 }
 
 mod fuzzy_internal_msgs {
+       use bitcoin::secp256k1::PublicKey;
+       use crate::blinded_path::payment::PaymentConstraints;
        use crate::prelude::*;
        use crate::ln::{PaymentPreimage, PaymentSecret};
 
        // 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 {
-               Legacy { // aka Realm-0
+       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,
                },
-               NonFinalNode {
-                       short_channel_id: u64,
-               },
-               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,
                },
+               BlindedReceive {
+                       amt_msat: u64,
+                       total_msat: u64,
+                       outgoing_cltv_value: u32,
+                       payment_secret: PaymentSecret,
+                       payment_constraints: PaymentConstraints,
+                       intro_node_blinding_point: PublicKey,
+               }
        }
 
-       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,
-               // 12 bytes of 0-padding for Legacy format
+       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,
+               },
+               BlindedForward {
+                       encrypted_tlvs: Vec<u8>,
+                       intro_node_blinding_point: Option<PublicKey>,
+               },
+               BlindedReceive {
+                       amt_msat: u64,
+                       total_msat: u64,
+                       outgoing_cltv_value: u32,
+                       encrypted_tlvs: Vec<u8>,
+                       intro_node_blinding_point: Option<PublicKey>, // Set if the introduction node of the blinded path is the final node
+               }
        }
 
        pub struct DecodedOnionErrorPacket {
@@ -1062,9 +1603,11 @@ pub(crate) use self::fuzzy_internal_msgs::*;
 #[derive(Clone)]
 pub(crate) struct OnionPacket {
        pub(crate) version: u8,
-       /// In order to ensure we always return an error on Onion decode in compliance with BOLT 4, we
-       /// have to deserialize OnionPackets contained in UpdateAddHTLCs even if the ephemeral public
-       /// key (here) is bogus, so we hold a Result instead of a PublicKey as we'd like.
+       /// In order to ensure we always return an error on onion decode in compliance with [BOLT
+       /// #4](https://github.com/lightning/bolts/blob/master/04-onion-routing.md), we have to
+       /// deserialize `OnionPacket`s contained in [`UpdateAddHTLC`] messages even if the ephemeral
+       /// public key (here) is bogus, so we hold a [`Result`] instead of a [`PublicKey`] as we'd
+       /// like.
        pub(crate) public_key: Result<PublicKey, secp256k1::Error>,
        pub(crate) hop_data: [u8; 20*65],
        pub(crate) hmac: [u8; 32],
@@ -1131,53 +1674,28 @@ 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,
+       dust_limit_satoshis,
+       max_htlc_value_in_flight_msat,
+       channel_reserve_satoshis,
+       htlc_minimum_msat,
+       minimum_depth,
+       to_self_delay,
+       max_accepted_htlcs,
+       funding_pubkey,
+       revocation_basepoint,
+       payment_point,
+       delayed_payment_basepoint,
+       htlc_basepoint,
+       first_per_commitment_point,
+}, {
+       (0, shutdown_scriptpubkey, (option, encoding: (Script, WithoutLength))), // Don't encode length twice.
+       (1, channel_type, option),
+});
 
+#[cfg(taproot)]
 impl_writeable_msg!(AcceptChannel, {
        temporary_channel_id,
        dust_limit_satoshis,
@@ -1193,11 +1711,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,
@@ -1205,42 +1800,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 },
@@ -1252,29 +1820,59 @@ impl_writeable!(ClosingSignedFeeRange, {
        max_fee_satoshis
 });
 
+#[cfg(not(taproot))]
 impl_writeable_msg!(CommitmentSigned, {
        channel_id,
        signature,
        htlc_signatures
 }, {});
 
+#[cfg(taproot)]
+impl_writeable_msg!(CommitmentSigned, {
+       channel_id,
+       signature,
+       htlc_signatures
+}, {
+       (2, partial_signature_with_nonce, option)
+});
+
 impl_writeable!(DecodedOnionErrorPacket, {
        hmac,
        failuremsg,
        pad
 });
 
+#[cfg(not(taproot))]
+impl_writeable_msg!(FundingCreated, {
+       temporary_channel_id,
+       funding_txid,
+       funding_output_index,
+       signature
+}, {});
+#[cfg(taproot)]
 impl_writeable_msg!(FundingCreated, {
        temporary_channel_id,
        funding_txid,
        funding_output_index,
        signature
+}, {
+       (2, partial_signature_with_nonce, option),
+       (4, next_local_nonce, option)
+});
+
+#[cfg(not(taproot))]
+impl_writeable_msg!(FundingSigned, {
+       channel_id,
+       signature
 }, {});
 
+#[cfg(taproot)]
 impl_writeable_msg!(FundingSigned, {
        channel_id,
        signature
-}, {});
+}, {
+       (2, partial_signature_with_nonce, option)
+});
 
 impl_writeable_msg!(ChannelReady, {
        channel_id,
@@ -1290,7 +1888,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(())
        }
@@ -1300,12 +1899,15 @@ impl Readable for Init {
        fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
                let global_features: InitFeatures = Readable::read(r)?;
                let features: InitFeatures = Readable::read(r)?;
-               let mut remote_network_address: Option<NetAddress> = None;
+               let mut remote_network_address: Option<SocketAddress> = 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,
                })
        }
@@ -1330,17 +1932,53 @@ 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,
        per_commitment_secret,
        next_per_commitment_point
 }, {});
 
+#[cfg(taproot)]
+impl_writeable_msg!(RevokeAndACK, {
+       channel_id,
+       per_commitment_secret,
+       next_per_commitment_point
+}, {
+       (4, next_local_nonce, option)
+});
+
 impl_writeable_msg!(Shutdown, {
        channel_id,
        scriptpubkey
@@ -1414,8 +2052,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> {
@@ -1455,29 +2095,49 @@ 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::Legacy { short_channel_id } => {
-                               0u8.write(w)?;
-                               short_channel_id.write(w)?;
-                               self.amt_to_forward.write(w)?;
-                               self.outgoing_cltv_value.write(w)?;
-                               w.write_all(&[0;12])?;
-                       },
-                       OnionHopDataFormat::NonFinalNode { short_channel_id } => {
-                               encode_varint_length_prefixed_tlv!(w, {
-                                       (2, HighZeroBytesDroppedBigSize(self.amt_to_forward), required),
-                                       (4, HighZeroBytesDroppedBigSize(self.outgoing_cltv_value), required),
+               match self {
+                       Self::Forward { short_channel_id, amt_to_forward, outgoing_cltv_value } => {
+                               _encode_varint_length_prefixed_tlv!(w, {
+                                       (2, HighZeroBytesDroppedBigSize(*amt_to_forward), required),
+                                       (4, HighZeroBytesDroppedBigSize(*outgoing_cltv_value), required),
                                        (6, short_channel_id, required)
                                });
                        },
-                       OnionHopDataFormat::FinalNode { ref payment_data, ref keysend_preimage } => {
-                               encode_varint_length_prefixed_tlv!(w, {
-                                       (2, HighZeroBytesDroppedBigSize(self.amt_to_forward), required),
-                                       (4, HighZeroBytesDroppedBigSize(self.outgoing_cltv_value), required),
+                       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(*amt_msat), required),
+                                       (4, HighZeroBytesDroppedBigSize(*outgoing_cltv_value), required),
                                        (8, payment_data, option),
-                                       (5482373484, keysend_preimage, option)
+                                       (16, payment_metadata.as_ref().map(|m| WithoutLength(m)), option)
+                               }, custom_tlvs.iter());
+                       },
+                       Self::BlindedForward { encrypted_tlvs, intro_node_blinding_point } => {
+                               _encode_varint_length_prefixed_tlv!(w, {
+                                       (10, *encrypted_tlvs, required_vec),
+                                       (12, intro_node_blinding_point, option)
+                               });
+                       },
+                       Self::BlindedReceive {
+                               amt_msat, total_msat, outgoing_cltv_value, encrypted_tlvs,
+                               intro_node_blinding_point,
+                       } => {
+                               _encode_varint_length_prefixed_tlv!(w, {
+                                       (2, HighZeroBytesDroppedBigSize(*amt_msat), required),
+                                       (4, HighZeroBytesDroppedBigSize(*outgoing_cltv_value), required),
+                                       (10, *encrypted_tlvs, required_vec),
+                                       (12, intro_node_blinding_point, option),
+                                       (18, HighZeroBytesDroppedBigSize(*total_msat), required)
                                });
                        },
                }
@@ -1485,69 +2145,92 @@ impl Writeable for OnionHopData {
        }
 }
 
-impl Readable for OnionHopData {
-       fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
-               let b: BigSize = Readable::read(r)?;
-               const LEGACY_ONION_HOP_FLAG: u64 = 0;
-               let (format, amt, cltv_value) = if b.0 != LEGACY_ONION_HOP_FLAG {
-                       let mut rd = FixedLengthReader::new(r, b.0);
-                       let mut amt = HighZeroBytesDroppedBigSize(0u64);
-                       let mut cltv_value = HighZeroBytesDroppedBigSize(0u32);
-                       let mut short_id: Option<u64> = None;
-                       let mut payment_data: Option<FinalOnionHopData> = None;
-                       let mut keysend_preimage: Option<PaymentPreimage> = None;
-                       decode_tlv_stream!(&mut rd, {
-                               (2, amt, required),
-                               (4, cltv_value, required),
-                               (6, short_id, option),
-                               (8, payment_data, option),
-                               // See https://github.com/lightning/blips/blob/master/blip-0003.md
-                               (5482373484, keysend_preimage, option)
-                       });
-                       rd.eat_remaining().map_err(|_| DecodeError::ShortRead)?;
-                       let format = if let Some(short_channel_id) = short_id {
-                               if payment_data.is_some() { return Err(DecodeError::InvalidValue); }
-                               OnionHopDataFormat::NonFinalNode {
-                                       short_channel_id,
-                               }
-                       } else {
-                               if let &Some(ref data) = &payment_data {
-                                       if data.total_msat > MAX_VALUE_MSAT {
-                                               return Err(DecodeError::InvalidValue);
-                                       }
-                               }
-                               OnionHopDataFormat::FinalNode {
-                                       payment_data,
-                                       keysend_preimage,
-                               }
-                       };
-                       (format, amt.0, cltv_value.0)
-               } else {
-                       let format = OnionHopDataFormat::Legacy {
-                               short_channel_id: Readable::read(r)?,
-                       };
-                       let amt: u64 = Readable::read(r)?;
-                       let cltv_value: u32 = Readable::read(r)?;
-                       r.read_exact(&mut [0; 12])?;
-                       (format, amt, cltv_value)
-               };
+impl<NS: Deref> ReadableArgs<&NS> for InboundOnionPayload where NS::Target: NodeSigner {
+       fn read<R: Read>(r: &mut R, node_signer: &NS) -> Result<Self, DecodeError> {
+               let mut amt = None;
+               let mut cltv_value = None;
+               let mut short_id: Option<u64> = None;
+               let mut payment_data: Option<FinalOnionHopData> = None;
+               let mut encrypted_tlvs_opt: Option<WithoutLength<Vec<u8>>> = None;
+               let mut intro_node_blinding_point = None;
+               let mut payment_metadata: Option<WithoutLength<Vec<u8>>> = None;
+               let mut total_msat = None;
+               let mut keysend_preimage: Option<PaymentPreimage> = None;
+               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, (option, encoding: (u64, HighZeroBytesDroppedBigSize))),
+                       (4, cltv_value, (option, encoding: (u32, HighZeroBytesDroppedBigSize))),
+                       (6, short_id, option),
+                       (8, payment_data, option),
+                       (10, encrypted_tlvs_opt, option),
+                       (12, intro_node_blinding_point, option),
+                       (16, payment_metadata, option),
+                       (18, total_msat, (option, encoding: (u64, HighZeroBytesDroppedBigSize))),
+                       // 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)
+               });
 
-               if amt > MAX_VALUE_MSAT {
-                       return Err(DecodeError::InvalidValue);
-               }
-               Ok(OnionHopData {
-                       format,
-                       amt_to_forward: amt,
-                       outgoing_cltv_value: cltv_value,
-               })
-       }
-}
+               if amt.unwrap_or(0) > MAX_VALUE_MSAT { return Err(DecodeError::InvalidValue) }
 
-// ReadableArgs because we need onion_utils::decode_next_hop to accommodate payment packets and
-// onion message packets.
-impl ReadableArgs<()> for OnionHopData {
-       fn read<R: Read>(r: &mut R, _arg: ()) -> Result<Self, DecodeError> {
-               <Self as Readable>::read(r)
+               if let Some(blinding_point) = intro_node_blinding_point {
+                       if short_id.is_some() || payment_data.is_some() || payment_metadata.is_some() {
+                               return Err(DecodeError::InvalidValue)
+                       }
+                       let enc_tlvs = encrypted_tlvs_opt.ok_or(DecodeError::InvalidValue)?.0;
+                       let enc_tlvs_ss = node_signer.ecdh(Recipient::Node, &blinding_point, None)
+                               .map_err(|_| DecodeError::InvalidValue)?;
+                       let rho = onion_utils::gen_rho_from_shared_secret(&enc_tlvs_ss.secret_bytes());
+                       let mut s = Cursor::new(&enc_tlvs);
+                       let mut reader = FixedLengthReader::new(&mut s, enc_tlvs.len() as u64);
+                       match ChaChaPolyReadAdapter::read(&mut reader, rho)? {
+                               ChaChaPolyReadAdapter { readable: ReceiveTlvs { payment_secret, payment_constraints }} => {
+                                       if total_msat.unwrap_or(0) > MAX_VALUE_MSAT { return Err(DecodeError::InvalidValue) }
+                                       Ok(Self::BlindedReceive {
+                                               amt_msat: amt.ok_or(DecodeError::InvalidValue)?,
+                                               total_msat: total_msat.ok_or(DecodeError::InvalidValue)?,
+                                               outgoing_cltv_value: cltv_value.ok_or(DecodeError::InvalidValue)?,
+                                               payment_secret,
+                                               payment_constraints,
+                                               intro_node_blinding_point: blinding_point,
+                                       })
+                               },
+                       }
+               } else if let Some(short_channel_id) = short_id {
+                       if payment_data.is_some() || payment_metadata.is_some() || encrypted_tlvs_opt.is_some() ||
+                               total_msat.is_some()
+                       { return Err(DecodeError::InvalidValue) }
+                       Ok(Self::Forward {
+                               short_channel_id,
+                               amt_to_forward: amt.ok_or(DecodeError::InvalidValue)?,
+                               outgoing_cltv_value: cltv_value.ok_or(DecodeError::InvalidValue)?,
+                       })
+               } else {
+                       if encrypted_tlvs_opt.is_some() || total_msat.is_some() {
+                               return Err(DecodeError::InvalidValue)
+                       }
+                       if let Some(data) = &payment_data {
+                               if data.total_msat > MAX_VALUE_MSAT {
+                                       return Err(DecodeError::InvalidValue);
+                               }
+                       }
+                       Ok(Self::Receive {
+                               payment_data,
+                               payment_metadata: payment_metadata.map(|w| w.0),
+                               keysend_preimage,
+                               amt_msat: amt.ok_or(DecodeError::InvalidValue)?,
+                               outgoing_cltv_value: cltv_value.ok_or(DecodeError::InvalidValue)?,
+                               custom_tlvs,
+                       })
+               }
        }
 }
 
@@ -1753,13 +2436,13 @@ impl Readable for UnsignedNodeAnnouncement {
        fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
                let features: NodeFeatures = Readable::read(r)?;
                let timestamp: u32 = Readable::read(r)?;
-               let node_id: PublicKey = Readable::read(r)?;
+               let node_id: NodeId = Readable::read(r)?;
                let mut rgb = [0; 3];
                r.read_exact(&mut rgb)?;
-               let alias: [u8; 32] = Readable::read(r)?;
+               let alias: NodeAlias = Readable::read(r)?;
 
                let addr_len: u16 = Readable::read(r)?;
-               let mut addresses: Vec<NetAddress> = Vec::new();
+               let mut addresses: Vec<SocketAddress> = Vec::new();
                let mut addr_readpos = 0;
                let mut excess = false;
                let mut excess_byte = 0;
@@ -1875,10 +2558,9 @@ impl_writeable_msg!(ReplyShortChannelIdsEnd, {
 }, {});
 
 impl QueryChannelRange {
-       /**
-        * Calculates the overflow safe ending block height for the query.
-        * Overflow returns `0xffffffff`, otherwise returns `first_blocknum + number_of_blocks`
-        */
+       /// Calculates the overflow safe ending block height for the query.
+       ///
+       /// Overflow returns `0xffffffff`, otherwise returns `first_blocknum + number_of_blocks`.
        pub fn end_blocknum(&self) -> u32 {
                match self.first_blocknum.checked_add(self.number_of_blocks) {
                        Some(block) => block,
@@ -1959,12 +2641,18 @@ impl_writeable_msg!(GossipTimestampFilter, {
 
 #[cfg(test)]
 mod tests {
+       use std::convert::TryFrom;
+       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::ChannelId;
        use crate::ln::features::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, NodeFeatures};
-       use crate::ln::msgs;
-       use crate::ln::msgs::{FinalOnionHopData, OptionalField, OnionErrorPacket, OnionHopDataFormat};
-       use crate::util::ser::{Writeable, Readable, Hostname};
+       use crate::ln::msgs::{self, FinalOnionHopData, OnionErrorPacket};
+       use crate::ln::msgs::SocketAddress;
+       use crate::routing::gossip::{NodeAlias, NodeId};
+       use crate::util::ser::{Writeable, Readable, ReadableArgs, Hostname, TransactionU16LenLimited};
+       use crate::util::test_utils;
 
        use bitcoin::hashes::hex::FromHex;
        use bitcoin::util::address::Address;
@@ -1978,42 +2666,73 @@ mod tests {
 
        use crate::io::{self, Cursor};
        use crate::prelude::*;
-       use core::convert::TryFrom;
+       use core::str::FromStr;
+       use crate::chain::transaction::OutPoint;
+
+       #[cfg(feature = "std")]
+       use std::net::{Ipv4Addr, Ipv6Addr};
+       use crate::ln::msgs::SocketAddressParseError;
 
        #[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],
+                       channel_id: ChannelId::from_bytes([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())
                };
 
                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],
+                       channel_id: ChannelId::from_bytes([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
+                       ]
                );
        }
 
@@ -2043,7 +2762,7 @@ mod tests {
                let sig_1 = get_sig_on!(privkey, secp_ctx, String::from("01010101010101010101010101010101"));
                let sig_2 = get_sig_on!(privkey, secp_ctx, String::from("02020202020202020202020202020202"));
                let announcement_signatures = msgs::AnnouncementSignatures {
-                       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],
+                       channel_id: ChannelId::from_bytes([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]),
                        short_channel_id: 2316138423780173,
                        node_signature: sig_1,
                        bitcoin_signature: sig_2,
@@ -2071,10 +2790,10 @@ mod tests {
                        features,
                        chain_hash: BlockHash::from_hex("6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000").unwrap(),
                        short_channel_id: 2316138423780173,
-                       node_id_1: pubkey_1,
-                       node_id_2: pubkey_2,
-                       bitcoin_key_1: pubkey_3,
-                       bitcoin_key_2: pubkey_4,
+                       node_id_1: NodeId::from_pubkey(&pubkey_1),
+                       node_id_2: NodeId::from_pubkey(&pubkey_2),
+                       bitcoin_key_1: NodeId::from_pubkey(&pubkey_3),
+                       bitcoin_key_2: NodeId::from_pubkey(&pubkey_4),
                        excess_data: if excess_data { vec![10, 0, 0, 20, 0, 0, 30, 0, 0, 40] } else { Vec::new() },
                };
                let channel_announcement = msgs::ChannelAnnouncement {
@@ -2119,24 +2838,24 @@ mod tests {
                };
                let mut addresses = Vec::new();
                if ipv4 {
-                       addresses.push(msgs::NetAddress::IPv4 {
+                       addresses.push(SocketAddress::TcpIpV4 {
                                addr: [255, 254, 253, 252],
                                port: 9735
                        });
                }
                if ipv6 {
-                       addresses.push(msgs::NetAddress::IPv6 {
+                       addresses.push(SocketAddress::TcpIpV6 {
                                addr: [255, 254, 253, 252, 251, 250, 249, 248, 247, 246, 245, 244, 243, 242, 241, 240],
                                port: 9735
                        });
                }
                if onionv2 {
-                       addresses.push(msgs::NetAddress::OnionV2(
+                       addresses.push(msgs::SocketAddress::OnionV2(
                                [255, 254, 253, 252, 251, 250, 249, 248, 247, 246, 38, 7]
                        ));
                }
                if onionv3 {
-                       addresses.push(msgs::NetAddress::OnionV3 {
+                       addresses.push(msgs::SocketAddress::OnionV3 {
                                ed25519_pubkey: [255, 254, 253, 252, 251, 250, 249, 248, 247, 246, 245, 244, 243, 242, 241, 240, 239, 238, 237, 236, 235, 234, 233, 232, 231, 230, 229, 228, 227, 226, 225, 224],
                                checksum: 32,
                                version: 16,
@@ -2144,7 +2863,7 @@ mod tests {
                        });
                }
                if hostname {
-                       addresses.push(msgs::NetAddress::Hostname {
+                       addresses.push(SocketAddress::Hostname {
                                hostname: Hostname::try_from(String::from("host")).unwrap(),
                                port: 9735,
                        });
@@ -2156,9 +2875,9 @@ mod tests {
                let unsigned_node_announcement = msgs::UnsignedNodeAnnouncement {
                        features,
                        timestamp: 20190119,
-                       node_id: pubkey_1,
+                       node_id: NodeId::from_pubkey(&pubkey_1),
                        rgb: [32; 3],
-                       alias: [16;32],
+                       alias: NodeAlias([16;32]),
                        addresses,
                        excess_address_data: if excess_address_data { vec![33, 108, 40, 11, 83, 149, 162, 84, 110, 126, 75, 38, 99, 224, 79, 129, 22, 34, 241, 90, 79, 146, 232, 58, 162, 233, 43, 162, 165, 115, 193, 57, 20, 44, 84, 174, 99, 7, 42, 30, 193, 238, 125, 192, 192, 75, 222, 92, 132, 120, 6, 23, 42, 160, 92, 146, 194, 42, 232, 227, 8, 209, 210, 105] } else { Vec::new() },
                        excess_data: if excess_data { vec![59, 18, 204, 25, 92, 224, 162, 209, 189, 166, 168, 139, 239, 161, 159, 160, 127, 81, 202, 167, 92, 232, 56, 55, 242, 137, 101, 96, 11, 138, 172, 171, 8, 85, 255, 176, 231, 65, 236, 95, 124, 65, 66, 30, 152, 41, 169, 212, 134, 17, 200, 200, 49, 247, 27, 229, 234, 115, 230, 101, 148, 151, 127, 253] } else { Vec::new() },
@@ -2279,7 +2998,7 @@ mod tests {
                let (_, pubkey_6) = get_keys_from!("0606060606060606060606060606060606060606060606060606060606060606", secp_ctx);
                let open_channel = msgs::OpenChannel {
                        chain_hash: BlockHash::from_hex("6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000").unwrap(),
-                       temporary_channel_id: [2; 32],
+                       temporary_channel_id: ChannelId::from_bytes([2; 32]),
                        funding_satoshis: 1311768467284833366,
                        push_msat: 2536655962884945560,
                        dust_limit_satoshis: 3608586615801332854,
@@ -2296,7 +3015,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();
@@ -2329,6 +3048,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: ChannelId::from_bytes([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);
@@ -2338,7 +3149,7 @@ mod tests {
                let (_, pubkey_5) = get_keys_from!("0505050505050505050505050505050505050505050505050505050505050505", secp_ctx);
                let (_, pubkey_6) = get_keys_from!("0606060606060606060606060606060606060606060606060606060606060606", secp_ctx);
                let accept_channel = msgs::AcceptChannel {
-                       temporary_channel_id: [2; 32],
+                       temporary_channel_id: ChannelId::from_bytes([2; 32]),
                        dust_limit_satoshis: 1311768467284833366,
                        max_htlc_value_in_flight_msat: 2536655962884945560,
                        channel_reserve_satoshis: 3608586615801332854,
@@ -2352,8 +3163,10 @@ 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,
                };
                let encoded_value = accept_channel.encode();
                let mut target_value = hex::decode("020202020202020202020202020202020202020202020202020202020202020212345678901234562334032891223698321446687011447600083a840000034d000c89d4c0bcc0bc031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f024d4b6cd1361032ca9bd2aeb9d900aa4d45d9ead80ac9423374c451a7254d076602531fe6068134503d2723133227c867ac8fa6c83c537e9a44c3c5bdbdcb1fe33703462779ad4aad39514614751a71085f2f10e1c7a593e4e030efb5b8721ce55b0b0362c0a046dacce86ddd0343c6d3c7c79c2208ba0d9c9cf24a6d046d21d21f90f703f006a18d5653c4edf5391ff23a61f03ff83d237e880ee61187fa9f379a028e0a").unwrap();
@@ -2369,16 +3182,78 @@ 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: ChannelId::from_bytes([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();
                let (privkey_1, _) = get_keys_from!("0101010101010101010101010101010101010101010101010101010101010101", secp_ctx);
                let sig_1 = get_sig_on!(privkey_1, secp_ctx, String::from("01010101010101010101010101010101"));
                let funding_created = msgs::FundingCreated {
-                       temporary_channel_id: [2; 32],
+                       temporary_channel_id: ChannelId::from_bytes([2; 32]),
                        funding_txid: Txid::from_hex("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap(),
                        funding_output_index: 255,
                        signature: sig_1,
+                       #[cfg(taproot)]
+                       partial_signature_with_nonce: None,
+                       #[cfg(taproot)]
+                       next_local_nonce: None,
                };
                let encoded_value = funding_created.encode();
                let target_value = hex::decode("02020202020202020202020202020202020202020202020202020202020202026e96fe9f8b0ddcd729ba03cfafa5a27b050b39d354dd980814268dfa9a44d4c200ffd977cb9b53d93a6ff64bb5f1e158b4094b66e798fb12911168a3ccdf80a83096340a6a95da0ae8d9f776528eecdbb747eb6b545495a4319ed5378e35b21e073a").unwrap();
@@ -2391,8 +3266,10 @@ mod tests {
                let (privkey_1, _) = get_keys_from!("0101010101010101010101010101010101010101010101010101010101010101", secp_ctx);
                let sig_1 = get_sig_on!(privkey_1, secp_ctx, String::from("01010101010101010101010101010101"));
                let funding_signed = msgs::FundingSigned {
-                       channel_id: [2; 32],
+                       channel_id: ChannelId::from_bytes([2; 32]),
                        signature: sig_1,
+                       #[cfg(taproot)]
+                       partial_signature_with_nonce: None,
                };
                let encoded_value = funding_signed.encode();
                let target_value = hex::decode("0202020202020202020202020202020202020202020202020202020202020202d977cb9b53d93a6ff64bb5f1e158b4094b66e798fb12911168a3ccdf80a83096340a6a95da0ae8d9f776528eecdbb747eb6b545495a4319ed5378e35b21e073a").unwrap();
@@ -2404,7 +3281,7 @@ mod tests {
                let secp_ctx = Secp256k1::new();
                let (_, pubkey_1,) = get_keys_from!("0101010101010101010101010101010101010101010101010101010101010101", secp_ctx);
                let channel_ready = msgs::ChannelReady {
-                       channel_id: [2; 32],
+                       channel_id: ChannelId::from_bytes([2; 32]),
                        next_per_commitment_point: pubkey_1,
                        short_channel_id_alias: None,
                };
@@ -2413,17 +3290,191 @@ mod tests {
                assert_eq!(encoded_value, target_value);
        }
 
+       #[test]
+       fn encoding_tx_add_input() {
+               let tx_add_input = msgs::TxAddInput {
+                       channel_id: ChannelId::from_bytes([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: ChannelId::from_bytes([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: ChannelId::from_bytes([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: ChannelId::from_bytes([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: ChannelId::from_bytes([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: ChannelId::from_bytes([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: ChannelId::from_bytes([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: ChannelId::from_bytes([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: ChannelId::from_bytes([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);
                let script = Builder::new().push_opcode(opcodes::OP_TRUE).into_script();
                let shutdown = msgs::Shutdown {
-                       channel_id: [2; 32],
+                       channel_id: ChannelId::from_bytes([2; 32]),
                        scriptpubkey:
-                                    if script_type == 1 { Address::p2pkh(&::bitcoin::PublicKey{compressed: true, inner: pubkey_1}, Network::Testnet).script_pubkey() }
+                               if script_type == 1 { Address::p2pkh(&::bitcoin::PublicKey{compressed: true, inner: pubkey_1}, Network::Testnet).script_pubkey() }
                                else if script_type == 2 { Address::p2sh(&script, Network::Testnet).unwrap().script_pubkey() }
                                else if script_type == 3 { Address::p2wpkh(&::bitcoin::PublicKey{compressed: true, inner: pubkey_1}, Network::Testnet).unwrap().script_pubkey() }
-                               else                     { Address::p2wsh(&script, Network::Testnet).script_pubkey() },
+                               else { Address::p2wsh(&script, Network::Testnet).script_pubkey() },
                };
                let encoded_value = shutdown.encode();
                let mut target_value = hex::decode("0202020202020202020202020202020202020202020202020202020202020202").unwrap();
@@ -2453,7 +3504,7 @@ mod tests {
                let (privkey_1, _) = get_keys_from!("0101010101010101010101010101010101010101010101010101010101010101", secp_ctx);
                let sig_1 = get_sig_on!(privkey_1, secp_ctx, String::from("01010101010101010101010101010101"));
                let closing_signed = msgs::ClosingSigned {
-                       channel_id: [2; 32],
+                       channel_id: ChannelId::from_bytes([2; 32]),
                        fee_satoshis: 2316138423780173,
                        signature: sig_1,
                        fee_range: None,
@@ -2464,7 +3515,7 @@ mod tests {
                assert_eq!(msgs::ClosingSigned::read(&mut Cursor::new(&target_value)).unwrap(), closing_signed);
 
                let closing_signed_with_range = msgs::ClosingSigned {
-                       channel_id: [2; 32],
+                       channel_id: ChannelId::from_bytes([2; 32]),
                        fee_satoshis: 2316138423780173,
                        signature: sig_1,
                        fee_range: Some(msgs::ClosingSignedFeeRange {
@@ -2490,12 +3541,13 @@ mod tests {
                        hmac: [2; 32]
                };
                let update_add_htlc = msgs::UpdateAddHTLC {
-                       channel_id: [2; 32],
+                       channel_id: ChannelId::from_bytes([2; 32]),
                        htlc_id: 2316138423780173,
                        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();
@@ -2505,7 +3557,7 @@ mod tests {
        #[test]
        fn encoding_update_fulfill_htlc() {
                let update_fulfill_htlc = msgs::UpdateFulfillHTLC {
-                       channel_id: [2; 32],
+                       channel_id: ChannelId::from_bytes([2; 32]),
                        htlc_id: 2316138423780173,
                        payment_preimage: PaymentPreimage([1; 32]),
                };
@@ -2520,7 +3572,7 @@ mod tests {
                        data: [1; 32].to_vec(),
                };
                let update_fail_htlc = msgs::UpdateFailHTLC {
-                       channel_id: [2; 32],
+                       channel_id: ChannelId::from_bytes([2; 32]),
                        htlc_id: 2316138423780173,
                        reason
                };
@@ -2532,7 +3584,7 @@ mod tests {
        #[test]
        fn encoding_update_fail_malformed_htlc() {
                let update_fail_malformed_htlc = msgs::UpdateFailMalformedHTLC {
-                       channel_id: [2; 32],
+                       channel_id: ChannelId::from_bytes([2; 32]),
                        htlc_id: 2316138423780173,
                        sha256_of_onion: [1; 32],
                        failure_code: 255
@@ -2553,9 +3605,11 @@ mod tests {
                let sig_3 = get_sig_on!(privkey_3, secp_ctx, String::from("01010101010101010101010101010101"));
                let sig_4 = get_sig_on!(privkey_4, secp_ctx, String::from("01010101010101010101010101010101"));
                let commitment_signed = msgs::CommitmentSigned {
-                       channel_id: [2; 32],
+                       channel_id: ChannelId::from_bytes([2; 32]),
                        signature: sig_1,
                        htlc_signatures: if htlcs { vec![sig_2, sig_3, sig_4] } else { Vec::new() },
+                       #[cfg(taproot)]
+                       partial_signature_with_nonce: None,
                };
                let encoded_value = commitment_signed.encode();
                let mut target_value = hex::decode("0202020202020202020202020202020202020202020202020202020202020202d977cb9b53d93a6ff64bb5f1e158b4094b66e798fb12911168a3ccdf80a83096340a6a95da0ae8d9f776528eecdbb747eb6b545495a4319ed5378e35b21e073a").unwrap();
@@ -2578,9 +3632,11 @@ mod tests {
                let secp_ctx = Secp256k1::new();
                let (_, pubkey_1) = get_keys_from!("0101010101010101010101010101010101010101010101010101010101010101", secp_ctx);
                let raa = msgs::RevokeAndACK {
-                       channel_id: [2; 32],
+                       channel_id: ChannelId::from_bytes([2; 32]),
                        per_commitment_secret: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
                        next_per_commitment_point: pubkey_1,
+                       #[cfg(taproot)]
+                       next_local_nonce: None,
                };
                let encoded_value = raa.encode();
                let target_value = hex::decode("02020202020202020202020202020202020202020202020202020202020202020101010101010101010101010101010101010101010101010101010101010101031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f").unwrap();
@@ -2590,7 +3646,7 @@ mod tests {
        #[test]
        fn encoding_update_fee() {
                let update_fee = msgs::UpdateFee {
-                       channel_id: [2; 32],
+                       channel_id: ChannelId::from_bytes([2; 32]),
                        feerate_per_kw: 20190119,
                };
                let encoded_value = update_fee.encode();
@@ -2600,27 +3656,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![]),
-                       remote_network_address: Some(msgs::NetAddress::IPv4 {
+                       networks: Some(vec![mainnet_hash]),
+                       remote_network_address: Some(SocketAddress::TcpIpV4 {
                                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);
        }
@@ -2628,7 +3693,7 @@ mod tests {
        #[test]
        fn encoding_error() {
                let error = msgs::ErrorMessage {
-                       channel_id: [2; 32],
+                       channel_id: ChannelId::from_bytes([2; 32]),
                        data: String::from("rust-lightning"),
                };
                let encoded_value = error.encode();
@@ -2639,7 +3704,7 @@ mod tests {
        #[test]
        fn encoding_warning() {
                let error = msgs::WarningMessage {
-                       channel_id: [2; 32],
+                       channel_id: ChannelId::from_bytes([2; 32]),
                        data: String::from("rust-lightning"),
                };
                let encoded_value = error.encode();
@@ -2668,88 +3733,155 @@ mod tests {
                assert_eq!(encoded_value, target_value);
        }
 
-       #[test]
-       fn encoding_legacy_onion_hop_data() {
-               let msg = msgs::OnionHopData {
-                       format: OnionHopDataFormat::Legacy {
-                               short_channel_id: 0xdeadbeef1bad1dea,
-                       },
-                       amt_to_forward: 0x0badf00d01020304,
-                       outgoing_cltv_value: 0xffffffff,
-               };
-               let encoded_value = msg.encode();
-               let target_value = hex::decode("00deadbeef1bad1dea0badf00d01020304ffffffff000000000000000000000000").unwrap();
-               assert_eq!(encoded_value, target_value);
-       }
-
        #[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 node_signer = test_utils::TestKeysInterface::new(&[42; 32], Network::Testnet);
+               let inbound_msg = ReadableArgs::read(&mut Cursor::new(&target_value[..]), &&node_signer).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,
-                               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 node_signer = test_utils::TestKeysInterface::new(&[42; 32], Network::Testnet);
+               let inbound_msg = ReadableArgs::read(&mut Cursor::new(&target_value[..]), &&node_signer).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
-                               }),
-                               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 node_signer = test_utils::TestKeysInterface::new(&[42; 32], Network::Testnet);
+               let inbound_msg = ReadableArgs::read(&mut Cursor::new(&target_value[..]), &&node_signer).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();
+               let node_signer = test_utils::TestKeysInterface::new(&[42; 32], Network::Testnet);
+               assert!(msgs::InboundOnionPayload::read(&mut Cursor::new(&encoded_value[..]), &&node_signer).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 = ReadableArgs::read(&mut Cursor::new(&encoded_value[..]), &&node_signer).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 node_signer = test_utils::TestKeysInterface::new(&[42; 32], Network::Testnet);
+               let inbound_msg: msgs::InboundOnionPayload = ReadableArgs::read(&mut Cursor::new(&target_value[..]), &&node_signer).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]
@@ -2899,28 +4031,72 @@ 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();
+
+               let node_signer = test_utils::TestKeysInterface::new(&[42; 32], Network::Testnet);
+               <msgs::InboundOnionPayload as ReadableArgs<&&test_utils::TestKeysInterface>>
+                       ::read(&mut rd, &&node_signer).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 {
-                       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),
+               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, required_vec),
+                               (2, HighZeroBytesDroppedBigSize(amt_to_forward), required),
+                               (4, HighZeroBytesDroppedBigSize(outgoing_cltv_value), required),
                                (6, short_channel_id, required)
                        });
                }
                Ok(encoded_payload)
        }
+
+       #[test]
+       #[cfg(feature = "std")]
+       fn test_socket_address_from_str() {
+               assert_eq!(SocketAddress::TcpIpV4 {
+                       addr: Ipv4Addr::new(127, 0, 0, 1).octets(),
+                       port: 1234,
+               }, SocketAddress::from_str("127.0.0.1:1234").unwrap());
+
+               assert_eq!(SocketAddress::TcpIpV6 {
+                       addr: Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).octets(),
+                       port: 1234,
+               }, SocketAddress::from_str("[0:0:0:0:0:0:0:1]:1234").unwrap());
+               assert_eq!(
+                       SocketAddress::Hostname {
+                               hostname: Hostname::try_from("lightning-node.mydomain.com".to_string()).unwrap(),
+                               port: 1234,
+                       }, SocketAddress::from_str("lightning-node.mydomain.com:1234").unwrap());
+               assert_eq!(
+                       SocketAddress::Hostname {
+                               hostname: Hostname::try_from("example.com".to_string()).unwrap(),
+                               port: 1234,
+                       }, SocketAddress::from_str("example.com:1234").unwrap());
+               assert_eq!(SocketAddress::OnionV3 {
+                       ed25519_pubkey: [37, 24, 75, 5, 25, 73, 117, 194, 139, 102, 182, 107, 4, 105, 247, 246, 85,
+                       111, 177, 172, 49, 137, 167, 155, 64, 221, 163, 47, 31, 33, 71, 3],
+                       checksum: 48326,
+                       version: 121,
+                       port: 1234
+               }, SocketAddress::from_str("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion:1234").unwrap());
+               assert_eq!(Err(SocketAddressParseError::InvalidOnionV3), SocketAddress::from_str("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6.onion:1234"));
+               assert_eq!(Err(SocketAddressParseError::InvalidInput), SocketAddress::from_str("127.0.0.1@1234"));
+               assert_eq!(Err(SocketAddressParseError::InvalidInput), "".parse::<SocketAddress>());
+               assert!(SocketAddress::from_str("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion.onion:9735:94").is_err());
+               assert!(SocketAddress::from_str("wrong$%#.com:1234").is_err());
+               assert_eq!(Err(SocketAddressParseError::InvalidPort), SocketAddress::from_str("example.com:wrong"));
+               assert!("localhost".parse::<SocketAddress>().is_err());
+               assert!("localhost:invalid-port".parse::<SocketAddress>().is_err());
+               assert!( "invalid-onion-v3-hostname.onion:8080".parse::<SocketAddress>().is_err());
+               assert!("b32.example.onion:invalid-port".parse::<SocketAddress>().is_err());
+               assert!("invalid-address".parse::<SocketAddress>().is_err());
+               assert!(SocketAddress::from_str("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion.onion:1234").is_err());
+       }
 }