@@ -18612,17 +18612,24 @@ impl<
1861218612 // edge or (b) removed from the outbound edge via claim. If it's in neither of these states, we
1861318613 // infer that it was removed from the outbound edge via fail, and fail it backwards to ensure
1861418614 // that it is handled.
18615- let mut already_forwarded_htlcs = Vec::new();
18616- let prune_forwarded_htlc =
18617- |already_forwarded_htlcs: &mut Vec<(PaymentHash, HTLCPreviousHopData, u64)>,
18618- prev_hop: &HTLCPreviousHopData| {
18619- if let Some(idx) = already_forwarded_htlcs.iter().position(|(_, htlc, _)| {
18620- prev_hop.htlc_id == htlc.htlc_id
18621- && prev_hop.prev_outbound_scid_alias == htlc.prev_outbound_scid_alias
18622- }) {
18623- already_forwarded_htlcs.swap_remove(idx);
18615+ let mut already_forwarded_htlcs: HashMap<
18616+ ChannelId,
18617+ Vec<(PaymentHash, HTLCPreviousHopData, u64)>,
18618+ > = new_hash_map();
18619+ let prune_forwarded_htlc = |already_forwarded_htlcs: &mut HashMap<
18620+ ChannelId,
18621+ Vec<(PaymentHash, HTLCPreviousHopData, u64)>,
18622+ >,
18623+ prev_hop: &HTLCPreviousHopData| {
18624+ if let hash_map::Entry::Occupied(mut entry) =
18625+ already_forwarded_htlcs.entry(prev_hop.channel_id)
18626+ {
18627+ entry.get_mut().retain(|(_, htlc, _)| prev_hop.htlc_id != htlc.htlc_id);
18628+ if entry.get().is_empty() {
18629+ entry.remove();
1862418630 }
18625- };
18631+ }
18632+ };
1862618633 {
1862718634 // If we're tracking pending payments, ensure we haven't lost any by looking at the
1862818635 // ChannelMonitor data for any channels for which we do not have authorative state
@@ -18667,11 +18674,23 @@ impl<
1866718674 hop_data,
1866818675 outbound_amt_msat,
1866918676 } => {
18670- already_forwarded_htlcs.push((
18671- payment_hash,
18672- hop_data,
18673- outbound_amt_msat,
18674- ));
18677+ match already_forwarded_htlcs.entry(hop_data.channel_id)
18678+ {
18679+ hash_map::Entry::Occupied(mut entry) => {
18680+ entry.get_mut().push((
18681+ payment_hash,
18682+ hop_data,
18683+ outbound_amt_msat,
18684+ ));
18685+ },
18686+ hash_map::Entry::Vacant(entry) => {
18687+ entry.insert(vec![(
18688+ payment_hash,
18689+ hop_data,
18690+ outbound_amt_msat,
18691+ )]);
18692+ },
18693+ }
1867518694 },
1867618695 InboundUpdateAdd::Legacy => {
1867718696 return Err(DecodeError::InvalidValue)
@@ -19371,44 +19390,50 @@ impl<
1937119390
1937219391 let mut processed_claims: HashSet<Vec<MPPClaimHTLCSource>> = new_hash_set();
1937319392 for (channel_id, monitor) in args.channel_monitors.iter() {
19393+ let counterparty_node_id = monitor.get_counterparty_node_id();
1937419394 for (payment_hash, (payment_preimage, payment_claims)) in monitor.get_stored_preimages()
1937519395 {
1937619396 // If we have unresolved inbound committed HTLCs that were already forwarded to the
1937719397 // outbound edge and removed via claim, we need to make sure to claim them backwards via
1937819398 // adding them to `pending_claims_to_replay`.
19379- for (hash, hop_data, outbound_amt_msat) in
19380- mem::take(&mut already_forwarded_htlcs).drain(.. )
19399+ if let hash_map::Entry::Occupied(mut entry) =
19400+ already_forwarded_htlcs.entry(*channel_id )
1938119401 {
19382- if hash != payment_hash {
19383- already_forwarded_htlcs.push((hash, hop_data, outbound_amt_msat));
19384- continue;
19385- }
19386- let new_pending_claim = !pending_claims_to_replay.iter().any(|(src, _, _, _, _, _, _)| {
19387- matches!(src, HTLCSource::PreviousHopData(hop) if hop.htlc_id == hop_data.htlc_id && hop.prev_outbound_scid_alias == hop_data.prev_outbound_scid_alias)
19388- });
19389- if new_pending_claim {
19390- let counterparty_node_id = monitor.get_counterparty_node_id();
19391- let is_channel_closed = channel_manager
19392- .per_peer_state
19393- .read()
19394- .unwrap()
19395- .get(&counterparty_node_id)
19396- .map_or(true, |peer_state_mtx| {
19397- !peer_state_mtx
19398- .lock()
19399- .unwrap()
19400- .channel_by_id
19401- .contains_key(channel_id)
19402+ for (hash, hop_data, outbound_amt_msat) in mem::take(entry.get_mut()) {
19403+ if hash != payment_hash {
19404+ entry.get_mut().push((hash, hop_data, outbound_amt_msat));
19405+ continue;
19406+ }
19407+ let new_pending_claim =
19408+ !pending_claims_to_replay.iter().any(|(src, _, _, _, _, _, _)| {
19409+ matches!(src, HTLCSource::PreviousHopData(hop) if hop.htlc_id == hop_data.htlc_id && hop.channel_id == hop_data.channel_id)
1940219410 });
19403- pending_claims_to_replay.push((
19404- HTLCSource::PreviousHopData(hop_data),
19405- payment_preimage,
19406- outbound_amt_msat,
19407- is_channel_closed,
19408- counterparty_node_id,
19409- monitor.get_funding_txo(),
19410- *channel_id,
19411- ));
19411+ if new_pending_claim {
19412+ let is_channel_closed = channel_manager
19413+ .per_peer_state
19414+ .read()
19415+ .unwrap()
19416+ .get(&counterparty_node_id)
19417+ .map_or(true, |peer_state_mtx| {
19418+ !peer_state_mtx
19419+ .lock()
19420+ .unwrap()
19421+ .channel_by_id
19422+ .contains_key(channel_id)
19423+ });
19424+ pending_claims_to_replay.push((
19425+ HTLCSource::PreviousHopData(hop_data),
19426+ payment_preimage,
19427+ outbound_amt_msat,
19428+ is_channel_closed,
19429+ counterparty_node_id,
19430+ monitor.get_funding_txo(),
19431+ *channel_id,
19432+ ));
19433+ }
19434+ }
19435+ if entry.get().is_empty() {
19436+ entry.remove();
1941219437 }
1941319438 }
1941419439 if !payment_claims.is_empty() {
@@ -19652,7 +19677,7 @@ impl<
1965219677 channel_manager
1965319678 .fail_htlc_backwards_internal(&source, &hash, &reason, receiver, ev_action);
1965419679 }
19655- for (hash, htlc, _) in already_forwarded_htlcs {
19680+ for (hash, htlc, _) in already_forwarded_htlcs.into_values().flatten() {
1965619681 let channel_id = htlc.channel_id;
1965719682 let node_id = htlc.counterparty_node_id;
1965819683 let source = HTLCSource::PreviousHopData(htlc);
0 commit comments