Skip to content

Commit 59ebb6f

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 aae02f4 commit 59ebb6f

File tree

1 file changed

+23
-15
lines changed

1 file changed

+23
-15
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4281,10 +4281,14 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
42814281
};
42824282
debug_assert!(!sources.is_empty());
42834283

4284-
// If we are claiming an MPP payment, we have to take special care to ensure that each
4285-
// channel exists before claiming all of the payments (inside one lock).
4286-
// Note that channel existance is sufficient as we should always get a monitor update
4287-
// which will take care of the real HTLC claim enforcement.
4284+
// If we are claiming an MPP payment, we check that all channels which contain a claimable
4285+
// HTLC still exist. While this isn't guaranteed to remain true if a channel closes while
4286+
// we're claiming (or even after we claim, before the commitment update dance completes),
4287+
// it should be a relatively rare race, and we'd rather not claim HTLCs that require us to
4288+
// go on-chain (and lose the on-chain fee to do so) than just reject the payment.
4289+
//
4290+
// Note that we'll still always get our funds - as long as the generated
4291+
// `ChannelMonitorUpdate` makes it out to the relevant monitor we can claim on-chain.
42884292
//
42894293
// If we find an HTLC which we would need to claim but for which we do not have a
42904294
// channel, we will fail all parts of the MPP payment. While we could wait and see if
@@ -4297,8 +4301,7 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
42974301
let mut valid_mpp = true;
42984302
let mut errs = Vec::new();
42994303
let mut claimed_any_htlcs = false;
4300-
let mut channel_state_lock = self.channel_state.lock().unwrap();
4301-
let channel_state = &mut *channel_state_lock;
4304+
let mut channel_state = Some(self.channel_state.lock().unwrap());
43024305
for htlc in sources.iter() {
43034306
let chan_id = match self.short_to_chan_info.read().unwrap().get(&htlc.prev_hop.short_channel_id) {
43044307
Some((_cp_id, chan_id)) => chan_id.clone(),
@@ -4308,7 +4311,7 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
43084311
}
43094312
};
43104313

4311-
if let None = channel_state.by_id.get(&chan_id) {
4314+
if let None = channel_state.as_ref().unwrap().by_id.get(&chan_id) {
43124315
valid_mpp = false;
43134316
break;
43144317
}
@@ -4346,7 +4349,8 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
43464349
}
43474350
if valid_mpp {
43484351
for htlc in sources.drain(..) {
4349-
match self.claim_funds_from_hop(&mut channel_state_lock, htlc.prev_hop, payment_preimage) {
4352+
if channel_state.is_none() { channel_state = Some(self.channel_state.lock().unwrap()); }
4353+
match self.claim_funds_from_hop(channel_state.take().unwrap(), htlc.prev_hop, payment_preimage) {
43504354
ClaimFundsFromHop::MonitorUpdateFail(pk, err, _) => {
43514355
if let msgs::ErrorAction::IgnoreError = err.err.action {
43524356
// We got a temporary failure updating monitor, but will claim the
@@ -4355,7 +4359,12 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
43554359
claimed_any_htlcs = true;
43564360
} else { errs.push((pk, err)); }
43574361
},
4358-
ClaimFundsFromHop::PrevHopForceClosed => unreachable!("We already checked for channel existence, we can't fail here!"),
4362+
ClaimFundsFromHop::PrevHopForceClosed => {
4363+
// This should be incredibly rare - we checked that all the channels were
4364+
// open above, though as we release the lock at each loop iteration it's
4365+
// still possible. We should still claim the HTLC on-chain through the
4366+
// closed-channel-update generated in claim_funds_from_hop.
4367+
},
43594368
ClaimFundsFromHop::DuplicateClaim => {
43604369
// While we should never get here in most cases, if we do, it likely
43614370
// indicates that the HTLC was timed out some time ago and is no longer
@@ -4366,7 +4375,7 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
43664375
}
43674376
}
43684377
}
4369-
mem::drop(channel_state_lock);
4378+
mem::drop(channel_state);
43704379
if !valid_mpp {
43714380
for htlc in sources.drain(..) {
43724381
let mut htlc_msat_height_data = htlc.value.to_be_bytes().to_vec();
@@ -4393,11 +4402,11 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
43934402
}
43944403
}
43954404

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

43994408
let chan_id = prev_hop.outpoint.to_channel_id();
4400-
let channel_state = &mut **channel_state_lock;
4409+
let channel_state = &mut *channel_state_lock;
44014410
if let hash_map::Entry::Occupied(mut chan) = channel_state.by_id.entry(chan_id) {
44024411
match chan.get_mut().get_update_fulfill_htlc_and_commit(prev_hop.htlc_id, payment_preimage, &self.logger) {
44034412
Ok(msgs_monitor_option) => {
@@ -4497,7 +4506,7 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
44974506
}
44984507
}
44994508

4500-
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]) {
4509+
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]) {
45014510
match source {
45024511
HTLCSource::OutboundRoute { session_priv, payment_id, path, .. } => {
45034512
mem::drop(channel_state_lock);
@@ -4544,7 +4553,7 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
45444553
},
45454554
HTLCSource::PreviousHopData(hop_data) => {
45464555
let prev_outpoint = hop_data.outpoint;
4547-
let res = self.claim_funds_from_hop(&mut channel_state_lock, hop_data, payment_preimage);
4556+
let res = self.claim_funds_from_hop(channel_state_lock, hop_data, payment_preimage);
45484557
let claimed_htlc = if let ClaimFundsFromHop::DuplicateClaim = res { false } else { true };
45494558
let htlc_claim_value_msat = match res {
45504559
ClaimFundsFromHop::MonitorUpdateFail(_, _, amt_opt) => amt_opt,
@@ -4558,7 +4567,6 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
45584567
// update to. Instead, we simply document in `PaymentForwarded` that this
45594568
// can happen.
45604569
}
4561-
mem::drop(channel_state_lock);
45624570
if let ClaimFundsFromHop::MonitorUpdateFail(pk, err, _) = res {
45634571
let result: Result<(), _> = Err(err);
45644572
let _ = handle_error!(self, result, pk);

0 commit comments

Comments
 (0)