Merge pull request #2478 from waterson/settle-htlcs
authorMatt Corallo <649246+TheBlueMatt@users.noreply.github.com>
Mon, 21 Aug 2023 22:32:54 +0000 (22:32 +0000)
committerGitHub <noreply@github.com>
Mon, 21 Aug 2023 22:32:54 +0000 (22:32 +0000)
Provide the HTLCs that settled a payment.

1  2 
lightning/src/events/mod.rs
lightning/src/ln/channelmanager.rs
lightning/src/ln/functional_test_utils.rs

index 9c38daf480e75dd220d1a030f3385ca7e22f4b41,77bf2f265fad9dafdec281b1fc410ccb89229a12..d0a7bc57a784f198c61a42b1955b5709649df6aa
@@@ -79,6 -79,37 +79,37 @@@ impl_writeable_tlv_based_enum!(PaymentP
        (2, SpontaneousPayment)
  );
  
+ /// Information about an HTLC that is part of a payment that can be claimed.
+ #[derive(Clone, Debug, PartialEq, Eq)]
+ pub struct ClaimedHTLC {
+       /// The `channel_id` of the channel over which the HTLC was received.
+       pub channel_id: [u8; 32],
+       /// The `user_channel_id` of the channel over which the HTLC was received. This is the value
+       /// passed in to [`ChannelManager::create_channel`] for outbound channels, or to
+       /// [`ChannelManager::accept_inbound_channel`] for inbound channels if
+       /// [`UserConfig::manually_accept_inbound_channels`] config flag is set to true. Otherwise
+       /// `user_channel_id` will be randomized for an inbound channel.
+       ///
+       /// This field will be zero for a payment that was serialized prior to LDK version 0.0.117. (This
+       /// should only happen in the case that a payment was claimable prior to LDK version 0.0.117, but
+       /// was not actually claimed until after upgrading.)
+       ///
+       /// [`ChannelManager::create_channel`]: crate::ln::channelmanager::ChannelManager::create_channel
+       /// [`ChannelManager::accept_inbound_channel`]: crate::ln::channelmanager::ChannelManager::accept_inbound_channel
+       /// [`UserConfig::manually_accept_inbound_channels`]: crate::util::config::UserConfig::manually_accept_inbound_channels
+       pub user_channel_id: u128,
+       /// The block height at which this HTLC expires.
+       pub cltv_expiry: u32,
+       /// The amount (in msats) of this part of an MPP.
+       pub value_msat: u64,
+ }
+ impl_writeable_tlv_based!(ClaimedHTLC, {
+       (0, channel_id, required),
+       (2, user_channel_id, required),
+       (4, cltv_expiry, required),
+       (6, value_msat, required),
+ });
  /// When the payment path failure took place and extra details about it. [`PathFailure::OnPath`] may
  /// contain a [`NetworkUpdate`] that needs to be applied to the [`NetworkGraph`].
  ///
@@@ -470,6 -501,12 +501,12 @@@ pub enum Event 
                /// The purpose of the claimed payment, i.e. whether the payment was for an invoice or a
                /// spontaneous payment.
                purpose: PaymentPurpose,
+               /// The HTLCs that comprise the claimed payment. This will be empty for events serialized prior
+               /// to LDK version 0.0.117.
+               htlcs: Vec<ClaimedHTLC>,
+               /// The sender-intended sum total of all the MPP parts. This will be `None` for events
+               /// serialized prior to LDK version 0.0.117.
+               sender_intended_total_msat: Option<u64>,
        },
        /// Indicates an outbound payment we made succeeded (i.e. it made it all the way to its target
        /// and we got back the payment preimage for it).
        /// payment is no longer retryable, due either to the [`Retry`] provided or
        /// [`ChannelManager::abandon_payment`] having been called for the corresponding payment.
        ///
 +      /// In exceedingly rare cases, it is possible that an [`Event::PaymentFailed`] is generated for
 +      /// a payment after an [`Event::PaymentSent`] event for this same payment has already been
 +      /// received and processed. In this case, the [`Event::PaymentFailed`] event MUST be ignored,
 +      /// and the payment MUST be treated as having succeeded.
 +      ///
        /// [`Retry`]: crate::ln::channelmanager::Retry
        /// [`ChannelManager::abandon_payment`]: crate::ln::channelmanager::ChannelManager::abandon_payment
        PaymentFailed {
@@@ -1040,13 -1072,15 +1077,15 @@@ impl Writeable for Event 
                                // We never write the OpenChannelRequest events as, upon disconnection, peers
                                // drop any channels which have not yet exchanged funding_signed.
                        },
