Skip to content

Commit a74640f

Browse files
committed
Don't hold channel_state lock for entire duration of claim_funds
When `claim_funds` has to claim multiple HTLCs as a part of a single MPP payment, it currently does so holding the `channel_state` lock for the entire duration of the claim loop. Here we swap that for taking the lock once for each HTLC. This allows us to be more flexible with locks going forward, and ultimately isn't a huge change - if our counterparty intends to force-close a channel, us choosing to ignore it by holding the `channel_state` lock for the duration of the claim isn't going to result in a commitment update, it will just result in the preimage already being in the `ChannelMonitor`.
1 parent c3e4234 commit a74640f

File tree

1 file changed

+15
-11
lines changed

1 file changed

+15
-11
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4300,8 +4300,7 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
43004300
let mut valid_mpp = true;
43014301
let mut errs = Vec::new();
43024302
let mut claimed_any_htlcs = false;
4303-
let mut channel_state_lock = self.channel_state.lock().unwrap();
4304-
let channel_state = &mut *channel_state_lock;
4303+
let mut channel_state = Some(self.channel_state.lock().unwrap());
43054304
for htlc in sources.iter() {
43064305
let chan_id = match self.short_to_chan_info.read().unwrap().get(&htlc.prev_hop.short_channel_id) {
43074306
Some((_cp_id, chan_id)) => chan_id.clone(),
@@ -4311,7 +4310,7 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
43114310
}
43124311
};
43134312

4314-
if let None = channel_state.by_id.get(&chan_id) {
4313+
if let None = channel_state.as_ref().unwrap().by_id.get(&chan_id) {
43154314
valid_mpp = false;
43164315
break;
43174316
}
@@ -4349,7 +4348,8 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
43494348
}
43504349
if valid_mpp {
43514350
for htlc in sources.drain(..) {
4352-
match self.claim_funds_from_hop(&mut channel_state_lock, htlc.prev_hop, payment_preimage) {
4351+
if channel_state.is_none() { channel_state = Some(self.channel_state.lock().unwrap()); }
4352+
match self.claim_funds_from_hop(channel_state.take().unwrap(), htlc.prev_hop, payment_preimage) {
43534353
ClaimFundsFromHop::MonitorUpdateFail(pk, err, _) => {
43544354
if let msgs::ErrorAction::IgnoreError = err.err.action {
43554355
// We got a temporary failure updating monitor, but will claim the
@@ -4358,7 +4358,12 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
43584358
claimed_any_htlcs = true;
43594359
} else { errs.push((pk, err)); }
43604360
},
4361-
ClaimFundsFromHop::PrevHopForceClosed => unreachable!("We already checked for channel existence, we can't fail here!"),
4361+
ClaimFundsFromHop::PrevHopForceClosed => {
4362+
// This should be incredibly rare - we checked that all the channels were
4363+
// open above, though as we release the lock at each loop iteration it's
4364+
// still possible. We should still claim the HTLC on-chain through the
4365+
// closed-channel-update generated in claim_funds_from_hop.
4366+
},
43624367
ClaimFundsFromHop::DuplicateClaim => {
43634368
// While we should never get here in most cases, if we do, it likely
43644369
// indicates that the HTLC was timed out some time ago and is no longer
@@ -4369,7 +4374,7 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
43694374
}
43704375
}
43714376
}
4372-
mem::drop(channel_state_lock);
4377+
mem::drop(channel_state);
43734378
if !valid_mpp {
43744379
for htlc in sources.drain(..) {
43754380
let mut htlc_msat_height_data = htlc.value.to_be_bytes().to_vec();
@@ -4396,11 +4401,11 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
43964401
}
43974402
}
43984403

4399-
fn claim_funds_from_hop(&self, channel_state_lock: &mut MutexGuard<ChannelHolder<<K::Target as KeysInterface>::Signer>>, prev_hop: HTLCPreviousHopData, payment_preimage: PaymentPreimage) -> ClaimFundsFromHop {
4404+
fn claim_funds_from_hop(&self, mut channel_state_lock: MutexGuard<ChannelHolder<<K::Target as KeysInterface>::Signer>>, prev_hop: HTLCPreviousHopData, payment_preimage: PaymentPreimage) -> ClaimFundsFromHop {
44004405
//TODO: Delay the claimed_funds relaying just like we do outbound relay!
44014406

44024407
let chan_id = prev_hop.outpoint.to_channel_id();
4403-
let channel_state = &mut **channel_state_lock;
4408+
let channel_state = &mut *channel_state_lock;
44044409
if let hash_map::Entry::Occupied(mut chan) = channel_state.by_id.entry(chan_id) {
44054410
match chan.get_mut().get_update_fulfill_htlc_and_commit(prev_hop.htlc_id, payment_preimage, &self.logger) {
44064411
Ok(msgs_monitor_option) => {
@@ -4500,7 +4505,7 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
45004505
}
45014506
}
45024507

4503-
fn claim_funds_internal(&self, mut channel_state_lock: MutexGuard<ChannelHolder<<K::Target as KeysInterface>::Signer>>, source: HTLCSource, payment_preimage: PaymentPreimage, forwarded_htlc_value_msat: Option<u64>, from_onchain: bool, next_channel_id: [u8; 32]) {
4508+
fn claim_funds_internal(&self, channel_state_lock: MutexGuard<ChannelHolder<<K::Target as KeysInterface>::Signer>>, source: HTLCSource, payment_preimage: PaymentPreimage, forwarded_htlc_value_msat: Option<u64>, from_onchain: bool, next_channel_id: [u8; 32]) {
45044509
match source {
45054510
HTLCSource::OutboundRoute { session_priv, payment_id, path, .. } => {
45064511
mem::drop(channel_state_lock);
@@ -4547,7 +4552,7 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
45474552
},
45484553
HTLCSource::PreviousHopData(hop_data) => {
45494554
let prev_outpoint = hop_data.outpoint;
4550-
let res = self.claim_funds_from_hop(&mut channel_state_lock, hop_data, payment_preimage);
4555+
let res = self.claim_funds_from_hop(channel_state_lock, hop_data, payment_preimage);
45514556
let claimed_htlc = if let ClaimFundsFromHop::DuplicateClaim = res { false } else { true };
45524557
let htlc_claim_value_msat = match res {
45534558
ClaimFundsFromHop::MonitorUpdateFail(_, _, amt_opt) => amt_opt,
@@ -4561,7 +4566,6 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
45614566
// update to. Instead, we simply document in `PaymentForwarded` that this
45624567
// can happen.
45634568
}
4564-
mem::drop(channel_state_lock);
45654569
if let ClaimFundsFromHop::MonitorUpdateFail(pk, err, _) = res {
45664570
let result: Result<(), _> = Err(err);
45674571
let _ = handle_error!(self, result, pk);

0 commit comments

Comments
 (0)