X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fchannelmanager.rs;fp=lightning%2Fsrc%2Fln%2Fchannelmanager.rs;h=4247d57cbb6ad199ba99842c8dae506ee08f2e25;hb=74bc9e2b4ac940f1a2a27438fa92aeea6589c747;hp=694d7734dba744af356d0b2eaa5466680316e2aa;hpb=f07f4b90f8de76d594328e11e36d094cdb936097;p=rust-lightning diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 694d7734..4247d57c 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -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; @@ -119,6 +119,8 @@ pub enum PendingHTLCRouting { /// 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 eventually when we bump MSRV + /// Set if this HTLC is being forwarded within a blinded path. + blinded: Option, }, /// 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, @@ -155,6 +157,28 @@ pub enum PendingHTLCRouting { }, } +/// 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 { + // 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 { @@ -213,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 { @@ -222,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, // This field is consumed by `claim_funds_from_hop()` when updating a force-closed backwards // channel with a preimage provided by the forward channel. @@ -2945,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), })); } @@ -4013,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 }; @@ -4058,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); @@ -4106,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 { @@ -4135,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(); @@ -4210,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); @@ -4222,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 { @@ -4276,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()); @@ -4305,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 @@ -4335,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 }, @@ -5098,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(); @@ -6381,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 { @@ -6584,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, @@ -8180,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 { @@ -9143,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) => { @@ -9247,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),