-                       &Event::PaymentClaimed { ref payment_hash, ref amount_msat, ref purpose, ref receiver_node_id } => {
+                       &Event::PaymentClaimed { ref payment_hash, ref amount_msat, ref purpose, ref receiver_node_id, ref htlcs, ref sender_intended_total_msat } => {
                                19u8.write(writer)?;
                                write_tlv_fields!(writer, {
                                        (0, payment_hash, required),
                                        (1, receiver_node_id, option),
                                        (2, purpose, required),
                                        (4, amount_msat, required),
+                                       (5, *htlcs, optional_vec),
+                                       (7, sender_intended_total_msat, option),
                                });
                        },
                        &Event::ProbeSuccessful { ref payment_id, ref payment_hash, ref path } => {
@@@ -1371,17 -1405,23 +1410,23 @@@ impl MaybeReadable for Event 
                                        let mut purpose = UpgradableRequired(None);
                                        let mut amount_msat = 0;
                                        let mut receiver_node_id = None;
+                                       let mut htlcs: Option<Vec<ClaimedHTLC>> = Some(vec![]);
+                                       let mut sender_intended_total_msat: Option<u64> = None;
                                        read_tlv_fields!(reader, {
                                                (0, payment_hash, required),
                                                (1, receiver_node_id, option),
                                                (2, purpose, upgradable_required),
                                                (4, amount_msat, required),
+                                               (5, htlcs, optional_vec),
+                                               (7, sender_intended_total_msat, option),
                                        });
                                        Ok(Some(Event::PaymentClaimed {
                                                receiver_node_id,
                                                payment_hash,
                                                purpose: _init_tlv_based_struct_field!(purpose, upgradable_required),
                                                amount_msat,
+                                               htlcs: htlcs.unwrap_or(vec![]),
+                                               sender_intended_total_msat,
                                        }))
                                };
                                f()
index 6739e5260f52335a52c8c5b0d4090fcc412c9382,5ad5549dc681348bc8f8eb57c56ad26773ed32d4..91ce2e5a47402c7d05bd885ce9bb602da88b7a2c
@@@ -181,6 -181,7 +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<u128>,
        htlc_id: u64,
        incoming_packet_shared_secret: [u8; 32],
        phantom_shared_secret: Option<[u8; 32]>,
@@@ -221,6 -222,17 +222,17 @@@ struct ClaimableHTLC 
        counterparty_skimmed_fee_msat: Option<u64>,
  }
  
+ 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 +508,15 @@@ struct ClaimingPayment 
        amount_msat: u64,
        payment_purpose: events::PaymentPurpose,
        receiver_node_id: PublicKey,
+       htlcs: Vec<events::ClaimedHTLC>,
+       sender_intended_value: Option<u64>,
  }
  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 {
@@@ -1144,11 -1160,7 +1160,11 @@@ wher
        /// could be in the middle of being processed without the direct mutex held.
        ///
        /// See `ChannelManager` struct-level documentation for lock order requirements.
 +      #[cfg(not(any(test, feature = "_test_utils")))]
        pending_events: Mutex<VecDeque<(events::Event, Option<EventCompletionAction>)>>,
 +      #[cfg(any(test, feature = "_test_utils"))]
 +      pub(crate) pending_events: Mutex<VecDeque<(events::Event, Option<EventCompletionAction>)>>,
 +
        /// A simple atomic flag to ensure only one task at a time can be processing events asynchronously.
        pending_events_processor: AtomicBool,
  
@@@ -3785,6 -3797,7 +3801,7 @@@ wher
                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,
  
                                                                                                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,
                                                        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, ..
                                                                                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,
                                                                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,
                                                                                );
                                                                                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,
                                        &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);
  
                                        }
                                }
  
