Correctly fail back downstream-failed blinded HTLCs as intro
[rust-lightning] / lightning / src / ln / channelmanager.rs
index fe050de913616f7508a39a6466a669c876949f4c..4247d57cbb6ad199ba99842c8dae506ee08f2e25 100644 (file)
 //! on-chain transactions (it only monitors the chain to watch for any force-closes that might
 //! imply it needs to fail HTLCs/payments/channels it manages).
 
-use bitcoin::blockdata::block::BlockHeader;
+use bitcoin::blockdata::block::Header;
 use bitcoin::blockdata::transaction::Transaction;
 use bitcoin::blockdata::constants::ChainHash;
+use bitcoin::key::constants::SECRET_KEY_SIZE;
 use bitcoin::network::constants::Network;
 
 use bitcoin::hashes::Hash;
@@ -28,7 +29,7 @@ use bitcoin::hash_types::{BlockHash, Txid};
 
 use bitcoin::secp256k1::{SecretKey,PublicKey};
 use bitcoin::secp256k1::Secp256k1;
-use bitcoin::{LockTime, secp256k1, Sequence};
+use bitcoin::{secp256k1, Sequence};
 
 use crate::blinded_path::BlindedPath;
 use crate::blinded_path::payment::{PaymentConstraints, ReceiveTlvs};
@@ -49,9 +50,10 @@ use crate::ln::features::Bolt11InvoiceFeatures;
 use crate::routing::gossip::NetworkGraph;
 use crate::routing::router::{BlindedTail, DefaultRouter, InFlightHtlcs, Path, Payee, PaymentParameters, Route, RouteParameters, Router};
 use crate::routing::scoring::{ProbabilisticScorer, ProbabilisticScoringFeeParameters};
+use crate::ln::onion_payment::{check_incoming_htlc_cltv, create_recv_pending_htlc_info, create_fwd_pending_htlc_info, decode_incoming_update_add_htlc_onion, InboundOnionErr, NextPacketDetails};
 use crate::ln::msgs;
 use crate::ln::onion_utils;
-use crate::ln::onion_utils::HTLCFailReason;
+use crate::ln::onion_utils::{HTLCFailReason, INVALID_ONION_BLINDING};
 use crate::ln::msgs::{ChannelMessageHandler, DecodeError, LightningError};
 #[cfg(test)]
 use crate::ln::outbound_payment;
@@ -64,7 +66,8 @@ use crate::offers::offer::{DerivedMetadata, Offer, OfferBuilder};
 use crate::offers::parse::Bolt12SemanticError;
 use crate::offers::refund::{Refund, RefundBuilder};
 use crate::onion_message::{Destination, OffersMessage, OffersMessageHandler, PendingOnionMessage, new_pending_onion_message};
-use crate::sign::{EntropySource, KeysManager, NodeSigner, Recipient, SignerProvider, WriteableEcdsaChannelSigner};
+use crate::sign::{EntropySource, KeysManager, NodeSigner, Recipient, SignerProvider};
+use crate::sign::ecdsa::WriteableEcdsaChannelSigner;
 use crate::util::config::{UserConfig, ChannelConfig, ChannelConfigUpdate};
 use crate::util::wakers::{Future, Notifier};
 use crate::util::scid_utils::fake_scid;
@@ -106,47 +109,96 @@ use crate::ln::script::ShutdownScript;
 // Alternatively, we can fill an outbound HTLC with a HTLCSource::OutboundRoute indicating this is
 // our payment, which we can use to decode errors or inform the user that the payment was sent.
 
+/// Routing info for an inbound HTLC onion.
 #[derive(Clone)] // See Channel::revoke_and_ack for why, tl;dr: Rust bug
-pub(super) enum PendingHTLCRouting {
+pub enum PendingHTLCRouting {
+       /// A forwarded HTLC.
        Forward {
+               /// BOLT 4 onion packet.
                onion_packet: msgs::OnionPacket,
                /// The SCID from the onion that we should forward to. This could be a real SCID or a fake one
                /// generated using `get_fake_scid` from the scid_utils::fake_scid module.
                short_channel_id: u64, // This should be NonZero<u64> eventually when we bump MSRV
+               /// Set if this HTLC is being forwarded within a blinded path.
+               blinded: Option<BlindedForward>,
        },
+       /// An HTLC paid to an invoice (supposedly) generated by us.
+       /// At this point, we have not checked that the invoice being paid was actually generated by us,
+       /// but rather it's claiming to pay an invoice of ours.
        Receive {
+               /// Payment secret and total msat received.
                payment_data: msgs::FinalOnionHopData,
+               /// See [`RecipientOnionFields::payment_metadata`] for more info.
                payment_metadata: Option<Vec<u8>>,
-               incoming_cltv_expiry: u32, // Used to track when we should expire pending HTLCs that go unclaimed
+               /// CLTV expiry of the received HTLC.
+               /// Used to track when we should expire pending HTLCs that go unclaimed.
+               incoming_cltv_expiry: u32,
+               /// Shared secret derived using a phantom node secret key. If this field is Some, the
+               /// payment was sent to a phantom node (one hop beyond the current node), but can be
+               /// settled by this node.
                phantom_shared_secret: Option<[u8; 32]>,
                /// See [`RecipientOnionFields::custom_tlvs`] for more info.
                custom_tlvs: Vec<(u64, Vec<u8>)>,
        },
+       /// Incoming keysend (sender provided the preimage in a TLV).
        ReceiveKeysend {
                /// This was added in 0.0.116 and will break deserialization on downgrades.
                payment_data: Option<msgs::FinalOnionHopData>,
+               /// Preimage for this onion payment. This preimage is provided by the sender and will be
+               /// used to settle the spontaneous payment.
                payment_preimage: PaymentPreimage,
+               /// See [`RecipientOnionFields::payment_metadata`] for more info.
                payment_metadata: Option<Vec<u8>>,
-               incoming_cltv_expiry: u32, // Used to track when we should expire pending HTLCs that go unclaimed
+               /// CLTV expiry of the received HTLC.
+               /// Used to track when we should expire pending HTLCs that go unclaimed.
+               incoming_cltv_expiry: u32,
                /// See [`RecipientOnionFields::custom_tlvs`] for more info.
                custom_tlvs: Vec<(u64, Vec<u8>)>,
        },
 }
 
+/// Information used to forward or fail this HTLC that is being forwarded within a blinded path.
+#[derive(Clone, Copy, Hash, PartialEq, Eq)]
+pub struct BlindedForward {
+       /// The `blinding_point` that was set in the inbound [`msgs::UpdateAddHTLC`], or in the inbound
+       /// onion payload if we're the introduction node. Useful for calculating the next hop's
+       /// [`msgs::UpdateAddHTLC::blinding_point`].
+       pub inbound_blinding_point: PublicKey,
+       // Another field will be added here when we support forwarding as a non-intro node.
+}
+
+impl PendingHTLCRouting {
+       // Used to override the onion failure code and data if the HTLC is blinded.
+       fn blinded_failure(&self) -> Option<BlindedFailure> {
+               // TODO: needs update when we support receiving to multi-hop blinded paths
+               if let Self::Forward { blinded: Some(_), .. } = self {
+                       Some(BlindedFailure::FromIntroductionNode)
+               } else {
+                       None
+               }
+       }
+}
+
+/// Full details of an incoming HTLC, including routing info.
 #[derive(Clone)] // See Channel::revoke_and_ack for why, tl;dr: Rust bug
-pub(super) struct PendingHTLCInfo {
-       pub(super) routing: PendingHTLCRouting,
-       pub(super) incoming_shared_secret: [u8; 32],
-       payment_hash: PaymentHash,
-       /// Amount received
-       pub(super) incoming_amt_msat: Option<u64>, // Added in 0.0.113
+pub struct PendingHTLCInfo {
+       /// Further routing details based on whether the HTLC is being forwarded or received.
+       pub routing: PendingHTLCRouting,
+       /// Shared secret from the previous hop.
+       /// Used encrypt failure packets in the event that the HTLC needs to be failed backwards.
+       pub incoming_shared_secret: [u8; 32],
+       /// Hash of the payment preimage, to lock the payment until the receiver releases the preimage.
+       pub payment_hash: PaymentHash,
+       /// Amount offered by this HTLC.
+       pub incoming_amt_msat: Option<u64>, // Added in 0.0.113
        /// Sender intended amount to forward or receive (actual amount received
        /// may overshoot this in either case)
-       pub(super) outgoing_amt_msat: u64,
-       pub(super) outgoing_cltv_value: u32,
+       pub outgoing_amt_msat: u64,
+       /// Outgoing timelock expiration blockheight.
+       pub outgoing_cltv_value: u32,
        /// The fee being skimmed off the top of this HTLC. If this is a forward, it'll be the fee we are
        /// skimming. If we're receiving this HTLC, it's the fee that our counterparty skimmed.
-       pub(super) skimmed_fee_msat: Option<u64>,
+       pub skimmed_fee_msat: Option<u64>,
 }
 
 #[derive(Clone)] // See Channel::revoke_and_ack for why, tl;dr: Rust bug
@@ -185,6 +237,13 @@ pub(super) enum HTLCForwardInfo {
        },
 }
 
+// Used for failing blinded HTLCs backwards correctly.
+#[derive(Clone, Debug, Hash, PartialEq, Eq)]
+enum BlindedFailure {
+       FromIntroductionNode,
+       // Another variant will be added here for non-intro nodes.
+}
+
 /// Tracks the inbound corresponding to an outbound HTLC
 #[derive(Clone, Debug, Hash, PartialEq, Eq)]
 pub(crate) struct HTLCPreviousHopData {
@@ -194,6 +253,7 @@ pub(crate) struct HTLCPreviousHopData {
        htlc_id: u64,
        incoming_packet_shared_secret: [u8; 32],
        phantom_shared_secret: Option<[u8; 32]>,
+       blinded_failure: Option<BlindedFailure>,
 
        // This field is consumed by `claim_funds_from_hop()` when updating a force-closed backwards
        // channel with a preimage provided by the forward channel.
@@ -238,6 +298,7 @@ impl From<&ClaimableHTLC> for events::ClaimedHTLC {
                        user_channel_id: val.prev_hop.user_channel_id.unwrap_or(0),
                        cltv_expiry: val.cltv_expiry,
                        value_msat: val.value,
+                       counterparty_skimmed_fee_msat: val.counterparty_skimmed_fee_msat.unwrap_or(0),
                }
        }
 }
@@ -296,7 +357,7 @@ impl Readable for InterceptId {
 /// Uniquely describes an HTLC by its source. Just the guaranteed-unique subset of [`HTLCSource`].
 pub(crate) enum SentHTLCId {
        PreviousHopData { short_channel_id: u64, htlc_id: u64 },
-       OutboundRoute { session_priv: SecretKey },
+       OutboundRoute { session_priv: [u8; SECRET_KEY_SIZE] },
 }
 impl SentHTLCId {
        pub(crate) fn from_source(source: &HTLCSource) -> Self {
@@ -306,7 +367,7 @@ impl SentHTLCId {
                                htlc_id: hop_data.htlc_id,
                        },
                        HTLCSource::OutboundRoute { session_priv, .. } =>
-                               Self::OutboundRoute { session_priv: *session_priv },
+                               Self::OutboundRoute { session_priv: session_priv.secret_bytes() },
                }
        }
 }
@@ -378,12 +439,6 @@ impl HTLCSource {
        }
 }
 
