Correctly fail back blinded inbound fwd HTLCs when adding to a Channel
[rust-lightning] / lightning / src / ln / channelmanager.rs
index e3fe74d1a07f9bf67f7a3c83fbd06525c4ebf594..aa44a63e590d0c60547bea8cc7156d6810f7d27b 100644 (file)
@@ -53,7 +53,7 @@ use crate::routing::scoring::{ProbabilisticScorer, ProbabilisticScoringFeeParame
 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;
@@ -167,6 +167,18 @@ pub struct BlindedForward {
        // 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 struct PendingHTLCInfo {
@@ -2965,14 +2977,24 @@ where
                        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
+               };
+
                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),
                                        }));
                                }
@@ -4080,7 +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: None,
+                               blinded_failure: payment.forward_info.routing.blinded_failure(),
                        });
 
                        let failure_reason = HTLCFailReason::from_failure_code(0x4000 | 10);
@@ -4129,7 +4151,7 @@ where
                                                                                                        htlc_id: prev_htlc_id,
                                                                                                        incoming_packet_shared_secret: incoming_shared_secret,
                                                                                                        phantom_shared_secret: $phantom_ss,
-                                                                                                       blinded_failure: None,
+                                                                                                       blinded_failure: routing.blinded_failure(),
                                                                                                });
 
                                                                                                let reason = if $next_hop_unknown {
@@ -4159,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();
@@ -4234,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);
@@ -4246,11 +4270,19 @@ where
                                                                                incoming_packet_shared_secret: incoming_shared_secret,
                                                                                // Phantom payments are only PendingHTLCRouting::Receive.
                                                                                phantom_shared_secret: None,
-                                                                               blinded_failure: 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 {
@@ -4301,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());
@@ -4330,7 +4363,7 @@ where
                                                                                htlc_id: prev_htlc_id,
                                                                                incoming_packet_shared_secret: incoming_shared_secret,
                                                                                phantom_shared_secret,
-                                                                               blinded_failure: None,
+                                                                               blinded_failure,
                                                                        },
                                                                        // We differentiate the received value from the sender intended value
                                                                        // if possible so that we don't prematurely mark MPP payments complete
@@ -6408,8 +6441,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 {
@@ -6611,7 +6648,7 @@ where
                                                                                        htlc_id: prev_htlc_id,
                                                                                        incoming_packet_shared_secret: forward_info.incoming_shared_secret,
                                                                                        phantom_shared_secret: None,
-                                                                                       blinded_failure: None,
+                                                                                       blinded_failure: forward_info.routing.blinded_failure(),
                                                                                });
 
                                                                                failed_intercept_forwards.push((htlc_source, forward_info.payment_hash,
@@ -8208,7 +8245,7 @@ where
                                                incoming_packet_shared_secret: htlc.forward_info.incoming_shared_secret,
                                                phantom_shared_secret: None,
                                                outpoint: htlc.prev_funding_outpoint,
-                                               blinded_failure: None,
+                                               blinded_failure: htlc.forward_info.routing.blinded_failure(),
                                        });
 
                                        let requested_forward_scid /* intercept scid */ = match htlc.forward_info.routing {