+                               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");
                self.pending_outbound_payments.finalize_claims(sources, &self.pending_events);
        }
  
 -      fn claim_funds_internal(&self, source: HTLCSource, payment_preimage: PaymentPreimage, forwarded_htlc_value_msat: Option<u64>, from_onchain: bool, next_channel_id: [u8; 32]) {
 +      fn claim_funds_internal(&self, source: HTLCSource, payment_preimage: PaymentPreimage, forwarded_htlc_value_msat: Option<u64>, from_onchain: bool, next_channel_outpoint: OutPoint) {
                match source {
                        HTLCSource::OutboundRoute { session_priv, payment_id, path, .. } => {
                                debug_assert!(self.background_events_processed_since_startup.load(Ordering::Acquire),
                                        "We don't support claim_htlc claims during startup - monitors may not be available yet");
 -                              self.pending_outbound_payments.claim_htlc(payment_id, payment_preimage, session_priv, path, from_onchain, &self.pending_events, &self.logger);
 +                              let ev_completion_action = EventCompletionAction::ReleaseRAAChannelMonitorUpdate {
 +                                      channel_funding_outpoint: next_channel_outpoint,
 +                                      counterparty_node_id: path.hops[0].pubkey,
 +                              };
 +                              self.pending_outbound_payments.claim_htlc(payment_id, payment_preimage,
 +                                      session_priv, path, from_onchain, ev_completion_action, &self.pending_events,
 +                                      &self.logger);
                        },
                        HTLCSource::PreviousHopData(hop_data) => {
                                let prev_outpoint = hop_data.outpoint;
                                                                        fee_earned_msat,
                                                                        claim_from_onchain_tx: from_onchain,
                                                                        prev_channel_id: Some(prev_outpoint.to_channel_id()),
 -                                                                      next_channel_id: Some(next_channel_id),
 +                                                                      next_channel_id: Some(next_channel_outpoint.to_channel_id()),
                                                                        outbound_amount_forwarded_msat: forwarded_htlc_value_msat,
                                                                },
                                                                downstream_counterparty_and_funding_outpoint: None,
                        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));
                                        }
                                },
        }
  
        fn internal_update_fulfill_htlc(&self, counterparty_node_id: &PublicKey, msg: &msgs::UpdateFulfillHTLC) -> Result<(), MsgHandleErrInternal> {
 +              let funding_txo;
                let (htlc_source, forwarded_htlc_value) = {
                        let per_peer_state = self.per_peer_state.read().unwrap();
                        let peer_state_mutex = per_peer_state.get(counterparty_node_id)
                        let peer_state = &mut *peer_state_lock;
                        match peer_state.channel_by_id.entry(msg.channel_id) {
                                hash_map::Entry::Occupied(mut chan) => {
 -                                      try_chan_entry!(self, chan.get_mut().update_fulfill_htlc(&msg), chan)
 +                                      let res = try_chan_entry!(self, chan.get_mut().update_fulfill_htlc(&msg), chan);
 +                                      funding_txo = chan.get().context.get_funding_txo().expect("We won't accept a fulfill until funded");
 +                                      res
                                },
                                hash_map::Entry::Vacant(_) => 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.channel_id))
                        }
                };
 -              self.claim_funds_internal(htlc_source, msg.payment_preimage.clone(), Some(forwarded_htlc_value), false, msg.channel_id);
 +              self.claim_funds_internal(htlc_source, msg.payment_preimage.clone(), Some(forwarded_htlc_value), false, funding_txo);
                Ok(())
        }
  
                                                                                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,
                        let peer_state = &mut *peer_state_lock;
                        match peer_state.channel_by_id.entry(msg.channel_id) {
                                hash_map::Entry::Occupied(mut chan) => {
 -                                      let funding_txo = chan.get().context.get_funding_txo();
 -                                      let (htlcs_to_fail, monitor_update_opt) = try_chan_entry!(self, chan.get_mut().revoke_and_ack(&msg, &self.fee_estimator, &self.logger), chan);
 +                                      let funding_txo_opt = chan.get().context.get_funding_txo();
 +                                      let mon_update_blocked = if let Some(funding_txo) = funding_txo_opt {
 +                                              self.raa_monitor_updates_held(
 +                                                      &peer_state.actions_blocking_raa_monitor_updates, funding_txo,
 +                                                      *counterparty_node_id)
 +                                      } else { false };
 +                                      let (htlcs_to_fail, monitor_update_opt) = try_chan_entry!(self,
 +                                              chan.get_mut().revoke_and_ack(&msg, &self.fee_estimator, &self.logger, mon_update_blocked), chan);
                                        let res = if let Some(monitor_update) = monitor_update_opt {
 -                                              handle_new_monitor_update!(self, funding_txo.unwrap(), monitor_update,
 +                                              let funding_txo = funding_txo_opt
 +                                                      .expect("Funding outpoint must have been set for RAA handling to succeed");
 +                                              handle_new_monitor_update!(self, funding_txo, monitor_update,
                                                        peer_state_lock, peer_state, per_peer_state, chan).map(|_| ())
                                        } else { Ok(()) };
                                        (htlcs_to_fail, res)
                                        MonitorEvent::HTLCEvent(htlc_update) => {
                                                if let Some(preimage) = htlc_update.payment_preimage {
                                                        log_trace!(self.logger, "Claiming HTLC with preimage {} from our monitor", log_bytes!(preimage.0));
 -                                                      self.claim_funds_internal(htlc_update.source, preimage, htlc_update.htlc_value_satoshis.map(|v| v * 1000), true, funding_outpoint.to_channel_id());
 +                                                      self.claim_funds_internal(htlc_update.source, preimage, htlc_update.htlc_value_satoshis.map(|v| v * 1000), true, funding_outpoint);
                                                } else {
                                                        log_trace!(self.logger, "Failing HTLC with hash {} from our monitor", log_bytes!(htlc_update.payment_hash.0));
                                                        let receiver = HTLCDestination::NextHopChannel { node_id: counterparty_node_id, channel_id: funding_outpoint.to_channel_id() };
@@@ -7145,6 -7159,7 +7180,7 @@@ wher
                                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,
@@@ -7920,7 -7935,8 +7956,8 @@@ impl_writeable_tlv_based!(HTLCPreviousH
        (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 {
@@@ -9000,13 -9016,7 +9037,13 @@@ wher
                                                                        // generating a `PaymentPathSuccessful` event but regenerating
                                                                        // it and the `PaymentSent` on every restart until the
                                                                        // `ChannelMonitor` is removed.
 -                                                                      pending_outbounds.claim_htlc(payment_id, preimage, session_priv, path, false, &pending_events, &args.logger);
 +                                                                      let compl_action =
 +                                                                              EventCompletionAction::ReleaseRAAChannelMonitorUpdate {
 +                                                                                      channel_funding_outpoint: monitor.get_funding_txo().0,
 +                                                                                      counterparty_node_id: path.hops[0].pubkey,
 +                                                                              };
 +                                                                      pending_outbounds.claim_htlc(payment_id, preimage, session_priv,
 +                                                                              path, false, compl_action, &pending_events, &args.logger);
                                                                        pending_events_read = pending_events.into_inner().unwrap();
                                                                }
                                                        },
                                                                        // downstream chan is closed (because we don't have a
                                                                        // channel_id -> peer map entry).
                                                                        counterparty_opt.is_none(),
 -                                                                      monitor.get_funding_txo().0.to_channel_id()))
 +                                                                      monitor.get_funding_txo().0))
                                                        } else { None }
                                                } else {
                                                        // If it was an outbound payment, we've handled it above - if a preimage
                                                        .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
                                                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));
                                }
                        }
                        channel_manager.fail_htlc_backwards_internal(&source, &payment_hash, &reason, receiver);
                }
  
 -              for (source, preimage, downstream_value, downstream_closed, downstream_chan_id) in pending_claims_to_replay {
 +              for (source, preimage, downstream_value, downstream_closed, downstream_funding) in pending_claims_to_replay {
                        // We use `downstream_closed` in place of `from_onchain` here just as a guess - we
                        // don't remember in the `ChannelMonitor` where we got a preimage from, but if the
                        // channel is closed we just assume that it probably came from an on-chain claim.
                        channel_manager.claim_funds_internal(source, preimage, Some(downstream_value),
 -                              downstream_closed, downstream_chan_id);
 +                              downstream_closed, downstream_funding);
                }
  
                //TODO: Broadcast channel update for closed channels, but only after we've made a