-struct InboundOnionErr {
-       err_code: u16,
-       err_data: Vec<u8>,
-       msg: &'static str,
-}
-
 /// This enum is used to specify which error data to send to peers when failing back an HTLC
 /// using [`ChannelManager::fail_htlc_backwards_with_reason`].
 ///
@@ -900,7 +955,7 @@ pub trait AChannelManager {
        /// A type implementing [`WriteableEcdsaChannelSigner`].
        type Signer: WriteableEcdsaChannelSigner + Sized;
        /// A type implementing [`SignerProvider`] for [`Self::Signer`].
-       type SignerProvider: SignerProvider<Signer = Self::Signer> + ?Sized;
+       type SignerProvider: SignerProvider<EcdsaSigner= Self::Signer> + ?Sized;
        /// A type that may be dereferenced to [`Self::SignerProvider`].
        type SP: Deref<Target = Self::SignerProvider>;
        /// A type implementing [`FeeEstimator`].
@@ -922,7 +977,7 @@ pub trait AChannelManager {
 impl<M: Deref, T: Deref, ES: Deref, NS: Deref, SP: Deref, F: Deref, R: Deref, L: Deref> AChannelManager
 for ChannelManager<M, T, ES, NS, SP, F, R, L>
 where
-       M::Target: chain::Watch<<SP::Target as SignerProvider>::Signer>,
+       M::Target: chain::Watch<<SP::Target as SignerProvider>::EcdsaSigner>,
        T::Target: BroadcasterInterface,
        ES::Target: EntropySource,
        NS::Target: NodeSigner,
@@ -939,7 +994,7 @@ where
        type ES = ES;
        type NodeSigner = NS::Target;
        type NS = NS;
-       type Signer = <SP::Target as SignerProvider>::Signer;
+       type Signer = <SP::Target as SignerProvider>::EcdsaSigner;
        type SignerProvider = SP::Target;
        type SP = SP;
        type FeeEstimator = F::Target;
@@ -1047,7 +1102,7 @@ where
 //
 pub struct ChannelManager<M: Deref, T: Deref, ES: Deref, NS: Deref, SP: Deref, F: Deref, R: Deref, L: Deref>
 where
-       M::Target: chain::Watch<<SP::Target as SignerProvider>::Signer>,
+       M::Target: chain::Watch<<SP::Target as SignerProvider>::EcdsaSigner>,
        T::Target: BroadcasterInterface,
        ES::Target: EntropySource,
        NS::Target: NodeSigner,
@@ -2262,7 +2317,7 @@ macro_rules! process_events_body {
 
 impl<M: Deref, T: Deref, ES: Deref, NS: Deref, SP: Deref, F: Deref, R: Deref, L: Deref> ChannelManager<M, T, ES, NS, SP, F, R, L>
 where
-       M::Target: chain::Watch<<SP::Target as SignerProvider>::Signer>,
+       M::Target: chain::Watch<<SP::Target as SignerProvider>::EcdsaSigner>,
        T::Target: BroadcasterInterface,
        ES::Target: EntropySource,
        NS::Target: NodeSigner,
@@ -2390,6 +2445,9 @@ where
        /// connection is available, the outbound `open_channel` message may fail to send, resulting in
        /// the channel eventually being silently forgotten (dropped on reload).
        ///
+       /// If `temporary_channel_id` is specified, it will be used as the temporary channel ID of the
+       /// channel. Otherwise, a random one will be generated for you.
+       ///
        /// Returns the new Channel's temporary `channel_id`. This ID will appear as
        /// [`Event::FundingGenerationReady::temporary_channel_id`] and in
        /// [`ChannelDetails::channel_id`] until after
@@ -2400,7 +2458,7 @@ where
        /// [`Event::FundingGenerationReady::user_channel_id`]: events::Event::FundingGenerationReady::user_channel_id
        /// [`Event::FundingGenerationReady::temporary_channel_id`]: events::Event::FundingGenerationReady::temporary_channel_id
        /// [`Event::ChannelClosed::channel_id`]: events::Event::ChannelClosed::channel_id
-       pub fn create_channel(&self, their_network_key: PublicKey, channel_value_satoshis: u64, push_msat: u64, user_channel_id: u128, override_config: Option<UserConfig>) -> Result<ChannelId, APIError> {
+       pub fn create_channel(&self, their_network_key: PublicKey, channel_value_satoshis: u64, push_msat: u64, user_channel_id: u128, temporary_channel_id: Option<ChannelId>, override_config: Option<UserConfig>) -> Result<ChannelId, APIError> {
                if channel_value_satoshis < 1000 {
                        return Err(APIError::APIMisuseError { err: format!("Channel value must be at least 1000 satoshis. It was {}", channel_value_satoshis) });
                }
@@ -2415,13 +2473,20 @@ where
                        .ok_or_else(|| APIError::APIMisuseError{ err: format!("Not connected to node: {}", their_network_key) })?;
 
                let mut peer_state = peer_state_mutex.lock().unwrap();
+
+               if let Some(temporary_channel_id) = temporary_channel_id {
+                       if peer_state.channel_by_id.contains_key(&temporary_channel_id) {
+                               return Err(APIError::APIMisuseError{ err: format!("Channel with temporary channel ID {} already exists!", temporary_channel_id)});
+                       }
+               }
+
                let channel = {
                        let outbound_scid_alias = self.create_and_insert_outbound_scid_alias();
                        let their_features = &peer_state.latest_features;
                        let config = if override_config.is_some() { override_config.as_ref().unwrap() } else { &self.default_configuration };
                        match OutboundV1Channel::new(&self.fee_estimator, &self.entropy_source, &self.signer_provider, their_network_key,
                                their_features, channel_value_satoshis, push_msat, user_channel_id, config,
-                               self.best_block.read().unwrap().height(), outbound_scid_alias)
+                               self.best_block.read().unwrap().height(), outbound_scid_alias, temporary_channel_id)
                        {
                                Ok(res) => res,
                                Err(e) => {
@@ -2903,236 +2968,45 @@ where
                }
        }
 
-       fn construct_fwd_pending_htlc_info(
-               &self, msg: &msgs::UpdateAddHTLC, hop_data: msgs::InboundOnionPayload, hop_hmac: [u8; 32],
-               new_packet_bytes: [u8; onion_utils::ONION_DATA_LEN], shared_secret: [u8; 32],
-               next_packet_pubkey_opt: Option<Result<PublicKey, secp256k1::Error>>
-       ) -> Result<PendingHTLCInfo, InboundOnionErr> {
-               debug_assert!(next_packet_pubkey_opt.is_some());
-               let outgoing_packet = msgs::OnionPacket {
-                       version: 0,
-                       public_key: next_packet_pubkey_opt.unwrap_or(Err(secp256k1::Error::InvalidPublicKey)),
-                       hop_data: new_packet_bytes,
-                       hmac: hop_hmac,
-               };
-
-               let (short_channel_id, amt_to_forward, outgoing_cltv_value) = match hop_data {
-                       msgs::InboundOnionPayload::Forward { short_channel_id, amt_to_forward, outgoing_cltv_value } =>
-                               (short_channel_id, amt_to_forward, outgoing_cltv_value),
-                       msgs::InboundOnionPayload::Receive { .. } | msgs::InboundOnionPayload::BlindedReceive { .. } =>
-                               return Err(InboundOnionErr {
-                                       msg: "Final Node OnionHopData provided for us as an intermediary node",
-                                       err_code: 0x4000 | 22,
-                                       err_data: Vec::new(),
-                               }),
-               };
-
-               Ok(PendingHTLCInfo {
-                       routing: PendingHTLCRouting::Forward {
-                               onion_packet: outgoing_packet,
-                               short_channel_id,
-                       },
-                       payment_hash: msg.payment_hash,
-                       incoming_shared_secret: shared_secret,
-                       incoming_amt_msat: Some(msg.amount_msat),
-                       outgoing_amt_msat: amt_to_forward,
-                       outgoing_cltv_value,
-                       skimmed_fee_msat: None,
-               })
-       }
-
-       fn construct_recv_pending_htlc_info(
-               &self, hop_data: msgs::InboundOnionPayload, shared_secret: [u8; 32], payment_hash: PaymentHash,
-               amt_msat: u64, cltv_expiry: u32, phantom_shared_secret: Option<[u8; 32]>, allow_underpay: bool,
-               counterparty_skimmed_fee_msat: Option<u64>,
-       ) -> Result<PendingHTLCInfo, InboundOnionErr> {
-               let (payment_data, keysend_preimage, custom_tlvs, onion_amt_msat, outgoing_cltv_value, payment_metadata) = match hop_data {
-                       msgs::InboundOnionPayload::Receive {
-                               payment_data, keysend_preimage, custom_tlvs, amt_msat, outgoing_cltv_value, payment_metadata, ..
-                       } =>
-                               (payment_data, keysend_preimage, custom_tlvs, amt_msat, outgoing_cltv_value, payment_metadata),
-                       msgs::InboundOnionPayload::BlindedReceive {
-                               amt_msat, total_msat, outgoing_cltv_value, payment_secret, ..
-                       } => {
-                               let payment_data = msgs::FinalOnionHopData { payment_secret, total_msat };
-                               (Some(payment_data), None, Vec::new(), amt_msat, outgoing_cltv_value, None)
-                       }
-                       msgs::InboundOnionPayload::Forward { .. } => {
-                               return Err(InboundOnionErr {
-                                       err_code: 0x4000|22,
-                                       err_data: Vec::new(),
-                                       msg: "Got non final data with an HMAC of 0",
-                               })
-                       },
-               };
-               // final_incorrect_cltv_expiry
-               if outgoing_cltv_value > cltv_expiry {
-                       return Err(InboundOnionErr {
-                               msg: "Upstream node set CLTV to less than the CLTV set by the sender",
-                               err_code: 18,
-                               err_data: cltv_expiry.to_be_bytes().to_vec()
-                       })
-               }
-               // final_expiry_too_soon
-               // We have to have some headroom to broadcast on chain if we have the preimage, so make sure
-               // we have at least HTLC_FAIL_BACK_BUFFER blocks to go.
-               //
-               // Also, ensure that, in the case of an unknown preimage for the received payment hash, our
-               // payment logic has enough time to fail the HTLC backward before our onchain logic triggers a
-               // channel closure (see HTLC_FAIL_BACK_BUFFER rationale).
-               let current_height: u32 = self.best_block.read().unwrap().height();
-               if cltv_expiry <= current_height + HTLC_FAIL_BACK_BUFFER + 1 {
-                       let mut err_data = Vec::with_capacity(12);
-                       err_data.extend_from_slice(&amt_msat.to_be_bytes());
-                       err_data.extend_from_slice(&current_height.to_be_bytes());
-                       return Err(InboundOnionErr {
-                               err_code: 0x4000 | 15, err_data,
-                               msg: "The final CLTV expiry is too soon to handle",
-                       });
-               }
-               if (!allow_underpay && onion_amt_msat > amt_msat) ||
-                       (allow_underpay && onion_amt_msat >
-                        amt_msat.saturating_add(counterparty_skimmed_fee_msat.unwrap_or(0)))
-               {
-                       return Err(InboundOnionErr {
-                               err_code: 19,
-                               err_data: amt_msat.to_be_bytes().to_vec(),
-                               msg: "Upstream node sent less than we were supposed to receive in payment",
-                       });
-               }
-
-               let routing = if let Some(payment_preimage) = keysend_preimage {
-                       // We need to check that the sender knows the keysend preimage before processing this
-                       // payment further. Otherwise, an intermediary routing hop forwarding non-keysend-HTLC X
-                       // could discover the final destination of X, by probing the adjacent nodes on the route
-                       // with a keysend payment of identical payment hash to X and observing the processing
-                       // time discrepancies due to a hash collision with X.
-                       let hashed_preimage = PaymentHash(Sha256::hash(&payment_preimage.0).into_inner());
-                       if hashed_preimage != payment_hash {
-                               return Err(InboundOnionErr {
-                                       err_code: 0x4000|22,
-                                       err_data: Vec::new(),
-                                       msg: "Payment preimage didn't match payment hash",
-                               });
-                       }
-                       if !self.default_configuration.accept_mpp_keysend && payment_data.is_some() {
-                               return Err(InboundOnionErr {
-                                       err_code: 0x4000|22,
-                                       err_data: Vec::new(),
-                                       msg: "We don't support MPP keysend payments",
-                               });
-                       }
-                       PendingHTLCRouting::ReceiveKeysend {
-                               payment_data,
-                               payment_preimage,
-                               payment_metadata,
-                               incoming_cltv_expiry: outgoing_cltv_value,
-                               custom_tlvs,
-                       }
-               } else if let Some(data) = payment_data {
-                       PendingHTLCRouting::Receive {
-                               payment_data: data,
-                               payment_metadata,
-                               incoming_cltv_expiry: outgoing_cltv_value,
-                               phantom_shared_secret,
-                               custom_tlvs,
-                       }
-               } else {
-                       return Err(InboundOnionErr {
-                               err_code: 0x4000|0x2000|3,
-                               err_data: Vec::new(),
-                               msg: "We require payment_secrets",
-                       });
-               };
-               Ok(PendingHTLCInfo {
-                       routing,
-                       payment_hash,
-                       incoming_shared_secret: shared_secret,
-                       incoming_amt_msat: Some(amt_msat),
-                       outgoing_amt_msat: onion_amt_msat,
-                       outgoing_cltv_value,
-                       skimmed_fee_msat: counterparty_skimmed_fee_msat,
-               })
-       }
-
        fn decode_update_add_htlc_onion(
                &self, msg: &msgs::UpdateAddHTLC
-       ) -> Result<(onion_utils::Hop, [u8; 32], Option<Result<PublicKey, secp256k1::Error>>), HTLCFailureMsg> {
-               macro_rules! return_malformed_err {
-                       ($msg: expr, $err_code: expr) => {
-                               {
-                                       log_info!(self.logger, "Failed to accept/forward incoming HTLC: {}", $msg);
-                                       return Err(HTLCFailureMsg::Malformed(msgs::UpdateFailMalformedHTLC {
-                                               channel_id: msg.channel_id,
-                                               htlc_id: msg.htlc_id,
-                                               sha256_of_onion: Sha256::hash(&msg.onion_routing_packet.hop_data).into_inner(),
-                                               failure_code: $err_code,
-                                       }));
-                               }
-                       }
-               }
-
-               if let Err(_) = msg.onion_routing_packet.public_key {
-                       return_malformed_err!("invalid ephemeral pubkey", 0x8000 | 0x4000 | 6);
-               }
-
-               let shared_secret = self.node_signer.ecdh(
-                       Recipient::Node, &msg.onion_routing_packet.public_key.unwrap(), None
-               ).unwrap().secret_bytes();
+       ) -> Result<
+               (onion_utils::Hop, [u8; 32], Option<Result<PublicKey, secp256k1::Error>>), HTLCFailureMsg
+       > {
+               let (next_hop, shared_secret, next_packet_details_opt) = decode_incoming_update_add_htlc_onion(
+                       msg, &self.node_signer, &self.logger, &self.secp_ctx
+               )?;
+
+               let is_blinded = match next_hop {
+                       onion_utils::Hop::Forward {
+                               next_hop_data: msgs::InboundOnionPayload::BlindedForward { .. }, ..
+                       } => true,
+                       _ => false, // TODO: update this when we support receiving to multi-hop blinded paths
+               };
 
-               if msg.onion_routing_packet.version != 0 {
-                       //TODO: Spec doesn't indicate if we should only hash hop_data here (and in other
-                       //sha256_of_onion error data packets), or the entire onion_routing_packet. Either way,
-                       //the hash doesn't really serve any purpose - in the case of hashing all data, the
-                       //receiving node would have to brute force to figure out which version was put in the
-                       //packet by the node that send us the message, in the case of hashing the hop_data, the
-                       //node knows the HMAC matched, so they already know what is there...
-                       return_malformed_err!("Unknown onion packet version", 0x8000 | 0x4000 | 4);
-               }
                macro_rules! return_err {
                        ($msg: expr, $err_code: expr, $data: expr) => {
                                {
                                        log_info!(self.logger, "Failed to accept/forward incoming HTLC: {}", $msg);
+                                       let (err_code, err_data) = if is_blinded {
+                                               (INVALID_ONION_BLINDING, &[0; 32][..])
+                                       } else { ($err_code, $data) };
                                        return Err(HTLCFailureMsg::Relay(msgs::UpdateFailHTLC {
                                                channel_id: msg.channel_id,
                                                htlc_id: msg.htlc_id,
-                                               reason: HTLCFailReason::reason($err_code, $data.to_vec())
+                                               reason: HTLCFailReason::reason(err_code, err_data.to_vec())
                                                        .get_encrypted_failure_packet(&shared_secret, &None),
                                        }));
                                }
                        }
                }
 
-               let next_hop = match onion_utils::decode_next_payment_hop(
-                       shared_secret, &msg.onion_routing_packet.hop_data[..], msg.onion_routing_packet.hmac,
-                       msg.payment_hash, &self.node_signer
-               ) {
-                       Ok(res) => res,
-                       Err(onion_utils::OnionDecodeErr::Malformed { err_msg, err_code }) => {
-                               return_malformed_err!(err_msg, err_code);
-                       },
-                       Err(onion_utils::OnionDecodeErr::Relay { err_msg, err_code }) => {
-                               return_err!(err_msg, err_code, &[0; 0]);
-                       },
-               };
-               let (outgoing_scid, outgoing_amt_msat, outgoing_cltv_value, next_packet_pk_opt) = match next_hop {
-                       onion_utils::Hop::Forward {
-                               next_hop_data: msgs::InboundOnionPayload::Forward {
-                                       short_channel_id, amt_to_forward, outgoing_cltv_value
-                               }, ..
-                       } => {
-                               let next_packet_pk = onion_utils::next_hop_pubkey(&self.secp_ctx,
-                                       msg.onion_routing_packet.public_key.unwrap(), &shared_secret);
-                               (short_channel_id, amt_to_forward, outgoing_cltv_value, Some(next_packet_pk))
-                       },
-                       // We'll do receive checks in [`Self::construct_pending_htlc_info`] so we have access to the
-                       // inbound channel's state.
-                       onion_utils::Hop::Receive { .. } => return Ok((next_hop, shared_secret, None)),
-                       onion_utils::Hop::Forward { next_hop_data: msgs::InboundOnionPayload::Receive { .. }, .. } |
-                               onion_utils::Hop::Forward { next_hop_data: msgs::InboundOnionPayload::BlindedReceive { .. }, .. } =>
-                       {
-                               return_err!("Final Node OnionHopData provided for us as an intermediary node", 0x4000 | 22, &[0; 0]);
-                       }
+               let NextPacketDetails {
+                       next_packet_pubkey, outgoing_amt_msat, outgoing_scid, outgoing_cltv_value
+               } = match next_packet_details_opt {
+                       Some(next_packet_details) => next_packet_details,
+                       // it is a receive, so no need for outbound checks
+                       None => return Ok((next_hop, shared_secret, None)),
                };
 
                // Perform outbound checks here instead of in [`Self::construct_pending_htlc_info`] because we
@@ -3209,38 +3083,22 @@ where
                                }
                                chan_update_opt
                        } else {
-                               if (msg.cltv_expiry as u64) < (outgoing_cltv_value) as u64 + MIN_CLTV_EXPIRY_DELTA as u64 {
-                                       // We really should set `incorrect_cltv_expiry` here but as we're not
-                                       // forwarding over a real channel we can't generate a channel_update
-                                       // for it. Instead we just return a generic temporary_node_failure.
-                                       break Some((
-                                                       "Forwarding node has tampered with the intended HTLC values or origin node has an obsolete cltv_expiry_delta",
-                                                       0x2000 | 2, None,
-                                       ));
-                               }
                                None
                        };
 
                        let cur_height = self.best_block.read().unwrap().height() + 1;
-                       // Theoretically, channel counterparty shouldn't send us a HTLC expiring now,
-                       // but we want to be robust wrt to counterparty packet sanitization (see
-                       // HTLC_FAIL_BACK_BUFFER rationale).
-                       if msg.cltv_expiry <= cur_height + HTLC_FAIL_BACK_BUFFER as u32 { // expiry_too_soon
-                               break Some(("CLTV expiry is too close", 0x1000 | 14, chan_update_opt));
-                       }
-                       if msg.cltv_expiry > cur_height + CLTV_FAR_FAR_AWAY as u32 { // expiry_too_far
-                               break Some(("CLTV expiry is too far in the future", 21, None));
-                       }
-                       // If the HTLC expires ~now, don't bother trying to forward it to our
-                       // counterparty. They should fail it anyway, but we don't want to bother with
-                       // the round-trips or risk them deciding they definitely want the HTLC and
-                       // force-closing to ensure they get it if we're offline.
-                       // We previously had a much more aggressive check here which tried to ensure
-                       // our counterparty receives an HTLC which has *our* risk threshold met on it,
-                       // but there is no need to do that, and since we're a bit conservative with our
-                       // risk threshold it just results in failing to forward payments.
-                       if (outgoing_cltv_value) as u64 <= (cur_height + LATENCY_GRACE_PERIOD_BLOCKS) as u64 {
-                               break Some(("Outgoing CLTV value is too soon", 0x1000 | 14, chan_update_opt));
+
+                       if let Err((err_msg, code)) = check_incoming_htlc_cltv(
+                               cur_height, outgoing_cltv_value, msg.cltv_expiry
+                       ) {
+                               if code & 0x1000 != 0 && chan_update_opt.is_none() {
+                                       // We really should set `incorrect_cltv_expiry` here but as we're not
+                                       // forwarding over a real channel we can't generate a channel_update
+                                       // for it. Instead we just return a generic temporary_node_failure.
+                                       break Some((err_msg, 0x2000 | 2, None))
+                               }
+                               let chan_update_opt = if code & 0x1000 != 0 { chan_update_opt } else { None };
+                               break Some((err_msg, code, chan_update_opt));
                        }
 
                        break None;
@@ -3270,7 +3128,7 @@ where
                        }
                        return_err!(err, code, &res.0[..]);
                }
-               Ok((next_hop, shared_secret, next_packet_pk_opt))
+               Ok((next_hop, shared_secret, Some(next_packet_pubkey)))
        }
 
        fn construct_pending_htlc_status<'a>(
@@ -3293,8 +3151,10 @@ where
                match decoded_hop {
                        onion_utils::Hop::Receive(next_hop_data) => {
                                // OUR PAYMENT!
-                               match self.construct_recv_pending_htlc_info(next_hop_data, shared_secret, msg.payment_hash,
-                                       msg.amount_msat, msg.cltv_expiry, None, allow_underpay, msg.skimmed_fee_msat)
+                               let current_height: u32 = self.best_block.read().unwrap().height();
+                               match create_recv_pending_htlc_info(next_hop_data, shared_secret, msg.payment_hash,
+                                       msg.amount_msat, msg.cltv_expiry, None, allow_underpay, msg.skimmed_fee_msat,
+                                       current_height, self.default_configuration.accept_mpp_keysend)
                                {
                                        Ok(info) => {
                                                // Note that we could obviously respond immediately with an update_fulfill_htlc
@@ -3307,7 +3167,7 @@ where
                                }
                        },
                        onion_utils::Hop::Forward { next_hop_data, next_hop_hmac, new_packet_bytes } => {
-                               match self.construct_fwd_pending_htlc_info(msg, next_hop_data, next_hop_hmac,
+                               match create_fwd_pending_htlc_info(msg, next_hop_data, next_hop_hmac,
                                        new_packet_bytes, shared_secret, next_packet_pubkey_opt) {
                                        Ok(info) => PendingHTLCStatus::Forward(info),
                                        Err(InboundOnionErr { err_code, err_data, msg }) => return_err!(msg, err_code, &err_data)
@@ -3419,12 +3279,10 @@ where
                let prng_seed = self.entropy_source.get_secure_random_bytes();
                let session_priv = SecretKey::from_slice(&session_priv_bytes[..]).expect("RNG is busted");
 
-               let onion_keys = onion_utils::construct_onion_keys(&self.secp_ctx, &path, &session_priv)
-                       .map_err(|_| APIError::InvalidRoute{err: "Pubkey along hop was maliciously selected".to_owned()})?;
-               let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(path, total_value, recipient_onion, cur_height, keysend_preimage)?;
-
-               let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, prng_seed, payment_hash)
-                       .map_err(|_| APIError::InvalidRoute { err: "Route size too large considering onion data".to_owned()})?;
+               let (onion_packet, htlc_msat, htlc_cltv) = onion_utils::create_payment_onion(
+                       &self.secp_ctx, &path, &session_priv, total_value, recipient_onion, cur_height,
+                       payment_hash, keysend_preimage, prng_seed
+               )?;
 
                let err: Result<(), _> = loop {
                        let (counterparty_node_id, id) = match self.short_to_chan_info.read().unwrap().get(&path.hops.first().unwrap().short_channel_id) {
@@ -3802,7 +3660,7 @@ where
 
                let mut peer_state_lock = peer_state_mutex.lock().unwrap();
                let peer_state = &mut *peer_state_lock;
-               let (chan, msg) = match peer_state.channel_by_id.remove(temporary_channel_id) {
+               let (chan, msg_opt) = match peer_state.channel_by_id.remove(temporary_channel_id) {
                        Some(ChannelPhase::UnfundedOutboundV1(chan)) => {
                                let funding_txo = find_funding_output(&chan, &funding_transaction)?;
 
@@ -3841,10 +3699,12 @@ where
                                }),
                };
 
-               peer_state.pending_msg_events.push(events::MessageSendEvent::SendFundingCreated {
-                       node_id: chan.context.get_counterparty_node_id(),
-                       msg,
-               });
+               if let Some(msg) = msg_opt {
+                       peer_state.pending_msg_events.push(events::MessageSendEvent::SendFundingCreated {
+                               node_id: chan.context.get_counterparty_node_id(),
+                               msg,
+                       });
+               }
                match peer_state.channel_by_id.entry(chan.context.channel_id()) {
                        hash_map::Entry::Occupied(_) => {
                                panic!("Generated duplicate funding txid?");
@@ -3935,7 +3795,10 @@ where
                        // lower than the next block height. However, the modules constituting our Lightning
                        // node might not have perfect sync about their blockchain views. Thus, if the wallet
                        // module is ahead of LDK, only allow one more block of headroom.
-                       if !funding_transaction.input.iter().all(|input| input.sequence == Sequence::MAX) && LockTime::from(funding_transaction.lock_time).is_block_height() && funding_transaction.lock_time.0 > height + 1 {
+                       if !funding_transaction.input.iter().all(|input| input.sequence == Sequence::MAX) &&
+                               funding_transaction.lock_time.is_block_height() &&
+                               funding_transaction.lock_time.to_consensus_u32() > height + 1
+                       {
                                result = result.and(Err(APIError::APIMisuseError {
                                        err: "Funding transaction absolute timelock is non-final".to_owned()
                                }));
@@ -4175,10 +4038,14 @@ where
                                        err: format!("Channel with id {} for the passed counterparty node_id {} is still opening.",
                                                next_hop_channel_id, next_node_id)
                                }),
-                               None => return Err(APIError::ChannelUnavailable {
-                                       err: format!("Channel with id {} not found for the passed counterparty node_id {}",
-                                               next_hop_channel_id, next_node_id)
-                               })
+                               None => {
+                                       let error = format!("Channel with id {} not found for the passed counterparty node_id {}",
+                                               next_hop_channel_id, next_node_id);
+                                       log_error!(self.logger, "{} when attempting to forward intercepted HTLC", error);
+                                       return Err(APIError::ChannelUnavailable {
+                                               err: error
+                                       })
+                               }
                        }
                };
 
@@ -4188,8 +4055,10 @@ where
                        })?;
 
                let routing = match payment.forward_info.routing {
-                       PendingHTLCRouting::Forward { onion_packet, .. } => {
-                               PendingHTLCRouting::Forward { onion_packet, short_channel_id: next_hop_scid }
+                       PendingHTLCRouting::Forward { onion_packet, blinded, .. } => {
+                               PendingHTLCRouting::Forward {
+                                       onion_packet, blinded, short_channel_id: next_hop_scid
+                               }
                        },
                        _ => unreachable!() // Only `PendingHTLCRouting::Forward`s are intercepted
                };
@@ -4233,6 +4102,7 @@ where
                                htlc_id: payment.prev_htlc_id,
                                incoming_packet_shared_secret: payment.forward_info.incoming_shared_secret,
                                phantom_shared_secret: None,
+                               blinded_failure: payment.forward_info.routing.blinded_failure(),
                        });
 
                        let failure_reason = HTLCFailReason::from_failure_code(0x4000 | 10);
@@ -4281,6 +4151,7 @@ where
                                                                                                        htlc_id: prev_htlc_id,
                                                                                                        incoming_packet_shared_secret: incoming_shared_secret,
                                                                                                        phantom_shared_secret: $phantom_ss,
+                                                                                                       blinded_failure: routing.blinded_failure(),
                                                                                                });
 
                                                                                                let reason = if $next_hop_unknown {
@@ -4310,7 +4181,7 @@ where
                                                                                                }
                                                                                        }
                                                                                }
-                                                                               if let PendingHTLCRouting::Forward { onion_packet, .. } = routing {
+                                                                               if let PendingHTLCRouting::Forward { ref onion_packet, .. } = routing {
                                                                                        let phantom_pubkey_res = self.node_signer.get_node_id(Recipient::PhantomNode);
                                                                                        if phantom_pubkey_res.is_ok() && fake_scid::is_valid_phantom(&self.fake_scid_rand_bytes, short_chan_id, &self.chain_hash) {
                                                                                                let phantom_shared_secret = self.node_signer.ecdh(Recipient::PhantomNode, &onion_packet.public_key.unwrap(), None).unwrap().secret_bytes();
@@ -4320,7 +4191,7 @@ where
                                                                                                ) {
                                                                                                        Ok(res) => res,
                                                                                                        Err(onion_utils::OnionDecodeErr::Malformed { err_msg, err_code }) => {
-                                                                                                               let sha256_of_onion = Sha256::hash(&onion_packet.hop_data).into_inner();
+                                                                                                               let sha256_of_onion = Sha256::hash(&onion_packet.hop_data).to_byte_array();
                                                                                                                // In this scenario, the phantom would have sent us an
                                                                                                                // `update_fail_malformed_htlc`, meaning here we encrypt the error as
                                                                                                                // if it came from us (the second-to-last hop) but contains the sha256
@@ -4333,9 +4204,11 @@ where
                                                                                                };
                                                                                                match next_hop {
                                                                                                        onion_utils::Hop::Receive(hop_data) => {
-                                                                                                               match self.construct_recv_pending_htlc_info(hop_data,
+                                                                                                               let current_height: u32 = self.best_block.read().unwrap().height();
+                                                                                                               match create_recv_pending_htlc_info(hop_data,
                                                                                                                        incoming_shared_secret, payment_hash, outgoing_amt_msat,
-                                                                                                                       outgoing_cltv_value, Some(phantom_shared_secret), false, None)
+                                                                                                                       outgoing_cltv_value, Some(phantom_shared_secret), false, None,
+                                                                                                                       current_height, self.default_configuration.accept_mpp_keysend)
                                                                                                                {
                                                                                                                        Ok(info) => phantom_receives.push((prev_short_channel_id, prev_funding_outpoint, prev_user_channel_id, vec![(info, prev_htlc_id)])),
                                                                                                                        Err(InboundOnionErr { err_code, err_data, msg }) => failed_payment!(msg, err_code, err_data, Some(phantom_shared_secret))
@@ -4383,7 +4256,9 @@ where
                                                                        prev_short_channel_id, prev_htlc_id, prev_funding_outpoint, prev_user_channel_id,
                                                                        forward_info: PendingHTLCInfo {
                                                                                incoming_shared_secret, payment_hash, outgoing_amt_msat, outgoing_cltv_value,
-                                                                               routing: PendingHTLCRouting::Forward { onion_packet, .. }, skimmed_fee_msat, ..
+                                                                               routing: PendingHTLCRouting::Forward {
+                                                                                       onion_packet, blinded, ..
+                                                                               }, skimmed_fee_msat, ..
                                                                        },
                                                                }) => {
                                                                        log_trace!(self.logger, "Adding HTLC from short id {} with payment_hash {} to channel with short id {} after delay", prev_short_channel_id, &payment_hash, short_chan_id);
@@ -4395,10 +4270,19 @@ where
                                                                                incoming_packet_shared_secret: incoming_shared_secret,
                                                                                // Phantom payments are only PendingHTLCRouting::Receive.
                                                                                phantom_shared_secret: None,
+                                                                               blinded_failure: blinded.map(|_| BlindedFailure::FromIntroductionNode),
+                                                                       });
+                                                                       let next_blinding_point = blinded.and_then(|b| {
+                                                                               let encrypted_tlvs_ss = self.node_signer.ecdh(
+                                                                                       Recipient::Node, &b.inbound_blinding_point, None
+                                                                               ).unwrap().secret_bytes();
+                                                                               onion_utils::next_hop_pubkey(
+                                                                                       &self.secp_ctx, b.inbound_blinding_point, &encrypted_tlvs_ss
+                                                                               ).ok()
                                                                        });
                                                                        if let Err(e) = chan.queue_add_htlc(outgoing_amt_msat,
                                                                                payment_hash, outgoing_cltv_value, htlc_source.clone(),
-                                                                               onion_packet, skimmed_fee_msat, &self.fee_estimator,
+                                                                               onion_packet, skimmed_fee_msat, next_blinding_point, &self.fee_estimator,
                                                                                &self.logger)
                                                                        {
                                                                                if let ChannelError::Ignore(msg) = e {
@@ -4449,6 +4333,7 @@ where
                                                                        skimmed_fee_msat, ..
                                                                }
                                                        }) => {
+                                                               let blinded_failure = routing.blinded_failure();
                                                                let (cltv_expiry, onion_payload, payment_data, phantom_shared_secret, mut onion_fields) = match routing {
                                                                        PendingHTLCRouting::Receive { payment_data, payment_metadata, incoming_cltv_expiry, phantom_shared_secret, custom_tlvs } => {
                                                                                let _legacy_hop_data = Some(payment_data.clone());
@@ -4478,6 +4363,7 @@ where
                                                                                htlc_id: prev_htlc_id,
                                                                                incoming_packet_shared_secret: incoming_shared_secret,
                                                                                phantom_shared_secret,
+                                                                               blinded_failure,
                                                                        },
                                                                        // We differentiate the received value from the sender intended value
                                                                        // if possible so that we don't prematurely mark MPP payments complete
@@ -4508,6 +4394,7 @@ where
                                                                                                htlc_id: $htlc.prev_hop.htlc_id,
                                                                                                incoming_packet_shared_secret: $htlc.prev_hop.incoming_packet_shared_secret,
                                                                                                phantom_shared_secret,
+                                                                                               blinded_failure: None,
                                                                                        }), payment_hash,
                                                                                        HTLCFailReason::reason(0x4000 | 15, htlc_msat_height_data),
                                                                                        HTLCDestination::FailedPayment { payment_hash: $payment_hash },
@@ -5271,9 +5158,23 @@ where
                                        &self.pending_events, &self.logger)
                                { self.push_pending_forwards_ev(); }
                        },
-                       HTLCSource::PreviousHopData(HTLCPreviousHopData { ref short_channel_id, ref htlc_id, ref incoming_packet_shared_secret, ref phantom_shared_secret, ref outpoint, .. }) => {
-                               log_trace!(self.logger, "Failing HTLC with payment_hash {} backwards from us with {:?}", &payment_hash, onion_error);
-                               let err_packet = onion_error.get_encrypted_failure_packet(incoming_packet_shared_secret, phantom_shared_secret);
+                       HTLCSource::PreviousHopData(HTLCPreviousHopData {
+                               ref short_channel_id, ref htlc_id, ref incoming_packet_shared_secret,
+                               ref phantom_shared_secret, ref outpoint, ref blinded_failure, ..
+                       }) => {
+                               log_trace!(self.logger, "Failing {}HTLC with payment_hash {} backwards from us: {:?}",
+                                       if blinded_failure.is_some() { "blinded " } else { "" }, &payment_hash, onion_error);
+                               let err_packet = match blinded_failure {
+                                       Some(BlindedFailure::FromIntroductionNode) => {
+                                               let blinded_onion_error = HTLCFailReason::reason(INVALID_ONION_BLINDING, vec![0; 32]);
+                                               blinded_onion_error.get_encrypted_failure_packet(
+                                                       incoming_packet_shared_secret, phantom_shared_secret
+                                               )
+                                       },
+                                       None => {
+                                               onion_error.get_encrypted_failure_packet(incoming_packet_shared_secret, phantom_shared_secret)
+                                       }
+                               };
 
                                let mut push_forward_ev = false;
                                let mut forward_htlcs = self.forward_htlcs.lock().unwrap();
@@ -5341,7 +5242,7 @@ where
        }
 
        fn claim_payment_internal(&self, payment_preimage: PaymentPreimage, custom_tlvs_known: bool) {
-               let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0).into_inner());
+               let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0).to_byte_array());
 
                let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
 
