Merge pull request #3144 from TheBlueMatt/2024-06-message-flags
[rust-lightning] / lightning / src / ln / msgs.rs
index cf569f4c493908ae0b29eb353d5d71401555804a..8f389d07cefc9b59cb314b58a597ac75d23aa199 100644 (file)
@@ -32,15 +32,15 @@ use bitcoin::blockdata::script::ScriptBuf;
 use bitcoin::hash_types::Txid;
 
 use crate::blinded_path::payment::{BlindedPaymentTlvs, ForwardTlvs, ReceiveTlvs};
-use crate::ln::{ChannelId, PaymentPreimage, PaymentHash, PaymentSecret};
+use crate::ln::types::{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};
 
+#[allow(unused_imports)]
 use crate::prelude::*;
-#[cfg(feature = "std")]
-use core::convert::TryFrom;
+
 use core::fmt;
 use core::fmt::Debug;
 use core::ops::Deref;
@@ -52,10 +52,10 @@ use core::fmt::Display;
 use crate::io::{self, Cursor, Read};
 use crate::io_extras::read_to_end;
 
-use crate::events::{EventsProvider, MessageSendEventsProvider};
+use crate::events::MessageSendEventsProvider;
 use crate::crypto::streams::ChaChaPolyReadAdapter;
 use crate::util::logger;
-use crate::util::ser::{LengthReadable, LengthReadableArgs, Readable, ReadableArgs, Writeable, Writer, WithoutLength, FixedLengthReader, HighZeroBytesDroppedBigSize, Hostname, TransactionU16LenLimited, BigSize};
+use crate::util::ser::{BigSize, FixedLengthReader, HighZeroBytesDroppedBigSize, Hostname, LengthRead, LengthReadable, LengthReadableArgs, Readable, ReadableArgs, TransactionU16LenLimited, WithoutLength, Writeable, Writer};
 use crate::util::base32;
 
 use crate::routing::gossip::{NodeAlias, NodeId};
@@ -91,6 +91,16 @@ pub enum DecodeError {
        Io(io::ErrorKind),
        /// The message included zlib-compressed values, which we don't support.
        UnsupportedCompression,
+       /// Value is validly encoded but is dangerous to use.
+       ///
+       /// This is used for things like [`ChannelManager`] deserialization where we want to ensure
+       /// that we don't use a [`ChannelManager`] which is in out of sync with the [`ChannelMonitor`].
+       /// This indicates that there is a critical implementation flaw in the storage implementation
+       /// and it's unsafe to continue.
+       ///
+       /// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
+       /// [`ChannelMonitor`]: crate::chain::channelmonitor::ChannelMonitor
+       DangerousValue,
 }
 
 /// An [`init`] message to be sent to or received from a peer.
@@ -396,8 +406,13 @@ pub struct ChannelReady {
        pub short_channel_id_alias: Option<u64>,
 }
 