@@@ -9479,7 -9491,6 +9518,7 @@@ mod tests 
  
                let bs_first_updates = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id());
                nodes[0].node.handle_update_fulfill_htlc(&nodes[1].node.get_our_node_id(), &bs_first_updates.update_fulfill_htlcs[0]);
 +              expect_payment_sent(&nodes[0], payment_preimage, None, false, false);
                nodes[0].node.handle_commitment_signed(&nodes[1].node.get_our_node_id(), &bs_first_updates.commitment_signed);
                check_added_monitors!(nodes[0], 1);
                let (as_first_raa, as_first_cs) = get_revoke_commit_msgs!(nodes[0], nodes[1].node.get_our_node_id());
                // Note that successful MPP payments will generate a single PaymentSent event upon the first
                // path's success and a PaymentPathSuccessful event for each path's success.
                let events = nodes[0].node.get_and_clear_pending_events();
 -              assert_eq!(events.len(), 3);
 +              assert_eq!(events.len(), 2);
                match events[0] {
 -                      Event::PaymentSent { payment_id: ref id, payment_preimage: ref preimage, payment_hash: ref hash, .. } => {
 -                              assert_eq!(Some(payment_id), *id);
 -                              assert_eq!(payment_preimage, *preimage);
 -                              assert_eq!(our_payment_hash, *hash);
 -                      },
 -                      _ => panic!("Unexpected event"),
 -              }
 -              match events[1] {
                        Event::PaymentPathSuccessful { payment_id: ref actual_payment_id, ref payment_hash, ref path } => {
                                assert_eq!(payment_id, *actual_payment_id);
                                assert_eq!(our_payment_hash, *payment_hash.as_ref().unwrap());
                        },
                        _ => panic!("Unexpected event"),
                }
 -              match events[2] {
 +              match events[1] {
                        Event::PaymentPathSuccessful { payment_id: ref actual_payment_id, ref payment_hash, ref path } => {
                                assert_eq!(payment_id, *actual_payment_id);
                                assert_eq!(our_payment_hash, *payment_hash.as_ref().unwrap());
index 48ce0f9464d79d15b32a05c0cc355a3d838c51ca,73d09c76f9f7ea74d834e3a9573e2995bf0cc0a4..1db4e873458001b820db2ba4d0284e89a95b20ce
@@@ -14,10 -14,10 +14,10 @@@ use crate::chain::{BestBlock, ChannelMo
  use crate::sign::EntropySource;
  use crate::chain::channelmonitor::ChannelMonitor;
  use crate::chain::transaction::OutPoint;
- use crate::events::{ClosureReason, Event, HTLCDestination, MessageSendEvent, MessageSendEventsProvider, PathFailure, PaymentPurpose, PaymentFailureReason};
+ use crate::events::{ClaimedHTLC, ClosureReason, Event, HTLCDestination, MessageSendEvent, MessageSendEventsProvider, PathFailure, PaymentPurpose, PaymentFailureReason};
  use crate::events::bump_transaction::{BumpTransactionEventHandler, Wallet, WalletSource};
  use crate::ln::{PaymentPreimage, PaymentHash, PaymentSecret};
 -use crate::ln::channelmanager::{AChannelManager, ChainParameters, ChannelManager, ChannelManagerReadArgs, RAACommitmentOrder, PaymentSendFailure, RecipientOnionFields, PaymentId, MIN_CLTV_EXPIRY_DELTA};
 +use crate::ln::channelmanager::{self, AChannelManager, ChainParameters, ChannelManager, ChannelManagerReadArgs, RAACommitmentOrder, PaymentSendFailure, RecipientOnionFields, PaymentId, MIN_CLTV_EXPIRY_DELTA};
  use crate::routing::gossip::{P2PGossipSync, NetworkGraph, NetworkUpdate};
  use crate::routing::router::{self, PaymentParameters, Route};
  use crate::ln::features::InitFeatures;
@@@ -933,6 -933,21 +933,21 @@@ macro_rules! check_added_monitors 
        }
  }
  
+ /// Checks whether the claimed HTLC for the specified path has the correct channel information.
+ ///
+ /// This will panic if the path is empty, if the HTLC's channel ID is not actually a channel that
+ /// connects the final two nodes in the path, or if the `user_channel_id` is incorrect.
+ pub fn check_claimed_htlc_channel<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, path: &[&Node<'a, 'b, 'c>], htlc: &ClaimedHTLC) {
+       let mut nodes = path.iter().rev();
+       let dest = nodes.next().expect("path should have a destination").node;
+       let prev = nodes.next().unwrap_or(&origin_node).node;
+       let dest_channels = dest.list_channels();
+       let ch = dest_channels.iter().find(|ch| ch.channel_id == htlc.channel_id)
+               .expect("HTLC's channel should be one of destination node's channels");
+       assert_eq!(htlc.user_channel_id, ch.user_channel_id);
+       assert_eq!(ch.counterparty.node_id, prev.get_our_node_id());
+ }
  pub fn _reload_node<'a, 'b, 'c>(node: &'a Node<'a, 'b, 'c>, default_config: UserConfig, chanman_encoded: &[u8], monitors_encoded: &[&[u8]]) -> TestChannelManager<'b, 'c> {
        let mut monitors_read = Vec::with_capacity(monitors_encoded.len());
        for encoded in monitors_encoded {
@@@ -1684,8 -1699,8 +1699,8 @@@ macro_rules! commitment_signed_dance 
                        bs_revoke_and_ack
                }
        };
 -      ($node_a: expr, $node_b: expr, (), $fail_backwards: expr, true /* skip last step */, false /* no extra message */) => {
 -              assert!($crate::ln::functional_test_utils::commitment_signed_dance_through_cp_raa(&$node_a, &$node_b, $fail_backwards).is_none());
 +      ($node_a: expr, $node_b: expr, (), $fail_backwards: expr, true /* skip last step */, false /* no extra message */, $incl_claim: expr) => {
 +              assert!($crate::ln::functional_test_utils::commitment_signed_dance_through_cp_raa(&$node_a, &$node_b, $fail_backwards, $incl_claim).is_none());
        };
        ($node_a: expr, $node_b: expr, $commitment_signed: expr, $fail_backwards: expr) => {
                $crate::ln::functional_test_utils::do_commitment_signed_dance(&$node_a, &$node_b, &$commitment_signed, $fail_backwards, false);
  /// the initiator's `revoke_and_ack` response. i.e. [`do_main_commitment_signed_dance`] plus the
  /// `revoke_and_ack` response to it.
  ///
 +/// An HTLC claim on one channel blocks the RAA channel monitor update for the outbound edge
 +/// channel until the inbound edge channel preimage monitor update completes. Thus, when checking
 +/// for channel monitor updates, we need to know if an `update_fulfill_htlc` was included in the
 +/// the commitment we're exchanging. `includes_claim` provides that information.
 +///
  /// Returns any additional message `node_b` generated in addition to the `revoke_and_ack` response.
 -pub fn commitment_signed_dance_through_cp_raa(node_a: &Node<'_, '_, '_>, node_b: &Node<'_, '_, '_>, fail_backwards: bool) -> Option<MessageSendEvent> {
 +pub fn commitment_signed_dance_through_cp_raa(node_a: &Node<'_, '_, '_>, node_b: &Node<'_, '_, '_>, fail_backwards: bool, includes_claim: bool) -> Option<MessageSendEvent> {
        let (extra_msg_option, bs_revoke_and_ack) = do_main_commitment_signed_dance(node_a, node_b, fail_backwards);
        node_a.node.handle_revoke_and_ack(&node_b.node.get_our_node_id(), &bs_revoke_and_ack);
 -      check_added_monitors(node_a, 1);
 +      check_added_monitors(node_a, if includes_claim { 0 } else { 1 });
        extra_msg_option
  }
  
@@@ -1752,23 -1762,7 +1767,23 @@@ pub fn do_commitment_signed_dance(node_
        node_a.node.handle_commitment_signed(&node_b.node.get_our_node_id(), commitment_signed);
        check_added_monitors!(node_a, 1);
  
 -      commitment_signed_dance!(node_a, node_b, (), fail_backwards, true, false);
 +      // If this commitment signed dance was due to a claim, don't check for an RAA monitor update.
 +      let got_claim = node_a.node.pending_events.lock().unwrap().iter().any(|(ev, action)| {
 +              let matching_action = if let Some(channelmanager::EventCompletionAction::ReleaseRAAChannelMonitorUpdate
 +                      { channel_funding_outpoint, counterparty_node_id }) = action
 +              {
 +                      if channel_funding_outpoint.to_channel_id() == commitment_signed.channel_id {
 +                              assert_eq!(*counterparty_node_id, node_b.node.get_our_node_id());
 +                              true
 +                      } else { false }
 +              } else { false };
 +              if matching_action {
 +                      if let Event::PaymentSent { .. } = ev {} else { panic!(); }
 +              }
 +              matching_action
 +      });
 +      if fail_backwards { assert!(!got_claim); }
 +      commitment_signed_dance!(node_a, node_b, (), fail_backwards, true, false, got_claim);
  
        if skip_last_step { return; }
  
@@@ -1913,7 -1907,7 +1928,7 @@@ macro_rules! expect_payment_claimed 
  
  pub fn expect_payment_sent<CM: AChannelManager, H: NodeHolder<CM=CM>>(node: &H,
        expected_payment_preimage: PaymentPreimage, expected_fee_msat_opt: Option<Option<u64>>,
 -      expect_per_path_claims: bool,
 +      expect_per_path_claims: bool, expect_post_ev_mon_update: bool,
  ) {
        let events = node.node().get_and_clear_pending_events();
        let expected_payment_hash = PaymentHash(
        } else {
                assert_eq!(events.len(), 1);
        }
 +      if expect_post_ev_mon_update {
 +              check_added_monitors(node, 1);
 +      }
        let expected_payment_id = match events[0] {
                Event::PaymentSent { ref payment_id, ref payment_preimage, ref payment_hash, ref fee_paid_msat } => {
                        assert_eq!(expected_payment_preimage, *payment_preimage);
        }
  }
  
 -#[cfg(test)]
 -#[macro_export]
 -macro_rules! expect_payment_sent_without_paths {
 -      ($node: expr, $expected_payment_preimage: expr) => {
 -              expect_payment_sent!($node, $expected_payment_preimage, None::<u64>, false);
 -      };
 -      ($node: expr, $expected_payment_preimage: expr, $expected_fee_msat_opt: expr) => {
 -              expect_payment_sent!($node, $expected_payment_preimage, $expected_fee_msat_opt, false);
 -      }
 -}
 -
  #[macro_export]
  macro_rules! expect_payment_sent {
        ($node: expr, $expected_payment_preimage: expr) => {
        };
        ($node: expr, $expected_payment_preimage: expr, $expected_fee_msat_opt: expr, $expect_paths: expr) => {
                $crate::ln::functional_test_utils::expect_payment_sent(&$node, $expected_payment_preimage,
 -                      $expected_fee_msat_opt.map(|o| Some(o)), $expect_paths);
 +                      $expected_fee_msat_opt.map(|o| Some(o)), $expect_paths, true);
        }
  }
  
@@@ -2284,11 -2286,34 +2299,34 @@@ pub fn pass_claimed_payment_along_route
        let claim_event = expected_paths[0].last().unwrap().node.get_and_clear_pending_events();
        assert_eq!(claim_event.len(), 1);
        match claim_event[0] {
-               Event::PaymentClaimed { purpose: PaymentPurpose::SpontaneousPayment(preimage), .. }|
-               Event::PaymentClaimed { purpose: PaymentPurpose::InvoicePayment { payment_preimage: Some(preimage), ..}, .. } =>
-                       assert_eq!(preimage, our_payment_preimage),
-               Event::PaymentClaimed { purpose: PaymentPurpose::InvoicePayment { .. }, payment_hash, .. } =>
-                       assert_eq!(&payment_hash.0, &Sha256::hash(&our_payment_preimage.0)[..]),
+               Event::PaymentClaimed {
+                       purpose: PaymentPurpose::SpontaneousPayment(preimage),
+                       amount_msat,
+                       ref htlcs,
+                       .. }
+               | Event::PaymentClaimed {
+                       purpose: PaymentPurpose::InvoicePayment { payment_preimage: Some(preimage), ..},
+                       ref htlcs,
+                       amount_msat,
+                       ..
+               } => {
+                       assert_eq!(preimage, our_payment_preimage);
+                       assert_eq!(htlcs.len(), expected_paths.len());  // One per path.
+                       assert_eq!(htlcs.iter().map(|h| h.value_msat).sum::<u64>(), amount_msat);
+                       expected_paths.iter().zip(htlcs).for_each(|(path, htlc)| check_claimed_htlc_channel(origin_node, path, htlc));
+               },
+               Event::PaymentClaimed {
+                       purpose: PaymentPurpose::InvoicePayment { .. },
+                       payment_hash,
+                       amount_msat,
+                       ref htlcs,
+                       ..
+               } => {
+                       assert_eq!(&payment_hash.0, &Sha256::hash(&our_payment_preimage.0)[..]);
+                       assert_eq!(htlcs.len(), expected_paths.len());  // One per path.
+                       assert_eq!(htlcs.iter().map(|h| h.value_msat).sum::<u64>(), amount_msat);
+                       expected_paths.iter().zip(htlcs).for_each(|(path, htlc)| check_claimed_htlc_channel(origin_node, path, htlc));
+               }
                _ => panic!(),
        }