Skip to content

Commit 0ec13f6

Browse files
committed
Fix a minor memory leak on PermanentFailure mon errs when sending
If we send a payment and fail to update the first-hop channel state with a `PermanentFailure` ChannelMonitorUpdateErr, we would have an entry in our pending payments map, but possibly not return the PaymentId back to the user to retry the payment, leading to a (rare and relatively minor) memory leak.
1 parent 6f002ea commit 0ec13f6

File tree

1 file changed

+23
-16
lines changed

1 file changed

+23
-16
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2075,6 +2075,21 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
20752075
Some(id) => id.clone(),
20762076
};
20772077

2078+
macro_rules! insert_outbound_payment {
2079+
() => {
2080+
let payment = payment_entry.or_insert_with(|| PendingOutboundPayment::Retryable {
2081+
session_privs: HashSet::new(),
2082+
pending_amt_msat: 0,
2083+
pending_fee_msat: Some(0),
2084+
payment_hash: *payment_hash,
2085+
payment_secret: *payment_secret,
2086+
starting_block_height: self.best_block.read().unwrap().height(),
2087+
total_msat: total_value,
2088+
});
2089+
assert!(payment.insert(session_priv_bytes, path));
2090+
}
2091+
}
2092+
20782093
let channel_state = &mut *channel_lock;
20792094
if let hash_map::Entry::Occupied(mut chan) = channel_state.by_id.entry(id) {
20802095
match {
@@ -2084,7 +2099,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
20842099
if !chan.get().is_live() {
20852100
return Err(APIError::ChannelUnavailable{err: "Peer for first hop currently disconnected/pending monitor update!".to_owned()});
20862101
}
2087-
let send_res = break_chan_entry!(self, chan.get_mut().send_htlc_and_commit(
2102+
break_chan_entry!(self, chan.get_mut().send_htlc_and_commit(
20882103
htlc_msat, payment_hash.clone(), htlc_cltv, HTLCSource::OutboundRoute {
20892104
path: path.clone(),
20902105
session_priv: session_priv.clone(),
@@ -2093,20 +2108,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
20932108
payment_secret: payment_secret.clone(),
20942109
payee: payee.clone(),
20952110
}, onion_packet, &self.logger),
2096-
channel_state, chan);
2097-
2098-
let payment = payment_entry.or_insert_with(|| PendingOutboundPayment::Retryable {
2099-
session_privs: HashSet::new(),
2100-
pending_amt_msat: 0,
2101-
pending_fee_msat: Some(0),
2102-
payment_hash: *payment_hash,
2103-
payment_secret: *payment_secret,
2104-
starting_block_height: self.best_block.read().unwrap().height(),
2105-
total_msat: total_value,
2106-
});
2107-
assert!(payment.insert(session_priv_bytes, path));
2108-
2109-
send_res
2111+
channel_state, chan)
21102112
} {
21112113
Some((update_add, commitment_signed, monitor_update)) => {
21122114
if let Err(e) = self.chain_monitor.update_channel(chan.get().get_funding_txo().unwrap(), monitor_update) {
@@ -2116,8 +2118,10 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
21162118
// is restored. Therefore, we must return an error indicating that
21172119
// it is unsafe to retry the payment wholesale, which we do in the
21182120
// send_payment check for MonitorUpdateFailed, below.
2121+
insert_outbound_payment!(); // Only do this after possibly break'ing on Perm failure above.
21192122
return Err(APIError::MonitorUpdateFailed);
21202123
}
2124+
insert_outbound_payment!();
21212125

21222126
log_debug!(self.logger, "Sending payment along path resulted in a commitment_signed for channel {}", log_bytes!(chan.get().channel_id()));
21232127
channel_state.pending_msg_events.push(events::MessageSendEvent::UpdateHTLCs {
@@ -2132,7 +2136,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
21322136
},
21332137
});
21342138
},
2135-
None => {},
2139+
None => { insert_outbound_payment!(); },
21362140
}
21372141
} else { unreachable!(); }
21382142
return Ok(());
@@ -2249,6 +2253,9 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
22492253
if has_err && has_ok {
22502254
Err(PaymentSendFailure::PartialFailure(results))
22512255
} else if has_err {
2256+
// If we failed to send any paths, we shouldn't have inserted the new PaymentId into
2257+
// our `pending_outbound_payments` map at all.
2258+
debug_assert!(self.pending_outbound_payments.lock().unwrap().get(&payment_id).is_none());
22522259
Err(PaymentSendFailure::AllFailedRetrySafe(results.drain(..).map(|r| r.unwrap_err()).collect()))
22532260
} else {
22542261
Ok(payment_id)

0 commit comments

Comments
 (0)