-/// An stfu (quiescence) message to be sent by or received from the stfu initiator.
-// TODO(splicing): Add spec link for `stfu`; still in draft, using from https://github.com/lightning/bolts/pull/863
+/// A randomly chosen number that is used to identify inputs within an interactive transaction
+/// construction.
+pub type SerialId = u64;
+
+/// An `stfu` (quiescence) message to be sent by or received from the stfu initiator.
+///
+// TODO(splicing): Add spec link for `stfu`; still in draft, using from https://github.com/lightning/bolts/pull/1160
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct Stfu {
        /// The channel ID where quiescence is intended
@@ -406,48 +421,51 @@ pub struct Stfu {
        pub initiator: u8,
 }
 
-/// A splice message to be sent by or received from the stfu initiator (splice initiator).
-// TODO(splicing): Add spec link for `splice`; still in draft, using from https://github.com/lightning/bolts/pull/863
+/// A `splice_init` message to be sent by or received from the stfu initiator (splice initiator).
+///
+// TODO(splicing): Add spec link for `splice_init`; still in draft, using from https://github.com/lightning/bolts/pull/1160
 #[derive(Clone, Debug, PartialEq, Eq)]
-pub struct Splice {
+pub struct SpliceInit {
        /// The channel ID where splicing is intended
        pub channel_id: ChannelId,
-       /// The genesis hash of the blockchain where the channel is intended to be spliced
-       pub chain_hash: ChainHash,
-       /// The intended change in channel capacity: the amount to be added (positive value)
-       /// or removed (negative value) by the sender (splice initiator) by splicing into/from the channel.
-       pub relative_satoshis: i64,
+       /// The amount the splice initiator is intending to add to its channel balance (splice-in)
+       /// or remove from its channel balance (splice-out).
+       pub funding_contribution_satoshis: i64,
        /// The feerate for the new funding transaction, set by the splice initiator
        pub funding_feerate_perkw: u32,
        /// The locktime for the new funding transaction
        pub locktime: u32,
        /// The key of the sender (splice initiator) controlling the new funding transaction
        pub funding_pubkey: PublicKey,
+       /// If set, only confirmed inputs added (by the splice acceptor) will be accepted
+       pub require_confirmed_inputs: Option<()>,
 }
 
-/// A splice_ack message to be received by or sent to the splice initiator.
+/// A `splice_ack` message to be received by or sent to the splice initiator.
 ///
-// TODO(splicing): Add spec link for `splice_ack`; still in draft, using from https://github.com/lightning/bolts/pull/863
+// TODO(splicing): Add spec link for `splice_ack`; still in draft, using from https://github.com/lightning/bolts/pull/1160
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct SpliceAck {
        /// The channel ID where splicing is intended
        pub channel_id: ChannelId,
-       /// The genesis hash of the blockchain where the channel is intended to be spliced
-       pub chain_hash: ChainHash,
-       /// The intended change in channel capacity: the amount to be added (positive value)
-       /// or removed (negative value) by the sender (splice acceptor) by splicing into/from the channel.
-       pub relative_satoshis: i64,
+       /// The amount the splice acceptor is intending to add to its channel balance (splice-in)
+       /// or remove from its channel balance (splice-out).
+       pub funding_contribution_satoshis: i64,
        /// The key of the sender (splice acceptor) controlling the new funding transaction
        pub funding_pubkey: PublicKey,
+       /// If set, only confirmed inputs added (by the splice initiator) will be accepted
+       pub require_confirmed_inputs: Option<()>,
 }
 
-/// A splice_locked message to be sent to or received from a peer.
+/// A `splice_locked` message to be sent to or received from a peer.
 ///
-// TODO(splicing): Add spec link for `splice_locked`; still in draft, using from https://github.com/lightning/bolts/pull/863
+// TODO(splicing): Add spec link for `splice_locked`; still in draft, using from https://github.com/lightning/bolts/pull/1160
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct SpliceLocked {
        /// The channel ID
        pub channel_id: ChannelId,
+       /// The ID of the new funding transaction that has been locked
+       pub splice_txid: Txid,
 }
 
 /// A tx_add_input message for adding an input during interactive transaction construction
@@ -459,7 +477,7 @@ pub struct TxAddInput {
        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,
+       pub serial_id: SerialId,
        /// Serialized transaction that contains the output this input spends to verify that it is non
        /// malleable.
        pub prevtx: TransactionU16LenLimited,
@@ -467,6 +485,8 @@ pub struct TxAddInput {
        pub prevtx_out: u32,
        /// The sequence number of this input
        pub sequence: u32,
+       /// The ID of the previous funding transaction, when it is being added as an input during splicing
+       pub shared_input_txid: Option<Txid>,
 }
 
 /// A tx_add_output message for adding an output during interactive transaction construction.
@@ -478,7 +498,7 @@ pub struct TxAddOutput {
        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,
+       pub serial_id: SerialId,
        /// The satoshi value of the output
        pub sats: u64,
        /// The scriptPubKey for the output
@@ -493,7 +513,7 @@ pub struct TxRemoveInput {
        /// The channel ID
        pub channel_id: ChannelId,
        /// The serial ID of the input to be removed
-       pub serial_id: u64,
+       pub serial_id: SerialId,
 }
 
 /// A tx_remove_output message for removing an output during interactive transaction construction.
@@ -504,7 +524,7 @@ pub struct TxRemoveOutput {
        /// The channel ID
        pub channel_id: ChannelId,
        /// The serial ID of the output to be removed
-       pub serial_id: u64,
+       pub serial_id: SerialId,
 }
 
 /// A tx_complete message signalling the conclusion of a peer's transaction contributions during
@@ -529,6 +549,8 @@ pub struct TxSignatures {
        pub tx_hash: Txid,
        /// The list of witnesses
        pub witnesses: Vec<Witness>,
+       /// Optional signature for the shared input -- the previous funding outpoint -- signed by both peers
+       pub shared_input_signature: Option<Signature>,
 }
 
 /// A tx_init_rbf message which initiates a replacement of the transaction after it's been
@@ -692,6 +714,15 @@ pub struct UpdateFailMalformedHTLC {
        pub failure_code: u16,
 }
 
+/// Optional batch parameters for `commitment_signed` message.
+#[derive(Clone, Debug, Hash, PartialEq, Eq)]
+pub struct CommitmentSignedBatch {
+       /// Batch size N: all N `commitment_signed` messages must be received before being processed
+       pub batch_size: u16,
+       /// The funding transaction, to discriminate among multiple pending funding transactions (e.g. in case of splicing)
+       pub funding_txid: Txid,
+}
+
 /// 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
@@ -703,6 +734,8 @@ pub struct CommitmentSigned {
        pub signature: Signature,
        /// Signatures on the HTLC transactions
        pub htlc_signatures: Vec<Signature>,
+       /// Optional batch size and other parameters
+       pub batch: Option<CommitmentSignedBatch>,
        #[cfg(taproot)]
        /// The partial Taproot signature on the commitment transaction
        pub partial_signature_with_nonce: Option<PartialSignatureWithNonce>,
@@ -1136,8 +1169,16 @@ pub struct UnsignedNodeAnnouncement {
        pub alias: NodeAlias,
        /// List of addresses on which this node is reachable
        pub addresses: Vec<SocketAddress>,
-       pub(crate) excess_address_data: Vec<u8>,
-       pub(crate) excess_data: Vec<u8>,
+       /// Excess address 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 address types are added to the lightning gossip protocol.
+       pub excess_address_data: Vec<u8>,
+       /// Excess data which was signed as a part of the message which we do not (yet) understand how
+       /// to decode.
+       ///
+       /// This is stored to ensure forward-compatibility as new fields are added to the lightning gossip protocol.
+       pub excess_data: Vec<u8>,
 }
 #[derive(Clone, Debug, Hash, PartialEq, Eq)]
 /// A [`node_announcement`] message to be sent to or received from a peer.
@@ -1203,8 +1244,11 @@ pub struct UnsignedChannelUpdate {
        pub short_channel_id: u64,
        /// A strictly monotonic announcement counter, with gaps allowed, specific to this channel
        pub timestamp: u32,
-       /// Channel flags
-       pub flags: u8,
+       /// Flags pertaining to this message.
+       pub message_flags: u8,
+       /// Flags pertaining to the channel, including to which direction in the channel this update
+       /// applies and whether the direction is currently able to forward HTLCs.
+       pub channel_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
@@ -1437,11 +1481,14 @@ pub trait ChannelMessageHandler : MessageSendEventsProvider {
        fn handle_stfu(&self, their_node_id: &PublicKey, msg: &Stfu);
 
        // Splicing
-       /// Handle an incoming `splice` message from the given peer.
-       fn handle_splice(&self, their_node_id: &PublicKey, msg: &Splice);
+       /// Handle an incoming `splice_init` message from the given peer.
+       #[cfg(splicing)]
+       fn handle_splice_init(&self, their_node_id: &PublicKey, msg: &SpliceInit);
        /// Handle an incoming `splice_ack` message from the given peer.
+       #[cfg(splicing)]
        fn handle_splice_ack(&self, their_node_id: &PublicKey, msg: &SpliceAck);
        /// Handle an incoming `splice_locked` message from the given peer.
+       #[cfg(splicing)]
        fn handle_splice_locked(&self, their_node_id: &PublicKey, msg: &SpliceLocked);
 
        // Interactive channel construction
@@ -1596,7 +1643,7 @@ pub trait RoutingMessageHandler : MessageSendEventsProvider {
 }
 
 /// A handler for received [`OnionMessage`]s and for providing generated ones to send.
-pub trait OnionMessageHandler: EventsProvider {
+pub trait OnionMessageHandler {
        /// Handle an incoming `onion_message` message from the given peer.
        fn handle_onion_message(&self, peer_node_id: &PublicKey, msg: &OnionMessage);
 
@@ -1650,11 +1697,13 @@ pub struct FinalOnionHopData {
 
 mod fuzzy_internal_msgs {
        use bitcoin::secp256k1::PublicKey;
-       use crate::blinded_path::payment::{PaymentConstraints, PaymentRelay};
-       use crate::prelude::*;
-       use crate::ln::{PaymentPreimage, PaymentSecret};
+       use crate::blinded_path::payment::{PaymentConstraints, PaymentContext, PaymentRelay};
+       use crate::ln::types::{PaymentPreimage, PaymentSecret};
        use crate::ln::features::BlindedHopFeatures;
-       use super::FinalOnionHopData;
+       use super::{FinalOnionHopData, TrampolineOnionPacket};
+
+       #[allow(unused_imports)]
+       use crate::prelude::*;
 
        // These types aren't intended to be pub, but are exposed for direct fuzzing (as we deserialize
        // them from untrusted input):
@@ -1687,35 +1736,58 @@ mod fuzzy_internal_msgs {
                        cltv_expiry_height: u32,
                        payment_secret: PaymentSecret,
                        payment_constraints: PaymentConstraints,
+                       payment_context: PaymentContext,
                        intro_node_blinding_point: Option<PublicKey>,
+                       keysend_preimage: Option<PaymentPreimage>,
+                       custom_tlvs: Vec<(u64, Vec<u8>)>,
                }
        }
 
-       pub(crate) enum OutboundOnionPayload {
+       pub(crate) enum OutboundOnionPayload<'a> {
                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,
                },
+               #[allow(unused)]
+               TrampolineEntrypoint {
+                       amt_to_forward: u64,
+                       outgoing_cltv_value: u32,
+                       multipath_trampoline_data: Option<FinalOnionHopData>,
+                       trampoline_packet: TrampolineOnionPacket,
+               },
                Receive {
                        payment_data: Option<FinalOnionHopData>,
-                       payment_metadata: Option<Vec<u8>>,
+                       payment_metadata: Option<&'a Vec<u8>>,
                        keysend_preimage: Option<PaymentPreimage>,
-                       custom_tlvs: Vec<(u64, Vec<u8>)>,
+                       custom_tlvs: &'a Vec<(u64, Vec<u8>)>,
                        sender_intended_htlc_amt_msat: u64,
                        cltv_expiry_height: u32,
                },
                BlindedForward {
-                       encrypted_tlvs: Vec<u8>,
+                       encrypted_tlvs: &'a Vec<u8>,
                        intro_node_blinding_point: Option<PublicKey>,
                },
                BlindedReceive {
                        sender_intended_htlc_amt_msat: u64,
                        total_msat: u64,
                        cltv_expiry_height: u32,
-                       encrypted_tlvs: Vec<u8>,
+                       encrypted_tlvs: &'a Vec<u8>,
                        intro_node_blinding_point: Option<PublicKey>, // Set if the introduction node of the blinded path is the final node
+                       keysend_preimage: Option<PaymentPreimage>,
+                       custom_tlvs: &'a Vec<(u64, Vec<u8>)>,
+               }
+       }
+
+       pub(crate) enum OutboundTrampolinePayload {
+               #[allow(unused)]
+               Forward {
+                       /// The value, in msat, of the payment after this hop's fee is deducted.
+                       amt_to_forward: u64,
+                       outgoing_cltv_value: u32,
+                       /// The node id to which the trampoline node must find a route
+                       outgoing_node_id: PublicKey,
                }
        }
 
@@ -1777,7 +1849,7 @@ pub struct TrampolineOnionPacket {
        // Unlike the onion packets used for payments, Trampoline onion packets have to be shorter than
        // 1300 bytes. The expected default is 650 bytes.
        // TODO: if 650 ends up being the most common size, optimize this to be:
-       // enum { ThirteenHundred([u8; 650]), VarLen(Vec<u8>) }
+       // enum { SixFifty([u8; 650]), VarLen(Vec<u8>) }
        pub hop_data: Vec<u8>,
        /// HMAC to verify the integrity of hop_data
        pub hmac: [u8; 32],
@@ -1805,6 +1877,26 @@ impl Writeable for TrampolineOnionPacket {
        }
 }
 
+impl LengthReadable for TrampolineOnionPacket {
+       fn read<R: LengthRead>(r: &mut R) -> Result<Self, DecodeError> {
+               let version = Readable::read(r)?;
+               let public_key = Readable::read(r)?;
+
+               let hop_data_len = r.total_bytes().saturating_sub(66); // 1 (version) + 33 (pubkey) + 32 (HMAC) = 66
+               let mut rd = FixedLengthReader::new(r, hop_data_len);
+               let hop_data = WithoutLength::<Vec<u8>>::read(&mut rd)?.0;
+
+               let hmac = Readable::read(r)?;
+
+               Ok(TrampolineOnionPacket {
+                       version,
+                       public_key,
+                       hop_data,
+                       hmac,
+               })
+       }
+}
+
 impl Debug for TrampolineOnionPacket {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                f.write_fmt(format_args!("TrampolineOnionPacket version {} with hmac {:?}", self.version, &self.hmac[..]))
@@ -1828,6 +1920,7 @@ impl fmt::Display for DecodeError {
                        DecodeError::BadLengthDescriptor => f.write_str("A length descriptor in the packet didn't describe the later data correctly"),
                        DecodeError::Io(ref e) => fmt::Debug::fmt(e, f),
                        DecodeError::UnsupportedCompression => f.write_str("We don't support receiving messages with zlib-compressed fields"),
+                       DecodeError::DangerousValue => f.write_str("Value would be dangerous to continue execution with"),
                }
        }
 }
@@ -2015,24 +2108,27 @@ impl_writeable_msg!(Stfu, {
        initiator,
 }, {});
 
-impl_writeable_msg!(Splice, {
+impl_writeable_msg!(SpliceInit, {
        channel_id,
-       chain_hash,
-       relative_satoshis,
+       funding_contribution_satoshis,
        funding_feerate_perkw,
        locktime,
        funding_pubkey,
-}, {});
+}, {
+       (2, require_confirmed_inputs, option), // `splice_init_tlvs`
+});
 
 impl_writeable_msg!(SpliceAck, {
        channel_id,
-       chain_hash,
-       relative_satoshis,
+       funding_contribution_satoshis,
        funding_pubkey,
-}, {});
+}, {
+       (2, require_confirmed_inputs, option), // `splice_ack_tlvs`
+});
 
 impl_writeable_msg!(SpliceLocked, {
        channel_id,
+       splice_txid,
 }, {});
 
 impl_writeable_msg!(TxAddInput, {
@@ -2041,7 +2137,9 @@ impl_writeable_msg!(TxAddInput, {
        prevtx,
        prevtx_out,
        sequence,
-}, {});
+}, {
+       (0, shared_input_txid, option), // `funding_txid`
+});
 
 impl_writeable_msg!(TxAddOutput, {
        channel_id,
@@ -2068,7 +2166,9 @@ impl_writeable_msg!(TxSignatures, {
        channel_id,
        tx_hash,
        witnesses,
-}, {});
+}, {
+       (0, shared_input_signature, option), // `signature`
+});
 
 impl_writeable_msg!(TxInitRbf, {
        channel_id,
@@ -2116,12 +2216,19 @@ impl_writeable!(ClosingSignedFeeRange, {
        max_fee_satoshis
 });
 
+impl_writeable_msg!(CommitmentSignedBatch, {
+       batch_size,
+       funding_txid,
+}, {});
+
 #[cfg(not(taproot))]
 impl_writeable_msg!(CommitmentSigned, {
        channel_id,
        signature,
        htlc_signatures
-}, {});
+}, {
+       (0, batch, option),
+});
 
 #[cfg(taproot)]
 impl_writeable_msg!(CommitmentSigned, {
@@ -2129,7 +2236,8 @@ impl_writeable_msg!(CommitmentSigned, {
        signature,
        htlc_signatures
 }, {
-       (2, partial_signature_with_nonce, option)
+       (0, batch, option),
+       (2, partial_signature_with_nonce, option),
 });
 
 impl_writeable!(DecodedOnionErrorPacket, {
@@ -2514,7 +2622,7 @@ impl Readable for FinalOnionHopData {
        }
 }
 
-impl Writeable for OutboundOnionPayload {
+impl<'a> Writeable for OutboundOnionPayload<'a> {
        fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
                match self {
                        Self::Forward { short_channel_id, amt_to_forward, outgoing_cltv_value } => {
@@ -2524,6 +2632,17 @@ impl Writeable for OutboundOnionPayload {
                                        (6, short_channel_id, required)
                                });
                        },
+                       Self::TrampolineEntrypoint {
+                               amt_to_forward, outgoing_cltv_value, ref multipath_trampoline_data,
+                               ref trampoline_packet
+                       } => {
+                               _encode_varint_length_prefixed_tlv!(w, {
+                                       (2, HighZeroBytesDroppedBigSize(*amt_to_forward), required),
+                                       (4, HighZeroBytesDroppedBigSize(*outgoing_cltv_value), required),
+                                       (8, multipath_trampoline_data, option),
+                                       (20, trampoline_packet, required)
+                               });
+                       },
                        Self::Receive {
                                ref payment_data, ref payment_metadata, ref keysend_preimage, sender_intended_htlc_amt_msat,
                                cltv_expiry_height, ref custom_tlvs,
@@ -2538,32 +2657,54 @@ impl Writeable for OutboundOnionPayload {
                                        (2, HighZeroBytesDroppedBigSize(*sender_intended_htlc_amt_msat), required),
                                        (4, HighZeroBytesDroppedBigSize(*cltv_expiry_height), required),
                                        (8, payment_data, option),
-                                       (16, payment_metadata.as_ref().map(|m| WithoutLength(m)), option)
+                                       (16, payment_metadata.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),
+                                       (10, **encrypted_tlvs, required_vec),
                                        (12, intro_node_blinding_point, option)
                                });
                        },
                        Self::BlindedReceive {
                                sender_intended_htlc_amt_msat, total_msat, cltv_expiry_height, encrypted_tlvs,
-                               intro_node_blinding_point,
+                               intro_node_blinding_point, keysend_preimage, 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(*sender_intended_htlc_amt_msat), required),
                                        (4, HighZeroBytesDroppedBigSize(*cltv_expiry_height), required),
-                                       (10, *encrypted_tlvs, required_vec),
+                                       (10, **encrypted_tlvs, required_vec),
                                        (12, intro_node_blinding_point, option),
                                        (18, HighZeroBytesDroppedBigSize(*total_msat), required)
-                               });
+                               }, custom_tlvs.iter());
                        },
                }
                Ok(())
        }
 }
 
+impl Writeable for OutboundTrampolinePayload {
+       fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
+               match self {
+                       Self::Forward { amt_to_forward, outgoing_cltv_value, outgoing_node_id } => {
+                               _encode_varint_length_prefixed_tlv!(w, {
+                                       (2, HighZeroBytesDroppedBigSize(*amt_to_forward), required),
+                                       (4, HighZeroBytesDroppedBigSize(*outgoing_cltv_value), required),
+                                       (14, outgoing_node_id, required)
+                               });
+                       }
+               }
+               Ok(())
+       }
+}
+
+
 impl<NS: Deref> ReadableArgs<(Option<PublicKey>, &NS)> for InboundOnionPayload where NS::Target: NodeSigner {
        fn read<R: Read>(r: &mut R, args: (Option<PublicKey>, &NS)) -> Result<Self, DecodeError> {
                let (update_add_blinding_point, node_signer) = args;
@@ -2606,9 +2747,7 @@ impl<NS: Deref> ReadableArgs<(Option<PublicKey>, &NS)> for InboundOnionPayload w
                }
 
                if let Some(blinding_point) = intro_node_blinding_point.or(update_add_blinding_point) {
-                       if short_id.is_some() || payment_data.is_some() || payment_metadata.is_some() ||
-                               keysend_preimage.is_some()
-                       {
+                       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;
@@ -2621,7 +2760,9 @@ impl<NS: Deref> ReadableArgs<(Option<PublicKey>, &NS)> for InboundOnionPayload w
                                ChaChaPolyReadAdapter { readable: BlindedPaymentTlvs::Forward(ForwardTlvs {
                                        short_channel_id, payment_relay, payment_constraints, features
                                })} => {
-                                       if amt.is_some() || cltv_value.is_some() || total_msat.is_some() {
+                                       if amt.is_some() || cltv_value.is_some() || total_msat.is_some() ||
+                                               keysend_preimage.is_some()
+                                       {
                                                return Err(DecodeError::InvalidValue)
                                        }
                                        Ok(Self::BlindedForward {
@@ -2633,7 +2774,7 @@ impl<NS: Deref> ReadableArgs<(Option<PublicKey>, &NS)> for InboundOnionPayload w
                                        })
                                },
                                ChaChaPolyReadAdapter { readable: BlindedPaymentTlvs::Receive(ReceiveTlvs {
-                                       payment_secret, payment_constraints
+                                       payment_secret, payment_constraints, payment_context
                                })} => {
                                        if total_msat.unwrap_or(0) > MAX_VALUE_MSAT { return Err(DecodeError::InvalidValue) }
                                        Ok(Self::BlindedReceive {
@@ -2642,7 +2783,10 @@ impl<NS: Deref> ReadableArgs<(Option<PublicKey>, &NS)> for InboundOnionPayload w
                                                cltv_expiry_height: cltv_value.ok_or(DecodeError::InvalidValue)?,
                                                payment_secret,
                                                payment_constraints,
+                                               payment_context,
                                                intro_node_blinding_point,
+                                               keysend_preimage,
+                                               custom_tlvs,
                                        })
                                },
                        }
@@ -2755,13 +2899,13 @@ impl_writeable!(ChannelAnnouncement, {
 
 impl Writeable for UnsignedChannelUpdate {
        fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
-               // `message_flags` used to indicate presence of `htlc_maximum_msat`, but was deprecated in the spec.
-               const MESSAGE_FLAGS: u8 = 1;
                self.chain_hash.write(w)?;
                self.short_channel_id.write(w)?;
                self.timestamp.write(w)?;
-               let all_flags = self.flags as u16 | ((MESSAGE_FLAGS as u16) << 8);
-               all_flags.write(w)?;
+               // Thw low bit of message_flags used to indicate the presence of `htlc_maximum_msat`, and
+               // now must be set
+               (self.message_flags | 1).write(w)?;
+               self.channel_flags.write(w)?;
                self.cltv_expiry_delta.write(w)?;
                self.htlc_minimum_msat.write(w)?;
                self.fee_base_msat.write(w)?;
@@ -2774,22 +2918,26 @@ impl Writeable for UnsignedChannelUpdate {
 
 impl Readable for UnsignedChannelUpdate {
        fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
-               Ok(Self {
+               let res = Self {
                        chain_hash: Readable::read(r)?,
                        short_channel_id: Readable::read(r)?,
                        timestamp: Readable::read(r)?,
-                       flags: {
-                               let flags: u16 = Readable::read(r)?;
-                               // Note: we ignore the `message_flags` for now, since it was deprecated by the spec.
-                               flags as u8
-                       },
+                       message_flags: Readable::read(r)?,
+                       channel_flags: Readable::read(r)?,
                        cltv_expiry_delta: Readable::read(r)?,
                        htlc_minimum_msat: Readable::read(r)?,
                        fee_base_msat: Readable::read(r)?,
                        fee_proportional_millionths: Readable::read(r)?,
                        htlc_maximum_msat: Readable::read(r)?,
                        excess_data: read_to_end(r)?,
-               })
+               };
+               if res.message_flags & 1 != 1 {
+                       // The `must_be_one` flag should be set (historically it indicated the presence of the
+                       // `htlc_maximum_msat` field, which is now required).
+                       Err(DecodeError::InvalidValue)
+               } else {
+                       Ok(res)
+               }
        }
 }
 
@@ -3083,26 +3231,25 @@ impl_writeable_msg!(GossipTimestampFilter, {
 
 #[cfg(test)]
 mod tests {
-       use std::convert::TryFrom;
-       use bitcoin::{Transaction, TxIn, ScriptBuf, Sequence, Witness, TxOut};
+       use bitcoin::{Amount, Transaction, TxIn, ScriptBuf, Sequence, Witness, TxOut};
        use hex::DisplayHex;
-       use crate::ln::{PaymentPreimage, PaymentHash, PaymentSecret};
-       use crate::ln::ChannelId;
+       use crate::ln::types::{ChannelId, PaymentPreimage, PaymentHash, PaymentSecret};
        use crate::ln::features::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, NodeFeatures};
-       use crate::ln::msgs::{self, FinalOnionHopData, OnionErrorPacket, CommonOpenChannelFields, CommonAcceptChannelFields};
+       use crate::ln::msgs::{self, FinalOnionHopData, OnionErrorPacket, CommonOpenChannelFields, CommonAcceptChannelFields, TrampolineOnionPacket};
        use crate::ln::msgs::SocketAddress;
        use crate::routing::gossip::{NodeAlias, NodeId};
-       use crate::util::ser::{Writeable, Readable, ReadableArgs, Hostname, TransactionU16LenLimited};
+       use crate::util::ser::{BigSize, FixedLengthReader, Hostname, LengthReadable, Readable, ReadableArgs, TransactionU16LenLimited, Writeable};
        use crate::util::test_utils;
 
        use bitcoin::hashes::hex::FromHex;
        use bitcoin::address::Address;
-       use bitcoin::network::constants::Network;
+       use bitcoin::network::Network;
        use bitcoin::blockdata::constants::ChainHash;
        use bitcoin::blockdata::script::Builder;
        use bitcoin::blockdata::opcodes;
        use bitcoin::hash_types::Txid;
        use bitcoin::locktime::absolute::LockTime;
+       use bitcoin::transaction::Version;
 
        use bitcoin::secp256k1::{PublicKey,SecretKey};
        use bitcoin::secp256k1::{Secp256k1, Message};
@@ -3193,7 +3340,7 @@ mod tests {
        macro_rules! get_sig_on {
                ($privkey: expr, $ctx: expr, $string: expr) => {
                        {
-                               let sighash = Message::from_slice(&$string.into_bytes()[..]).unwrap();
+                               let sighash = Message::from_digest_slice(&$string.into_bytes()[..]).unwrap();
                                $ctx.sign_ecdsa(&sighash, &$privkey)
                        }
                }
@@ -3386,7 +3533,8 @@ mod tests {
                        chain_hash: ChainHash::using_genesis_block(Network::Bitcoin),
                        short_channel_id: 2316138423780173,
                        timestamp: 20190119,
-                       flags: if direction { 1 } else { 0 } | if disable { 1 << 1 } else { 0 },
+                       message_flags: 1, // Only must_be_one
+                       channel_flags: if direction { 1 } else { 0 } | if disable { 1 << 1 } else { 0 },
                        cltv_expiry_delta: 144,
                        htlc_minimum_msat: 1000000,
                        htlc_maximum_msat: 131355275467161,
@@ -3741,19 +3889,19 @@ mod tests {
        }
 
        #[test]
-       fn encoding_splice() {
+       fn encoding_splice_init() {
                let secp_ctx = Secp256k1::new();
                let (_, pubkey_1,) = get_keys_from!("0101010101010101010101010101010101010101010101010101010101010101", secp_ctx);
-               let splice = msgs::Splice {
-                       chain_hash: ChainHash::from_hex("6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000").unwrap(),
+               let splice_init = msgs::SpliceInit {
                        channel_id: ChannelId::from_bytes([2; 32]),
-                       relative_satoshis: 123456,
+                       funding_contribution_satoshis: -123456,
                        funding_feerate_perkw: 2000,
                        locktime: 0,
                        funding_pubkey: pubkey_1,
+                       require_confirmed_inputs: Some(()),
                };
-               let encoded_value = splice.encode();
-               assert_eq!(encoded_value.as_hex().to_string(), "02020202020202020202020202020202020202020202020202020202020202026fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000000000000001e240000007d000000000031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f");
+               let encoded_value = splice_init.encode();
+               assert_eq!(encoded_value.as_hex().to_string(), "0202020202020202020202020202020202020202020202020202020202020202fffffffffffe1dc0000007d000000000031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f0200");
        }
 
        #[test]
@@ -3770,23 +3918,24 @@ mod tests {
        fn encoding_splice_ack() {
                let secp_ctx = Secp256k1::new();
                let (_, pubkey_1,) = get_keys_from!("0101010101010101010101010101010101010101010101010101010101010101", secp_ctx);
-               let splice = msgs::SpliceAck {
-                       chain_hash: ChainHash::from_hex("6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000").unwrap(),
+               let splice_ack = msgs::SpliceAck {
                        channel_id: ChannelId::from_bytes([2; 32]),
-                       relative_satoshis: 123456,
+                       funding_contribution_satoshis: -123456,
                        funding_pubkey: pubkey_1,
+                       require_confirmed_inputs: Some(()),
                };
-               let encoded_value = splice.encode();
-               assert_eq!(encoded_value.as_hex().to_string(), "02020202020202020202020202020202020202020202020202020202020202026fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000000000000001e240031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f");
+               let encoded_value = splice_ack.encode();
+               assert_eq!(encoded_value.as_hex().to_string(), "0202020202020202020202020202020202020202020202020202020202020202fffffffffffe1dc0031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f0200");
        }
 
        #[test]
        fn encoding_splice_locked() {
-               let splice = msgs::SpliceLocked {
+               let splice_locked = msgs::SpliceLocked {
                        channel_id: ChannelId::from_bytes([2; 32]),
+                       splice_txid: Txid::from_str("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap(),
                };
-               let encoded_value = splice.encode();
-               assert_eq!(encoded_value.as_hex().to_string(), "0202020202020202020202020202020202020202020202020202020202020202");
+               let encoded_value = splice_locked.encode();
+               assert_eq!(encoded_value.as_hex().to_string(), "02020202020202020202020202020202020202020202020202020202020202026e96fe9f8b0ddcd729ba03cfafa5a27b050b39d354dd980814268dfa9a44d4c2");
        }
 
        #[test]
@@ -3795,7 +3944,7 @@ mod tests {
                        channel_id: ChannelId::from_bytes([2; 32]),
                        serial_id: 4886718345,
                        prevtx: TransactionU16LenLimited::new(Transaction {
-                               version: 2,
+                               version: Version::TWO,
                                lock_time: LockTime::ZERO,
                                input: vec![TxIn {
                                        previous_output: OutPoint { txid: Txid::from_str("305bab643ee297b8b6b76b320792c8223d55082122cb606bf89382146ced9c77").unwrap(), index: 2 }.into_bitcoin_outpoint(),
@@ -3807,21 +3956,22 @@ mod tests {
                                }],
                                output: vec![
                                        TxOut {
-                                               value: 12704566,
-                                               script_pubkey: Address::from_str("bc1qzlffunw52jav8vwdu5x3jfk6sr8u22rmq3xzw2").unwrap().payload.script_pubkey(),
+                                               value: Amount::from_sat(12704566),
+                                               script_pubkey: Address::from_str("bc1qzlffunw52jav8vwdu5x3jfk6sr8u22rmq3xzw2").unwrap().payload().script_pubkey(),
                                        },
                                        TxOut {
-                                               value: 245148,
-                                               script_pubkey: Address::from_str("bc1qxmk834g5marzm227dgqvynd23y2nvt2ztwcw2z").unwrap().payload.script_pubkey(),
+                                               value: Amount::from_sat(245148),
+                                               script_pubkey: Address::from_str("bc1qxmk834g5marzm227dgqvynd23y2nvt2ztwcw2z").unwrap().payload().script_pubkey(),
                                        },
                                ],
                        }).unwrap(),
                        prevtx_out: 305419896,
                        sequence: 305419896,
+                       shared_input_txid: Some(Txid::from_str("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap()),
                };
                let encoded_value = tx_add_input.encode();
-               let target_value = <Vec<u8>>::from_hex("0202020202020202020202020202020202020202020202020202020202020202000000012345678900de02000000000101779ced6c148293f86b60cb222108553d22c89207326bb7b6b897e23e64ab5b300200000000fdffffff0236dbc1000000000016001417d29e4dd454bac3b1cde50d1926da80cfc5287b9cbd03000000000016001436ec78d514df462da95e6a00c24daa8915362d420247304402206af85b7dd67450ad12c979302fac49dfacbc6a8620f49c5da2b5721cf9565ca502207002b32fed9ce1bf095f57aeb10c36928ac60b12e723d97d2964a54640ceefa701210301ab7dc16488303549bfcdd80f6ae5ee4c20bf97ab5410bbd6b1bfa85dcd6944000000001234567812345678").unwrap();
-               assert_eq!(encoded_value, target_value);
+               let target_value = "0202020202020202020202020202020202020202020202020202020202020202000000012345678900de02000000000101779ced6c148293f86b60cb222108553d22c89207326bb7b6b897e23e64ab5b300200000000fdffffff0236dbc1000000000016001417d29e4dd454bac3b1cde50d1926da80cfc5287b9cbd03000000000016001436ec78d514df462da95e6a00c24daa8915362d420247304402206af85b7dd67450ad12c979302fac49dfacbc6a8620f49c5da2b5721cf9565ca502207002b32fed9ce1bf095f57aeb10c36928ac60b12e723d97d2964a54640ceefa701210301ab7dc16488303549bfcdd80f6ae5ee4c20bf97ab5410bbd6b1bfa85dcd694400000000123456781234567800206e96fe9f8b0ddcd729ba03cfafa5a27b050b39d354dd980814268dfa9a44d4c2";
+               assert_eq!(encoded_value.as_hex().to_string(), target_value);
        }
 
        #[test]
@@ -3830,7 +3980,7 @@ mod tests {
                        channel_id: ChannelId::from_bytes([2; 32]),
                        serial_id: 4886718345,
                        sats: 4886718345,
-                       script: Address::from_str("bc1qxmk834g5marzm227dgqvynd23y2nvt2ztwcw2z").unwrap().payload.script_pubkey(),
+                       script: Address::from_str("bc1qxmk834g5marzm227dgqvynd23y2nvt2ztwcw2z").unwrap().payload().script_pubkey(),
                };
                let encoded_value = tx_add_output.encode();
                let target_value = <Vec<u8>>::from_hex("0202020202020202020202020202020202020202020202020202020202020202000000012345678900000001234567890016001436ec78d514df462da95e6a00c24daa8915362d42").unwrap();
@@ -3871,6 +4021,10 @@ mod tests {
 
        #[test]
        fn encoding_tx_signatures() {
+               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 tx_signatures = msgs::TxSignatures {
                        channel_id: ChannelId::from_bytes([2; 32]),
                        tx_hash: Txid::from_str("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap(),
@@ -3882,6 +4036,7 @@ mod tests {
                                        <Vec<u8>>::from_hex("3045022100ee00dbf4a862463e837d7c08509de814d620e4d9830fa84818713e0fa358f145022021c3c7060c4d53fe84fd165d60208451108a778c13b92ca4c6bad439236126cc01").unwrap(),
                                        <Vec<u8>>::from_hex("028fbbf0b16f5ba5bcb5dd37cd4047ce6f726a21c06682f9ec2f52b057de1dbdb5").unwrap()]),
                        ],
+                       shared_input_signature: Some(sig_1),
                };
                let encoded_value = tx_signatures.encode();
                let mut target_value = <Vec<u8>>::from_hex("0202020202020202020202020202020202020202020202020202020202020202").unwrap(); // channel_id
@@ -3901,6 +4056,8 @@ mod tests {
                target_value.append(&mut <Vec<u8>>::from_hex("3045022100ee00dbf4a862463e837d7c08509de814d620e4d9830fa84818713e0fa358f145022021c3c7060c4d53fe84fd165d60208451108a778c13b92ca4c6bad439236126cc01").unwrap());
                target_value.append(&mut <Vec<u8>>::from_hex("21").unwrap()); // len of witness element data (VarInt)
                target_value.append(&mut <Vec<u8>>::from_hex("028fbbf0b16f5ba5bcb5dd37cd4047ce6f726a21c06682f9ec2f52b057de1dbdb5").unwrap());
+               target_value.append(&mut <Vec<u8>>::from_hex("0040").unwrap()); // type and len (64)
+               target_value.append(&mut <Vec<u8>>::from_hex("d977cb9b53d93a6ff64bb5f1e158b4094b66e798fb12911168a3ccdf80a83096340a6a95da0ae8d9f776528eecdbb747eb6b545495a4319ed5378e35b21e073a").unwrap());
                assert_eq!(encoded_value, target_value);
        }
 
@@ -4108,17 +4265,19 @@ mod tests {
                        channel_id: ChannelId::from_bytes([2; 32]),
                        signature: sig_1,
                        htlc_signatures: if htlcs { vec![sig_2, sig_3, sig_4] } else { Vec::new() },
+                       batch: Some(msgs::CommitmentSignedBatch { batch_size: 3, funding_txid: Txid::from_str("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap() }),
                        #[cfg(taproot)]
                        partial_signature_with_nonce: None,
                };
                let encoded_value = commitment_signed.encode();
-               let mut target_value = <Vec<u8>>::from_hex("0202020202020202020202020202020202020202020202020202020202020202d977cb9b53d93a6ff64bb5f1e158b4094b66e798fb12911168a3ccdf80a83096340a6a95da0ae8d9f776528eecdbb747eb6b545495a4319ed5378e35b21e073a").unwrap();
+               let mut target_value = "0202020202020202020202020202020202020202020202020202020202020202d977cb9b53d93a6ff64bb5f1e158b4094b66e798fb12911168a3ccdf80a83096340a6a95da0ae8d9f776528eecdbb747eb6b545495a4319ed5378e35b21e073a".to_string();
                if htlcs {
-                       target_value.append(&mut <Vec<u8>>::from_hex("00031735b6a427e80d5fe7cd90a2f4ee08dc9c27cda7c35a4172e5d85b12c49d4232537e98f9b1f3c5e6989a8b9644e90e8918127680dbd0d4043510840fc0f1e11a216c280b5395a2546e7e4b2663e04f811622f15a4f91e83aa2e92ba2a573c139142c54ae63072a1ec1ee7dc0c04bde5c847806172aa05c92c22ae8e308d1d2692b12cc195ce0a2d1bda6a88befa19fa07f51caa75ce83837f28965600b8aacab0855ffb0e741ec5f7c41421e9829a9d48611c8c831f71be5ea73e66594977ffd").unwrap());
+                       target_value += "00031735b6a427e80d5fe7cd90a2f4ee08dc9c27cda7c35a4172e5d85b12c49d4232537e98f9b1f3c5e6989a8b9644e90e8918127680dbd0d4043510840fc0f1e11a216c280b5395a2546e7e4b2663e04f811622f15a4f91e83aa2e92ba2a573c139142c54ae63072a1ec1ee7dc0c04bde5c847806172aa05c92c22ae8e308d1d2692b12cc195ce0a2d1bda6a88befa19fa07f51caa75ce83837f28965600b8aacab0855ffb0e741ec5f7c41421e9829a9d48611c8c831f71be5ea73e66594977ffd";
                } else {
-                       target_value.append(&mut <Vec<u8>>::from_hex("0000").unwrap());
+                       target_value += "0000";
                }
-               assert_eq!(encoded_value, target_value);
+               target_value += "002200036e96fe9f8b0ddcd729ba03cfafa5a27b050b39d354dd980814268dfa9a44d4c2"; // batch
+               assert_eq!(encoded_value.as_hex().to_string(), target_value);
        }
 
        #[test]
@@ -4263,7 +4422,7 @@ mod tests {
                        keysend_preimage: None,
                        sender_intended_htlc_amt_msat: 0x0badf00d01020304,
                        cltv_expiry_height: 0xffffffff,
-                       custom_tlvs: vec![],
+                       custom_tlvs: &vec![],
                };
                let encoded_value = outbound_msg.encode();
                let target_value = <Vec<u8>>::from_hex("1002080badf00d010203040404ffffffff").unwrap();
@@ -4291,7 +4450,7 @@ mod tests {
                        keysend_preimage: None,
                        sender_intended_htlc_amt_msat: 0x0badf00d01020304,
                        cltv_expiry_height: 0xffffffff,
-                       custom_tlvs: vec![],
+                       custom_tlvs: &vec![],
                };
                let encoded_value = outbound_msg.encode();
                let target_value = <Vec<u8>>::from_hex("3602080badf00d010203040404ffffffff082442424242424242424242424242424242424242424242424242424242424242421badca1f").unwrap();
@@ -4328,7 +4487,7 @@ mod tests {
                        payment_data: None,
                        payment_metadata: None,
                        keysend_preimage: None,
-                       custom_tlvs: bad_type_range_tlvs,
+                       custom_tlvs: &bad_type_range_tlvs,
                        sender_intended_htlc_amt_msat: 0x0badf00d01020304,
                        cltv_expiry_height: 0xffffffff,
                };
@@ -4340,7 +4499,7 @@ mod tests {
                        ((1 << 16) - 1, vec![42; 32]),
                ];
                if let msgs::OutboundOnionPayload::Receive { ref mut custom_tlvs, .. } = msg {
-                       *custom_tlvs = good_type_range_tlvs.clone();
+                       *custom_tlvs = &good_type_range_tlvs;
                }
                let encoded_value = msg.encode();
                let inbound_msg = ReadableArgs::read(&mut Cursor::new(&encoded_value[..]), (None, &&node_signer)).unwrap();
@@ -4360,7 +4519,7 @@ mod tests {
                        payment_data: None,
                        payment_metadata: None,
                        keysend_preimage: None,
-                       custom_tlvs: expected_custom_tlvs.clone(),
+                       custom_tlvs: &expected_custom_tlvs,
                        sender_intended_htlc_amt_msat: 0x0badf00d01020304,
                        cltv_expiry_height: 0xffffffff,
                };
@@ -4384,6 +4543,71 @@ mod tests {
                } else { panic!(); }
        }
 
+       #[test]
+       fn encoding_final_onion_hop_data_with_trampoline_packet() {
+               let secp_ctx = Secp256k1::new();
+               let (_private_key, public_key) = get_keys_from!("0101010101010101010101010101010101010101010101010101010101010101", secp_ctx);
+
+               let compressed_public_key = public_key.serialize();
+               assert_eq!(compressed_public_key.len(), 33);
+
+               let trampoline_packet = TrampolineOnionPacket {
+                       version: 0,
+                       public_key,
+                       hop_data: vec![1; 650], // this should be the standard encoded length
+                       hmac: [2; 32],
+               };
+               let encoded_trampoline_packet = trampoline_packet.encode();
+               assert_eq!(encoded_trampoline_packet.len(), 716);
+
+               { // verify that a codec round trip works
+                       let mut reader = Cursor::new(&encoded_trampoline_packet);
+                       let mut trampoline_packet_reader = FixedLengthReader::new(&mut reader, encoded_trampoline_packet.len() as u64);
+                       let decoded_trampoline_packet: TrampolineOnionPacket = <TrampolineOnionPacket as LengthReadable>::read(&mut trampoline_packet_reader).unwrap();
+                       assert_eq!(decoded_trampoline_packet.encode(), encoded_trampoline_packet);
+               }
+
+               let msg = msgs::OutboundOnionPayload::TrampolineEntrypoint {
+                       multipath_trampoline_data: None,
+                       amt_to_forward: 0x0badf00d01020304,
+                       outgoing_cltv_value: 0xffffffff,
+                       trampoline_packet,
+               };
+               let encoded_payload = msg.encode();
+
+               let trampoline_type_bytes = &encoded_payload[19..=19];
+               let mut trampoline_type_cursor = Cursor::new(trampoline_type_bytes);
+               let trampoline_type_big_size: BigSize = Readable::read(&mut trampoline_type_cursor).unwrap();
+               assert_eq!(trampoline_type_big_size.0, 20);
+
+               let trampoline_length_bytes = &encoded_payload[20..=22];
+               let mut trampoline_length_cursor = Cursor::new(trampoline_length_bytes);
+               let trampoline_length_big_size: BigSize = Readable::read(&mut trampoline_length_cursor).unwrap();
+               assert_eq!(trampoline_length_big_size.0, encoded_trampoline_packet.len() as u64);
+       }
+
+       #[test]
+       fn encoding_final_onion_hop_data_with_eclair_trampoline_packet() {
+               let public_key = PublicKey::from_slice(&<Vec<u8>>::from_hex("02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619").unwrap()).unwrap();
+               let hop_data = <Vec<u8>>::from_hex("cff34152f3a36e52ca94e74927203a560392b9cc7ce3c45809c6be52166c24a595716880f95f178bf5b30ca63141f74db6e92795c6130877cfdac3d4bd3087ee73c65d627ddd709112a848cc99e303f3706509aa43ba7c8a88cba175fccf9a8f5016ef06d3b935dbb15196d7ce16dc1a7157845566901d7b2197e52cab4ce487014b14816e5805f9fcacb4f8f88b8ff176f1b94f6ce6b00bc43221130c17d20ef629db7c5f7eafaa166578c720619561dd14b3277db557ec7dcdb793771aef0f2f667cfdbeae3ac8d331c5994779dffb31e5fc0dbdedc0c592ca6d21c18e47fe3528d6975c19517d7e2ea8c5391cf17d0fe30c80913ed887234ccb48808f7ef9425bcd815c3b586210979e3bb286ef2851bf9ce04e28c40a203df98fd648d2f1936fd2f1def0e77eecb277229b4b682322371c0a1dbfcd723a991993df8cc1f2696b84b055b40a1792a29f710295a18fbd351b0f3ff34cd13941131b8278ba79303c89117120eea691738a9954908195143b039dbeed98f26a92585f3d15cf742c953799d3272e0545e9b744be9d3b4c").unwrap();
+               let hmac_vector = <Vec<u8>>::from_hex("bb079bfc4b35190eee9f59a1d7b41ba2f773179f322dafb4b1af900c289ebd6c").unwrap();
+               let mut hmac = [0; 32];
+               hmac.copy_from_slice(&hmac_vector);
+
+               let compressed_public_key = public_key.serialize();
+               assert_eq!(compressed_public_key.len(), 33);
+
+               let trampoline_packet = TrampolineOnionPacket {
+                       version: 0,
+                       public_key,
+                       hop_data,
+                       hmac,
+               };
+               let encoded_trampoline_packet = trampoline_packet.encode();
+               let expected_eclair_trampoline_packet = <Vec<u8>>::from_hex("0002eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619cff34152f3a36e52ca94e74927203a560392b9cc7ce3c45809c6be52166c24a595716880f95f178bf5b30ca63141f74db6e92795c6130877cfdac3d4bd3087ee73c65d627ddd709112a848cc99e303f3706509aa43ba7c8a88cba175fccf9a8f5016ef06d3b935dbb15196d7ce16dc1a7157845566901d7b2197e52cab4ce487014b14816e5805f9fcacb4f8f88b8ff176f1b94f6ce6b00bc43221130c17d20ef629db7c5f7eafaa166578c720619561dd14b3277db557ec7dcdb793771aef0f2f667cfdbeae3ac8d331c5994779dffb31e5fc0dbdedc0c592ca6d21c18e47fe3528d6975c19517d7e2ea8c5391cf17d0fe30c80913ed887234ccb48808f7ef9425bcd815c3b586210979e3bb286ef2851bf9ce04e28c40a203df98fd648d2f1936fd2f1def0e77eecb277229b4b682322371c0a1dbfcd723a991993df8cc1f2696b84b055b40a1792a29f710295a18fbd351b0f3ff34cd13941131b8278ba79303c89117120eea691738a9954908195143b039dbeed98f26a92585f3d15cf742c953799d3272e0545e9b744be9d3b4cbb079bfc4b35190eee9f59a1d7b41ba2f773179f322dafb4b1af900c289ebd6c").unwrap();
+               assert_eq!(encoded_trampoline_packet, expected_eclair_trampoline_packet);
+       }
+
        #[test]
        fn query_channel_range_end_blocknum() {
                let tests: Vec<(u32, u32, u32)> = vec![