@@ -6229,7 +6130,7 @@ where
 
                let mut peer_state_lock = peer_state_mutex.lock().unwrap();
                let peer_state = &mut *peer_state_lock;
-               let (chan, funding_msg, monitor) =
+               let (chan, funding_msg_opt, monitor) =
                        match peer_state.channel_by_id.remove(&msg.temporary_channel_id) {
                                Some(ChannelPhase::UnfundedInboundV1(inbound_chan)) => {
                                        match inbound_chan.funding_created(msg, best_block, &self.signer_provider, &self.logger) {
@@ -6252,9 +6153,12 @@ where
                                None => return Err(MsgHandleErrInternal::send_err_msg_no_close(format!("Got a message for a channel from the wrong node! No such channel for the passed counterparty_node_id {}", counterparty_node_id), msg.temporary_channel_id))
                        };
 
-               match peer_state.channel_by_id.entry(funding_msg.channel_id) {
+               match peer_state.channel_by_id.entry(chan.context.channel_id()) {
                        hash_map::Entry::Occupied(_) => {
-                               Err(MsgHandleErrInternal::send_err_msg_no_close("Already had channel with the new channel_id".to_owned(), funding_msg.channel_id))
+                               Err(MsgHandleErrInternal::send_err_msg_no_close(
+                                       "Already had channel with the new channel_id".to_owned(),
+                                       chan.context.channel_id()
+                               ))
                        },
                        hash_map::Entry::Vacant(e) => {
                                let mut id_to_peer_lock = self.id_to_peer.lock().unwrap();
@@ -6262,7 +6166,7 @@ where
                                        hash_map::Entry::Occupied(_) => {
                                                return Err(MsgHandleErrInternal::send_err_msg_no_close(
                                                        "The funding_created message had the same funding_txid as an existing channel - funding is not possible".to_owned(),
-                                                       funding_msg.channel_id))
+                                                       chan.context.channel_id()))
                                        },
                                        hash_map::Entry::Vacant(i_e) => {
                                                let monitor_res = self.chain_monitor.watch_channel(monitor.get_funding_txo().0, monitor);
@@ -6274,10 +6178,12 @@ where
                                                        // hasn't persisted to disk yet - we can't lose money on a transaction that we haven't
                                                        // accepted payment from yet. We do, however, need to wait to send our channel_ready
                                                        // until we have persisted our monitor.
-                                                       peer_state.pending_msg_events.push(events::MessageSendEvent::SendFundingSigned {
-                                                               node_id: counterparty_node_id.clone(),
-                                                               msg: funding_msg,
-                                                       });
+                                                       if let Some(msg) = funding_msg_opt {
+                                                               peer_state.pending_msg_events.push(events::MessageSendEvent::SendFundingSigned {
+                                                                       node_id: counterparty_node_id.clone(),
+                                                                       msg,
+                                                               });
+                                                       }
 
                                                        if let ChannelPhase::Funded(chan) = e.insert(ChannelPhase::Funded(chan)) {
                                                                handle_new_monitor_update!(self, persist_state, peer_state_lock, peer_state,
@@ -6288,9 +6194,13 @@ where
                                                        Ok(())
                                                } else {
                                                        log_error!(self.logger, "Persisting initial ChannelMonitor failed, implying the funding outpoint was duplicated");
+                                                       let channel_id = match funding_msg_opt {
+                                                               Some(msg) => msg.channel_id,
+                                                               None => chan.context.channel_id(),
+                                                       };
                                                        return Err(MsgHandleErrInternal::send_err_msg_no_close(
                                                                "The funding_created message had the same funding_txid as an existing channel - funding is not possible".to_owned(),
-                                                               funding_msg.channel_id));
+                                                               channel_id));
                                                }
                                        }
                                }
@@ -6545,8 +6455,12 @@ where
                                                // but if we've sent a shutdown and they haven't acknowledged it yet, we just
                                                // want to reject the new HTLC and fail it backwards instead of forwarding.
                                                match pending_forward_info {
-                                                       PendingHTLCStatus::Forward(PendingHTLCInfo { ref incoming_shared_secret, .. }) => {
-                                                               let reason = if (error_code & 0x1000) != 0 {
+                                                       PendingHTLCStatus::Forward(PendingHTLCInfo {
+                                                               ref incoming_shared_secret, ref routing, ..
+                                                       }) => {
+                                                               let reason = if routing.blinded_failure().is_some() {
+                                                                       HTLCFailReason::reason(INVALID_ONION_BLINDING, vec![0; 32])
+                                                               } else if (error_code & 0x1000) != 0 {
                                                                        let (real_code, error_data) = self.get_htlc_inbound_temp_fail_err_and_data(error_code, chan);
                                                                        HTLCFailReason::reason(real_code, error_data)
                                                                } else {
@@ -6725,7 +6639,7 @@ where
                                                        if !is_our_scid && forward_info.incoming_amt_msat.is_some() &&
                                                           fake_scid::is_valid_intercept(&self.fake_scid_rand_bytes, scid, &self.chain_hash)
                                                        {
-                                                               let intercept_id = InterceptId(Sha256::hash(&forward_info.incoming_shared_secret).into_inner());
+                                                               let intercept_id = InterceptId(Sha256::hash(&forward_info.incoming_shared_secret).to_byte_array());
                                                                let mut pending_intercepts = self.pending_intercepted_htlcs.lock().unwrap();
                                                                match pending_intercepts.entry(intercept_id) {
                                                                        hash_map::Entry::Vacant(entry) => {
@@ -6748,6 +6662,7 @@ where
                                                                                        htlc_id: prev_htlc_id,
                                                                                        incoming_packet_shared_secret: forward_info.incoming_shared_secret,
                                                                                        phantom_shared_secret: None,
+                                                                                       blinded_failure: forward_info.routing.blinded_failure(),
                                                                                });
 
                                                                                failed_intercept_forwards.push((htlc_source, forward_info.payment_hash,
@@ -7216,6 +7131,66 @@ where
                has_update
        }
 
+       /// When a call to a [`ChannelSigner`] method returns an error, this indicates that the signer
+       /// is (temporarily) unavailable, and the operation should be retried later.
+       ///
+       /// This method allows for that retry - either checking for any signer-pending messages to be
+       /// attempted in every channel, or in the specifically provided channel.
+       ///
+       /// [`ChannelSigner`]: crate::sign::ChannelSigner
+       #[cfg(test)] // This is only implemented for one signer method, and should be private until we
+                    // actually finish implementing it fully.
+       pub fn signer_unblocked(&self, channel_opt: Option<(PublicKey, ChannelId)>) {
+               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
+
+               let unblock_chan = |phase: &mut ChannelPhase<SP>, pending_msg_events: &mut Vec<MessageSendEvent>| {
+                       let node_id = phase.context().get_counterparty_node_id();
+                       if let ChannelPhase::Funded(chan) = phase {
+                               let msgs = chan.signer_maybe_unblocked(&self.logger);
+                               if let Some(updates) = msgs.commitment_update {
+                                       pending_msg_events.push(events::MessageSendEvent::UpdateHTLCs {
+                                               node_id,
+                                               updates,
+                                       });
+                               }
+                               if let Some(msg) = msgs.funding_signed {
+                                       pending_msg_events.push(events::MessageSendEvent::SendFundingSigned {
+                                               node_id,
+                                               msg,
+                                       });
+                               }
+                               if let Some(msg) = msgs.funding_created {
+                                       pending_msg_events.push(events::MessageSendEvent::SendFundingCreated {
+                                               node_id,
+                                               msg,
+                                       });
+                               }
+                               if let Some(msg) = msgs.channel_ready {
+                                       send_channel_ready!(self, pending_msg_events, chan, msg);
+                               }
+                       }
+               };
+
+               let per_peer_state = self.per_peer_state.read().unwrap();
+               if let Some((counterparty_node_id, channel_id)) = channel_opt {
+                       if let Some(peer_state_mutex) = per_peer_state.get(&counterparty_node_id) {
+                               let mut peer_state_lock = peer_state_mutex.lock().unwrap();
+                               let peer_state = &mut *peer_state_lock;
+                               if let Some(chan) = peer_state.channel_by_id.get_mut(&channel_id) {
+                                       unblock_chan(chan, &mut peer_state.pending_msg_events);
+                               }
+                       }
+               } else {
+                       for (_cp_id, peer_state_mutex) in per_peer_state.iter() {
+                               let mut peer_state_lock = peer_state_mutex.lock().unwrap();
+                               let peer_state = &mut *peer_state_lock;
+                               for (_, chan) in peer_state.channel_by_id.iter_mut() {
+                                       unblock_chan(chan, &mut peer_state.pending_msg_events);
+                               }
+                       }
+               }
+       }
+
        /// Check whether any channels have finished removing all pending updates after a shutdown
        /// exchange and can now send a closing_signed.
        /// Returns whether any closing_signed messages were generated.
@@ -7908,7 +7883,7 @@ where
 
 impl<M: Deref, T: Deref, ES: Deref, NS: Deref, SP: Deref, F: Deref, R: Deref, L: Deref> MessageSendEventsProvider for ChannelManager<M, T, ES, NS, SP, F, R, L>
 where
-       M::Target: chain::Watch<<SP::Target as SignerProvider>::Signer>,
+       M::Target: chain::Watch<<SP::Target as SignerProvider>::EcdsaSigner>,
        T::Target: BroadcasterInterface,
        ES::Target: EntropySource,
        NS::Target: NodeSigner,
@@ -7970,7 +7945,7 @@ where
 
 impl<M: Deref, T: Deref, ES: Deref, NS: Deref, SP: Deref, F: Deref, R: Deref, L: Deref> EventsProvider for ChannelManager<M, T, ES, NS, SP, F, R, L>
 where
-       M::Target: chain::Watch<<SP::Target as SignerProvider>::Signer>,
+       M::Target: chain::Watch<<SP::Target as SignerProvider>::EcdsaSigner>,
        T::Target: BroadcasterInterface,
        ES::Target: EntropySource,
        NS::Target: NodeSigner,
@@ -7991,7 +7966,7 @@ where
 
 impl<M: Deref, T: Deref, ES: Deref, NS: Deref, SP: Deref, F: Deref, R: Deref, L: Deref> chain::Listen for ChannelManager<M, T, ES, NS, SP, F, R, L>
 where
-       M::Target: chain::Watch<<SP::Target as SignerProvider>::Signer>,
+       M::Target: chain::Watch<<SP::Target as SignerProvider>::EcdsaSigner>,
        T::Target: BroadcasterInterface,
        ES::Target: EntropySource,
        NS::Target: NodeSigner,
@@ -8000,7 +7975,7 @@ where
        R::Target: Router,
        L::Target: Logger,
 {
-       fn filtered_block_connected(&self, header: &BlockHeader, txdata: &TransactionData, height: u32) {
+       fn filtered_block_connected(&self, header: &Header, txdata: &TransactionData, height: u32) {
                {
                        let best_block = self.best_block.read().unwrap();
                        assert_eq!(best_block.block_hash(), header.prev_blockhash,
@@ -8013,7 +7988,7 @@ where
                self.best_block_updated(header, height);
        }
 
-       fn block_disconnected(&self, header: &BlockHeader, height: u32) {
+       fn block_disconnected(&self, header: &Header, height: u32) {
                let _persistence_guard =
                        PersistenceNotifierGuard::optionally_notify_skipping_background_events(
                                self, || -> NotifyOption { NotifyOption::DoPersist });
@@ -8033,7 +8008,7 @@ where
 
 impl<M: Deref, T: Deref, ES: Deref, NS: Deref, SP: Deref, F: Deref, R: Deref, L: Deref> chain::Confirm for ChannelManager<M, T, ES, NS, SP, F, R, L>
 where
-       M::Target: chain::Watch<<SP::Target as SignerProvider>::Signer>,
+       M::Target: chain::Watch<<SP::Target as SignerProvider>::EcdsaSigner>,
        T::Target: BroadcasterInterface,
        ES::Target: EntropySource,
        NS::Target: NodeSigner,
@@ -8042,7 +8017,7 @@ where
        R::Target: Router,
        L::Target: Logger,
 {
-       fn transactions_confirmed(&self, header: &BlockHeader, txdata: &TransactionData, height: u32) {
+       fn transactions_confirmed(&self, header: &Header, txdata: &TransactionData, height: u32) {
                // Note that we MUST NOT end up calling methods on self.chain_monitor here - we're called
                // during initialization prior to the chain_monitor being fully configured in some cases.
                // See the docs for `ChannelManagerReadArgs` for more.
@@ -8063,7 +8038,7 @@ where
                }
        }
 
-       fn best_block_updated(&self, header: &BlockHeader, height: u32) {
+       fn best_block_updated(&self, header: &Header, height: u32) {
                // Note that we MUST NOT end up calling methods on self.chain_monitor here - we're called
                // during initialization prior to the chain_monitor being fully configured in some cases.
                // See the docs for `ChannelManagerReadArgs` for more.
@@ -8101,14 +8076,17 @@ where
                });
        }
 
-       fn get_relevant_txids(&self) -> Vec<(Txid, Option<BlockHash>)> {
+       fn get_relevant_txids(&self) -> Vec<(Txid, u32, Option<BlockHash>)> {
                let mut res = Vec::with_capacity(self.short_to_chan_info.read().unwrap().len());
                for (_cp_id, peer_state_mutex) in self.per_peer_state.read().unwrap().iter() {
                        let mut peer_state_lock = peer_state_mutex.lock().unwrap();
                        let peer_state = &mut *peer_state_lock;
                        for chan in peer_state.channel_by_id.values().filter_map(|phase| if let ChannelPhase::Funded(chan) = phase { Some(chan) } else { None }) {
-                               if let (Some(funding_txo), Some(block_hash)) = (chan.context.get_funding_txo(), chan.context.get_funding_tx_confirmed_in()) {
-                                       res.push((funding_txo.txid, Some(block_hash)));
+                               let txid_opt = chan.context.get_funding_txo();
+                               let height_opt = chan.context.get_funding_tx_confirmation_height();
+                               let hash_opt = chan.context.get_funding_tx_confirmed_in();
+                               if let (Some(funding_txo), Some(conf_height), Some(block_hash)) = (txid_opt, height_opt, hash_opt) {
+                                       res.push((funding_txo.txid, conf_height, Some(block_hash)));
                                }
                        }
                }
@@ -8131,7 +8109,7 @@ where
 
 impl<M: Deref, T: Deref, ES: Deref, NS: Deref, SP: Deref, F: Deref, R: Deref, L: Deref> ChannelManager<M, T, ES, NS, SP, F, R, L>
 where
-       M::Target: chain::Watch<<SP::Target as SignerProvider>::Signer>,
+       M::Target: chain::Watch<<SP::Target as SignerProvider>::EcdsaSigner>,
        T::Target: BroadcasterInterface,
        ES::Target: EntropySource,
        NS::Target: NodeSigner,
@@ -8281,6 +8259,7 @@ where
                                                incoming_packet_shared_secret: htlc.forward_info.incoming_shared_secret,
                                                phantom_shared_secret: None,
                                                outpoint: htlc.prev_funding_outpoint,
+                                               blinded_failure: htlc.forward_info.routing.blinded_failure(),
                                        });
 
                                        let requested_forward_scid /* intercept scid */ = match htlc.forward_info.routing {
@@ -8375,7 +8354,7 @@ where
 impl<M: Deref, T: Deref, ES: Deref, NS: Deref, SP: Deref, F: Deref, R: Deref, L: Deref>
        ChannelMessageHandler for ChannelManager<M, T, ES, NS, SP, F, R, L>
 where
-       M::Target: chain::Watch<<SP::Target as SignerProvider>::Signer>,
+       M::Target: chain::Watch<<SP::Target as SignerProvider>::EcdsaSigner>,
        T::Target: BroadcasterInterface,
        ES::Target: EntropySource,
        NS::Target: NodeSigner,
@@ -8450,6 +8429,30 @@ where
                });
        }
 
+       fn handle_stfu(&self, counterparty_node_id: &PublicKey, msg: &msgs::Stfu) {
+               let _: Result<(), _> = handle_error!(self, Err(MsgHandleErrInternal::send_err_msg_no_close(
+                       "Quiescence not supported".to_owned(),
+                        msg.channel_id.clone())), *counterparty_node_id);
+       }
+
+       fn handle_splice(&self, counterparty_node_id: &PublicKey, msg: &msgs::Splice) {
+               let _: Result<(), _> = handle_error!(self, Err(MsgHandleErrInternal::send_err_msg_no_close(
+                       "Splicing not supported".to_owned(),
+                        msg.channel_id.clone())), *counterparty_node_id);
+       }
+
+       fn handle_splice_ack(&self, counterparty_node_id: &PublicKey, msg: &msgs::SpliceAck) {
+               let _: Result<(), _> = handle_error!(self, Err(MsgHandleErrInternal::send_err_msg_no_close(
+                       "Splicing not supported (splice_ack)".to_owned(),
+                        msg.channel_id.clone())), *counterparty_node_id);
+       }
+
+       fn handle_splice_locked(&self, counterparty_node_id: &PublicKey, msg: &msgs::SpliceLocked) {
+               let _: Result<(), _> = handle_error!(self, Err(MsgHandleErrInternal::send_err_msg_no_close(
+                       "Splicing not supported (splice_locked)".to_owned(),
+                        msg.channel_id.clone())), *counterparty_node_id);
+       }
+
        fn handle_shutdown(&self, counterparty_node_id: &PublicKey, msg: &msgs::Shutdown) {
                let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
                let _ = handle_error!(self, self.internal_shutdown(counterparty_node_id, msg), *counterparty_node_id);
@@ -8618,6 +8621,12 @@ where
                                                // Common Channel Establishment
                                                &events::MessageSendEvent::SendChannelReady { .. } => false,
                                                &events::MessageSendEvent::SendAnnouncementSignatures { .. } => false,
+                                               // Quiescence
+                                               &events::MessageSendEvent::SendStfu { .. } => false,
+                                               // Splicing
+                                               &events::MessageSendEvent::SendSplice { .. } => false,
+                                               &events::MessageSendEvent::SendSpliceAck { .. } => false,
+                                               &events::MessageSendEvent::SendSpliceLocked { .. } => false,
                                                // Interactive Transaction Construction
                                                &events::MessageSendEvent::SendTxAddInput { .. } => false,
                                                &events::MessageSendEvent::SendTxAddOutput { .. } => false,
@@ -8899,7 +8908,7 @@ where
 impl<M: Deref, T: Deref, ES: Deref, NS: Deref, SP: Deref, F: Deref, R: Deref, L: Deref>
 OffersMessageHandler for ChannelManager<M, T, ES, NS, SP, F, R, L>
 where
-       M::Target: chain::Watch<<SP::Target as SignerProvider>::Signer>,
+       M::Target: chain::Watch<<SP::Target as SignerProvider>::EcdsaSigner>,
        T::Target: BroadcasterInterface,
        ES::Target: EntropySource,
        NS::Target: NodeSigner,
@@ -9214,9 +9223,14 @@ impl_writeable_tlv_based!(PhantomRouteHints, {
        (6, real_node_pubkey, required),
 });
 
+impl_writeable_tlv_based!(BlindedForward, {
+       (0, inbound_blinding_point, required),
+});
+
 impl_writeable_tlv_based_enum!(PendingHTLCRouting,
        (0, Forward) => {
                (0, onion_packet, required),
+               (1, blinded, option),
                (2, short_channel_id, required),
        },
        (1, Receive) => {
@@ -9318,10 +9332,15 @@ impl_writeable_tlv_based_enum!(PendingHTLCStatus, ;
        (1, Fail),
 );
 
+impl_writeable_tlv_based_enum!(BlindedFailure,
+       (0, FromIntroductionNode) => {}, ;
+);
+
 impl_writeable_tlv_based!(HTLCPreviousHopData, {
        (0, short_channel_id, required),
        (1, phantom_shared_secret, option),
        (2, outpoint, required),
+       (3, blinded_failure, option),
        (4, htlc_id, required),
        (6, incoming_packet_shared_secret, required),
        (7, user_channel_id, option),
@@ -9496,7 +9515,7 @@ impl_writeable_tlv_based!(PendingInboundPayment, {
 
 impl<M: Deref, T: Deref, ES: Deref, NS: Deref, SP: Deref, F: Deref, R: Deref, L: Deref> Writeable for ChannelManager<M, T, ES, NS, SP, F, R, L>
 where
-       M::Target: chain::Watch<<SP::Target as SignerProvider>::Signer>,
+       M::Target: chain::Watch<<SP::Target as SignerProvider>::EcdsaSigner>,
        T::Target: BroadcasterInterface,
        ES::Target: EntropySource,
        NS::Target: NodeSigner,
@@ -9800,7 +9819,7 @@ impl_writeable_tlv_based_enum!(ChannelShutdownState,
 /// [`ChainMonitor`]: crate::chain::chainmonitor::ChainMonitor
 pub struct ChannelManagerReadArgs<'a, M: Deref, T: Deref, ES: Deref, NS: Deref, SP: Deref, F: Deref, R: Deref, L: Deref>
 where
-       M::Target: chain::Watch<<SP::Target as SignerProvider>::Signer>,
+       M::Target: chain::Watch<<SP::Target as SignerProvider>::EcdsaSigner>,
        T::Target: BroadcasterInterface,
        ES::Target: EntropySource,
        NS::Target: NodeSigner,
@@ -9859,13 +9878,13 @@ where
        /// this struct.
        ///
        /// This is not exported to bindings users because we have no HashMap bindings
-       pub channel_monitors: HashMap<OutPoint, &'a mut ChannelMonitor<<SP::Target as SignerProvider>::Signer>>,
+       pub channel_monitors: HashMap<OutPoint, &'a mut ChannelMonitor<<SP::Target as SignerProvider>::EcdsaSigner>>,
 }
 
 impl<'a, M: Deref, T: Deref, ES: Deref, NS: Deref, SP: Deref, F: Deref, R: Deref, L: Deref>
                ChannelManagerReadArgs<'a, M, T, ES, NS, SP, F, R, L>
 where
-       M::Target: chain::Watch<<SP::Target as SignerProvider>::Signer>,
+       M::Target: chain::Watch<<SP::Target as SignerProvider>::EcdsaSigner>,
        T::Target: BroadcasterInterface,
        ES::Target: EntropySource,
        NS::Target: NodeSigner,
@@ -9878,7 +9897,7 @@ where
        /// HashMap for you. This is primarily useful for C bindings where it is not practical to
        /// populate a HashMap directly from C.
        pub fn new(entropy_source: ES, node_signer: NS, signer_provider: SP, fee_estimator: F, chain_monitor: M, tx_broadcaster: T, router: R, logger: L, default_config: UserConfig,
-                       mut channel_monitors: Vec<&'a mut ChannelMonitor<<SP::Target as SignerProvider>::Signer>>) -> Self {
+                       mut channel_monitors: Vec<&'a mut ChannelMonitor<<SP::Target as SignerProvider>::EcdsaSigner>>) -> Self {
                Self {
                        entropy_source, node_signer, signer_provider, fee_estimator, chain_monitor, tx_broadcaster, router, logger, default_config,
                        channel_monitors: channel_monitors.drain(..).map(|monitor| { (monitor.get_funding_txo().0, monitor) }).collect()
@@ -9891,7 +9910,7 @@ where
 impl<'a, M: Deref, T: Deref, ES: Deref, NS: Deref, SP: Deref, F: Deref, R: Deref, L: Deref>
        ReadableArgs<ChannelManagerReadArgs<'a, M, T, ES, NS, SP, F, R, L>> for (BlockHash, Arc<ChannelManager<M, T, ES, NS, SP, F, R, L>>)
 where
-       M::Target: chain::Watch<<SP::Target as SignerProvider>::Signer>,
+       M::Target: chain::Watch<<SP::Target as SignerProvider>::EcdsaSigner>,
        T::Target: BroadcasterInterface,
        ES::Target: EntropySource,
        NS::Target: NodeSigner,
@@ -9909,7 +9928,7 @@ where
 impl<'a, M: Deref, T: Deref, ES: Deref, NS: Deref, SP: Deref, F: Deref, R: Deref, L: Deref>
        ReadableArgs<ChannelManagerReadArgs<'a, M, T, ES, NS, SP, F, R, L>> for (BlockHash, ChannelManager<M, T, ES, NS, SP, F, R, L>)
 where
-       M::Target: chain::Watch<<SP::Target as SignerProvider>::Signer>,
+       M::Target: chain::Watch<<SP::Target as SignerProvider>::EcdsaSigner>,
        T::Target: BroadcasterInterface,
        ES::Target: EntropySource,
        NS::Target: NodeSigner,
@@ -10770,7 +10789,7 @@ mod tests {
        use crate::events::{Event, HTLCDestination, MessageSendEvent, MessageSendEventsProvider, ClosureReason};
        use crate::ln::{PaymentPreimage, PaymentHash, PaymentSecret};
        use crate::ln::ChannelId;
-       use crate::ln::channelmanager::{inbound_payment, PaymentId, PaymentSendFailure, RecipientOnionFields, InterceptId};
+       use crate::ln::channelmanager::{create_recv_pending_htlc_info, inbound_payment, PaymentId, PaymentSendFailure, RecipientOnionFields, InterceptId};
        use crate::ln::functional_test_utils::*;
        use crate::ln::msgs::{self, ErrorAction};
        use crate::ln::msgs::ChannelMessageHandler;
@@ -11150,7 +11169,7 @@ mod tests {
                let _chan = create_chan_between_nodes(&nodes[0], &nodes[1]);
                let route_params = RouteParameters::from_payment_params_and_value(
                        PaymentParameters::for_keysend(payee_pubkey, 40, false), 10_000);
-               let network_graph = nodes[0].network_graph.clone();
+               let network_graph = nodes[0].network_graph;
                let first_hops = nodes[0].node.list_usable_channels();
                let scorer = test_utils::TestScorer::new();
                let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes();
@@ -11195,7 +11214,7 @@ mod tests {
                let _chan = create_chan_between_nodes(&nodes[0], &nodes[1]);
                let route_params = RouteParameters::from_payment_params_and_value(
                        PaymentParameters::for_keysend(payee_pubkey, 40, false), 10_000);
-               let network_graph = nodes[0].network_graph.clone();
+               let network_graph = nodes[0].network_graph;
                let first_hops = nodes[0].node.list_usable_channels();
                let scorer = test_utils::TestScorer::new();
                let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes();
@@ -11206,7 +11225,7 @@ mod tests {
 
                let test_preimage = PaymentPreimage([42; 32]);
                let test_secret = PaymentSecret([43; 32]);
-               let payment_hash = PaymentHash(Sha256::hash(&test_preimage.0).into_inner());
+               let payment_hash = PaymentHash(Sha256::hash(&test_preimage.0).to_byte_array());
                let session_privs = nodes[0].node.test_add_new_pending_payment(payment_hash,
                        RecipientOnionFields::secret_only(test_secret), PaymentId(payment_hash.0), &route).unwrap();
                nodes[0].node.test_send_payment_internal(&route, payment_hash,
@@ -11331,14 +11350,14 @@ mod tests {
                let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
                let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
 
-               nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 1_000_000, 500_000_000, 42, None).unwrap();
+               nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 1_000_000, 500_000_000, 42, None, None).unwrap();
                let open_channel = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
                nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), &open_channel);
                let accept_channel = get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id());
                nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), &accept_channel);
 
                let (temporary_channel_id, tx, _funding_output) = create_funding_transaction(&nodes[0], &nodes[1].node.get_our_node_id(), 1_000_000, 42);
-               let channel_id = ChannelId::from_bytes(tx.txid().into_inner());
+               let channel_id = ChannelId::from_bytes(tx.txid().to_byte_array());
                {
                        // Ensure that the `id_to_peer` map is empty until either party has received the
                        // funding transaction, and have the real `channel_id`.
@@ -11489,7 +11508,7 @@ mod tests {
                let intercept_id = InterceptId([0; 32]);
 
                // Test the API functions.
-               check_not_connected_to_peer_error(nodes[0].node.create_channel(unkown_public_key, 1_000_000, 500_000_000, 42, None), unkown_public_key);
+               check_not_connected_to_peer_error(nodes[0].node.create_channel(unkown_public_key, 1_000_000, 500_000_000, 42, None, None), unkown_public_key);
 
                check_unkown_peer_error(nodes[0].node.accept_inbound_channel(&channel_id, &unkown_public_key, 42), unkown_public_key);
 
@@ -11544,7 +11563,7 @@ mod tests {
 
                // Note that create_network connects the nodes together for us
 
-               nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, 0, 42, None).unwrap();
+               nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, 0, 42, None, None).unwrap();
                let mut open_channel_msg = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
 
                let mut funding_tx = None;
@@ -11631,7 +11650,7 @@ mod tests {
                        open_channel_msg.temporary_channel_id);
 
                // Of course, however, outbound channels are always allowed
-               nodes[1].node.create_channel(last_random_pk, 100_000, 0, 42, None).unwrap();
+               nodes[1].node.create_channel(last_random_pk, 100_000, 0, 42, None, None).unwrap();
                get_event_msg!(nodes[1], MessageSendEvent::SendOpenChannel, last_random_pk);
 
                // If we fund the first channel, nodes[0] has a live on-chain channel with us, it is now
@@ -11658,7 +11677,7 @@ mod tests {
 
                // Note that create_network connects the nodes together for us
 
-               nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, 0, 42, None).unwrap();
+               nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, 0, 42, None, None).unwrap();
                let mut open_channel_msg = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
 
                for _ in 0..super::MAX_UNFUNDED_CHANS_PER_PEER {
@@ -11674,7 +11693,7 @@ mod tests {
                        open_channel_msg.temporary_channel_id);
 
                // but we can still open an outbound channel.
-               nodes[1].node.create_channel(nodes[0].node.get_our_node_id(), 100_000, 0, 42, None).unwrap();
+               nodes[1].node.create_channel(nodes[0].node.get_our_node_id(), 100_000, 0, 42, None, None).unwrap();
                get_event_msg!(nodes[1], MessageSendEvent::SendOpenChannel, nodes[0].node.get_our_node_id());
 
                // but even with such an outbound channel, additional inbound channels will still fail.
@@ -11696,7 +11715,7 @@ mod tests {
 
                // Note that create_network connects the nodes together for us
 
-               nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, 0, 42, None).unwrap();
+               nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, 0, 42, None, None).unwrap();
                let mut open_channel_msg = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
 
                // First, get us up to MAX_UNFUNDED_CHANNEL_PEERS so we can test at the edge
@@ -11772,9 +11791,11 @@ mod tests {
                };
                // Check that if the amount we received + the penultimate hop extra fee is less than the sender
                // intended amount, we fail the payment.
+               let current_height: u32 = node[0].node.best_block.read().unwrap().height();
                if let Err(crate::ln::channelmanager::InboundOnionErr { err_code, .. }) =
-                       node[0].node.construct_recv_pending_htlc_info(hop_data, [0; 32], PaymentHash([0; 32]),
-                               sender_intended_amt_msat - extra_fee_msat - 1, 42, None, true, Some(extra_fee_msat))
+                       create_recv_pending_htlc_info(hop_data, [0; 32], PaymentHash([0; 32]),
+                               sender_intended_amt_msat - extra_fee_msat - 1, 42, None, true, Some(extra_fee_msat),
+                               current_height, node[0].node.default_configuration.accept_mpp_keysend)
                {
                        assert_eq!(err_code, 19);
                } else { panic!(); }
@@ -11790,8 +11811,10 @@ mod tests {
                        }),
                        custom_tlvs: Vec::new(),
                };
-               assert!(node[0].node.construct_recv_pending_htlc_info(hop_data, [0; 32], PaymentHash([0; 32]),
-                       sender_intended_amt_msat - extra_fee_msat, 42, None, true, Some(extra_fee_msat)).is_ok());
+               let current_height: u32 = node[0].node.best_block.read().unwrap().height();
+               assert!(create_recv_pending_htlc_info(hop_data, [0; 32], PaymentHash([0; 32]),
+                       sender_intended_amt_msat - extra_fee_msat, 42, None, true, Some(extra_fee_msat),
+                       current_height, node[0].node.default_configuration.accept_mpp_keysend).is_ok());
        }
 
        #[test]
@@ -11801,7 +11824,8 @@ mod tests {
                let node_chanmgr = create_node_chanmgrs(1, &node_cfg, &[None]);
                let node = create_network(1, &node_cfg, &node_chanmgr);
 
-               let result = node[0].node.construct_recv_pending_htlc_info(msgs::InboundOnionPayload::Receive {
+               let current_height: u32 = node[0].node.best_block.read().unwrap().height();
+               let result = create_recv_pending_htlc_info(msgs::InboundOnionPayload::Receive {
                        amt_msat: 100,
                        outgoing_cltv_value: 22,
                        payment_metadata: None,
@@ -11810,7 +11834,8 @@ mod tests {
                                payment_secret: PaymentSecret([0; 32]), total_msat: 100,
                        }),
                        custom_tlvs: Vec::new(),
-               }, [0; 32], PaymentHash([0; 32]), 100, 23, None, true, None);
+               }, [0; 32], PaymentHash([0; 32]), 100, 23, None, true, None, current_height,
+                       node[0].node.default_configuration.accept_mpp_keysend);
 
                // Should not return an error as this condition:
                // https://github.com/lightning/bolts/blob/4dcc377209509b13cf89a4b91fde7d478f5b46d8/04-onion-routing.md?plain=1#L334
@@ -11834,7 +11859,7 @@ mod tests {
                        &[Some(anchors_cfg.clone()), Some(anchors_cfg.clone()), Some(anchors_manual_accept_cfg.clone())]);
                let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
 
-               nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, 0, 42, None).unwrap();
+               nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, 0, 42, None, None).unwrap();
                let open_channel_msg = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
 
                nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), &open_channel_msg);
@@ -11875,7 +11900,7 @@ mod tests {
                let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[Some(anchors_config.clone()), Some(anchors_config.clone())]);
                let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
 
-               nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, 0, 0, None).unwrap();
+               nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, 0, 0, None, None).unwrap();
                let open_channel_msg = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
                assert!(open_channel_msg.channel_type.as_ref().unwrap().supports_anchors_zero_fee_htlc_tx());
 
@@ -12060,9 +12085,10 @@ pub mod bench {
        use crate::util::test_utils;
        use crate::util::config::{UserConfig, MaxDustHTLCExposure};
 
+       use bitcoin::blockdata::locktime::absolute::LockTime;
        use bitcoin::hashes::Hash;
        use bitcoin::hashes::sha256::Hash as Sha256;
-       use bitcoin::{Block, BlockHeader, PackedLockTime, Transaction, TxMerkleNode, TxOut};
+       use bitcoin::{Block, Transaction, TxOut};
 
        use crate::sync::{Arc, Mutex, RwLock};
 
@@ -12133,13 +12159,13 @@ pub mod bench {
                node_b.peer_connected(&node_a.get_our_node_id(), &Init {
                        features: node_a.init_features(), networks: None, remote_network_address: None
                }, false).unwrap();
-               node_a.create_channel(node_b.get_our_node_id(), 8_000_000, 100_000_000, 42, None).unwrap();
+               node_a.create_channel(node_b.get_our_node_id(), 8_000_000, 100_000_000, 42, None, None).unwrap();
                node_b.handle_open_channel(&node_a.get_our_node_id(), &get_event_msg!(node_a_holder, MessageSendEvent::SendOpenChannel, node_b.get_our_node_id()));
                node_a.handle_accept_channel(&node_b.get_our_node_id(), &get_event_msg!(node_b_holder, MessageSendEvent::SendAcceptChannel, node_a.get_our_node_id()));
 
                let tx;
                if let Event::FundingGenerationReady { temporary_channel_id, output_script, .. } = get_event!(node_a_holder, Event::FundingGenerationReady) {
-                       tx = Transaction { version: 2, lock_time: PackedLockTime::ZERO, input: Vec::new(), output: vec![TxOut {
+                       tx = Transaction { version: 2, lock_time: LockTime::ZERO, input: Vec::new(), output: vec![TxOut {
                                value: 8_000_000, script_pubkey: output_script,
                        }]};
                        node_a.funding_transaction_generated(&temporary_channel_id, &node_b.get_our_node_id(), tx.clone()).unwrap();
@@ -12212,7 +12238,7 @@ pub mod bench {
                                let mut payment_preimage = PaymentPreimage([0; 32]);
                                payment_preimage.0[0..8].copy_from_slice(&payment_count.to_le_bytes());
                                payment_count += 1;
-                               let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0[..]).into_inner());
+                               let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0[..]).to_byte_array());
                                let payment_secret = $node_b.create_inbound_payment_for_hash(payment_hash, None, 7200, None).unwrap();
 
                                $node_a.send_payment(payment_hash, RecipientOnionFields::secret_only(payment_secret),