X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fchannelmanager.rs;h=eb13f6b4aa1901620596a49af90abd3efbdf3603;hb=cf64e3fba52d7b7f6abce352948d78b97bcb9700;hp=6739e5260f52335a52c8c5b0d4090fcc412c9382;hpb=cb923c604eb51512c210457e9b494847676226f6;p=rust-lightning diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 6739e526..eb13f6b4 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -181,6 +181,7 @@ pub(super) enum HTLCForwardInfo { pub(crate) struct HTLCPreviousHopData { // Note that this may be an outbound SCID alias for the associated channel. short_channel_id: u64, + user_channel_id: Option, htlc_id: u64, incoming_packet_shared_secret: [u8; 32], phantom_shared_secret: Option<[u8; 32]>, @@ -221,6 +222,17 @@ struct ClaimableHTLC { counterparty_skimmed_fee_msat: Option, } +impl From<&ClaimableHTLC> for events::ClaimedHTLC { + fn from(val: &ClaimableHTLC) -> Self { + events::ClaimedHTLC { + channel_id: val.prev_hop.outpoint.to_channel_id(), + user_channel_id: val.prev_hop.user_channel_id.unwrap_or(0), + cltv_expiry: val.cltv_expiry, + value_msat: val.value, + } + } +} + /// A payment identifier used to uniquely identify a payment to LDK. /// /// This is not exported to bindings users as we just use [u8; 32] directly @@ -496,11 +508,15 @@ struct ClaimingPayment { amount_msat: u64, payment_purpose: events::PaymentPurpose, receiver_node_id: PublicKey, + htlcs: Vec, + sender_intended_value: Option, } impl_writeable_tlv_based!(ClaimingPayment, { (0, amount_msat, required), (2, payment_purpose, required), (4, receiver_node_id, required), + (5, htlcs, optional_vec), + (7, sender_intended_value, option), }); struct ClaimablePayment { @@ -2898,9 +2914,9 @@ where short_channel_id, amt_to_forward, outgoing_cltv_value }, .. } => { - let next_pk = onion_utils::next_hop_packet_pubkey(&self.secp_ctx, + 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_pk)) + (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. @@ -3785,6 +3801,7 @@ where if let PendingHTLCRouting::Forward { short_channel_id, .. } = payment.forward_info.routing { let htlc_source = HTLCSource::PreviousHopData(HTLCPreviousHopData { short_channel_id: payment.prev_short_channel_id, + user_channel_id: Some(payment.prev_user_channel_id), outpoint: payment.prev_funding_outpoint, htlc_id: payment.prev_htlc_id, incoming_packet_shared_secret: payment.forward_info.incoming_shared_secret, @@ -3832,6 +3849,7 @@ where let htlc_source = HTLCSource::PreviousHopData(HTLCPreviousHopData { short_channel_id: prev_short_channel_id, + user_channel_id: Some(prev_user_channel_id), outpoint: prev_funding_outpoint, htlc_id: prev_htlc_id, incoming_packet_shared_secret: incoming_shared_secret, @@ -3936,7 +3954,7 @@ where for forward_info in pending_forwards.drain(..) { match forward_info { HTLCForwardInfo::AddHTLC(PendingAddHTLCInfo { - prev_short_channel_id, prev_htlc_id, prev_funding_outpoint, prev_user_channel_id: _, + 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, .. @@ -3945,6 +3963,7 @@ where log_trace!(self.logger, "Adding HTLC from short id {} with payment_hash {} to channel with short id {} after delay", prev_short_channel_id, log_bytes!(payment_hash.0), short_chan_id); let htlc_source = HTLCSource::PreviousHopData(HTLCPreviousHopData { short_channel_id: prev_short_channel_id, + user_channel_id: Some(prev_user_channel_id), outpoint: prev_funding_outpoint, htlc_id: prev_htlc_id, incoming_packet_shared_secret: incoming_shared_secret, @@ -4026,6 +4045,7 @@ where let claimable_htlc = ClaimableHTLC { prev_hop: HTLCPreviousHopData { short_channel_id: prev_short_channel_id, + user_channel_id: Some(prev_user_channel_id), outpoint: prev_funding_outpoint, htlc_id: prev_htlc_id, incoming_packet_shared_secret: incoming_shared_secret, @@ -4055,6 +4075,7 @@ where ); failed_forwards.push((HTLCSource::PreviousHopData(HTLCPreviousHopData { short_channel_id: $htlc.prev_hop.short_channel_id, + user_channel_id: $htlc.prev_hop.user_channel_id, outpoint: prev_funding_outpoint, htlc_id: $htlc.prev_hop.htlc_id, incoming_packet_shared_secret: $htlc.prev_hop.incoming_packet_shared_secret, @@ -4786,7 +4807,7 @@ 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 }) => { + 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 {:?}", log_bytes!(payment_hash.0), onion_error); let err_packet = onion_error.get_encrypted_failure_packet(incoming_packet_shared_secret, phantom_shared_secret); @@ -4873,9 +4894,11 @@ where } } + let htlcs = payment.htlcs.iter().map(events::ClaimedHTLC::from).collect(); + let sender_intended_value = payment.htlcs.first().map(|htlc| htlc.total_msat); let dup_purpose = claimable_payments.pending_claiming_payments.insert(payment_hash, ClaimingPayment { amount_msat: payment.htlcs.iter().map(|source| source.value).sum(), - payment_purpose: payment.purpose, receiver_node_id, + payment_purpose: payment.purpose, receiver_node_id, htlcs, sender_intended_value }); if dup_purpose.is_some() { debug_assert!(false, "Shouldn't get a duplicate pending claim event ever"); @@ -5139,9 +5162,20 @@ where match action { MonitorUpdateCompletionAction::PaymentClaimed { payment_hash } => { let payment = self.claimable_payments.lock().unwrap().pending_claiming_payments.remove(&payment_hash); - if let Some(ClaimingPayment { amount_msat, payment_purpose: purpose, receiver_node_id }) = payment { + if let Some(ClaimingPayment { + amount_msat, + payment_purpose: purpose, + receiver_node_id, + htlcs, + sender_intended_value: sender_intended_total_msat, + }) = payment { self.pending_events.lock().unwrap().push_back((events::Event::PaymentClaimed { - payment_hash, purpose, amount_msat, receiver_node_id: Some(receiver_node_id), + payment_hash, + purpose, + amount_msat, + receiver_node_id: Some(receiver_node_id), + htlcs, + sender_intended_total_msat, }, None)); } }, @@ -6019,6 +6053,7 @@ where log_info!(self.logger, "Failed to forward incoming HTLC: detected duplicate intercepted payment over short channel id {}", scid); let htlc_source = HTLCSource::PreviousHopData(HTLCPreviousHopData { short_channel_id: prev_short_channel_id, + user_channel_id: Some(prev_user_channel_id), outpoint: prev_funding_outpoint, htlc_id: prev_htlc_id, incoming_packet_shared_secret: forward_info.incoming_shared_secret, @@ -7145,6 +7180,7 @@ where if height >= htlc.forward_info.outgoing_cltv_value - HTLC_FAIL_BACK_BUFFER { let prev_hop_data = HTLCSource::PreviousHopData(HTLCPreviousHopData { short_channel_id: htlc.prev_short_channel_id, + user_channel_id: Some(htlc.prev_user_channel_id), htlc_id: htlc.prev_htlc_id, incoming_packet_shared_secret: htlc.forward_info.incoming_shared_secret, phantom_shared_secret: None, @@ -7510,6 +7546,46 @@ where fn handle_error(&self, counterparty_node_id: &PublicKey, msg: &msgs::ErrorMessage) { let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self); + match &msg.data as &str { + "cannot co-op close channel w/ active htlcs"| + "link failed to shutdown" => + { + // LND hasn't properly handled shutdown messages ever, and force-closes any time we + // send one while HTLCs are still present. The issue is tracked at + // https://github.com/lightningnetwork/lnd/issues/6039 and has had multiple patches + // to fix it but none so far have managed to land upstream. The issue appears to be + // very low priority for the LND team despite being marked "P1". + // We're not going to bother handling this in a sensible way, instead simply + // repeating the Shutdown message on repeat until morale improves. + if msg.channel_id != [0; 32] { + let per_peer_state = self.per_peer_state.read().unwrap(); + let peer_state_mutex_opt = per_peer_state.get(counterparty_node_id); + if peer_state_mutex_opt.is_none() { return; } + let mut peer_state = peer_state_mutex_opt.unwrap().lock().unwrap(); + if let Some(chan) = peer_state.channel_by_id.get(&msg.channel_id) { + if let Some(msg) = chan.get_outbound_shutdown() { + peer_state.pending_msg_events.push(events::MessageSendEvent::SendShutdown { + node_id: *counterparty_node_id, + msg, + }); + } + peer_state.pending_msg_events.push(events::MessageSendEvent::HandleError { + node_id: *counterparty_node_id, + action: msgs::ErrorAction::SendWarningMessage { + msg: msgs::WarningMessage { + channel_id: msg.channel_id, + data: "You appear to be exhibiting LND bug 6039, we'll keep sending you shutdown messages until you handle them correctly".to_owned() + }, + log_level: Level::Trace, + } + }); + } + } + return; + } + _ => {} + } + if msg.channel_id == [0; 32] { let channel_ids: Vec<[u8; 32]> = { let per_peer_state = self.per_peer_state.read().unwrap(); @@ -7733,7 +7809,7 @@ impl Writeable for ChannelDetails { impl Readable for ChannelDetails { fn read(reader: &mut R) -> Result { - _init_and_read_tlv_fields!(reader, { + _init_and_read_len_prefixed_tlv_fields!(reader, { (1, inbound_scid_alias, option), (2, channel_id, required), (3, channel_type, option), @@ -7920,7 +7996,8 @@ impl_writeable_tlv_based!(HTLCPreviousHopData, { (1, phantom_shared_secret, option), (2, outpoint, required), (4, htlc_id, required), - (6, incoming_packet_shared_secret, required) + (6, incoming_packet_shared_secret, required), + (7, user_channel_id, option), }); impl Writeable for ClaimableHTLC { @@ -7946,7 +8023,7 @@ impl Writeable for ClaimableHTLC { impl Readable for ClaimableHTLC { fn read(reader: &mut R) -> Result { - _init_and_read_tlv_fields!(reader, { + _init_and_read_len_prefixed_tlv_fields!(reader, { (0, prev_hop, required), (1, total_msat, option), (2, value_ser, required), @@ -9174,7 +9251,7 @@ where .expect("Failed to get node_id for phantom node recipient"); receiver_node_id = Some(phantom_pubkey) } - for claimable_htlc in payment.htlcs { + for claimable_htlc in &payment.htlcs { claimable_amt_msat += claimable_htlc.value; // Add a holding-cell claim of the payment to the Channel, which should be @@ -9210,6 +9287,8 @@ where payment_hash, purpose: payment.purpose, amount_msat: claimable_amt_msat, + htlcs: payment.htlcs.iter().map(events::ClaimedHTLC::from).collect(), + sender_intended_total_msat: payment.htlcs.first().map(|htlc| htlc.total_msat), }, None)); } }