Skip to content

Commit 45e0a63

Browse files
f - refactor claim_funds to only hold channel_state when necessary
1 parent 960ab7d commit 45e0a63

File tree

1 file changed

+64
-63
lines changed

1 file changed

+64
-63
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 64 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -4079,8 +4079,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
40794079

40804080
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
40814081

4082-
let mut channel_state = Some(self.channel_state.lock().unwrap());
4083-
let removed_source = channel_state.as_mut().unwrap().claimable_htlcs.remove(&payment_hash);
4082+
let removed_source = self.channel_state.lock().unwrap().claimable_htlcs.remove(&payment_hash);
40844083
if let Some((payment_purpose, mut sources)) = removed_source {
40854084
assert!(!sources.is_empty());
40864085

@@ -4098,72 +4097,77 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
40984097
let mut claimable_amt_msat = 0;
40994098
let mut expected_amt_msat = None;
41004099
let mut valid_mpp = true;
4101-
for htlc in sources.iter() {
4102-
if let None = channel_state.as_ref().unwrap().short_to_chan_info.get(&htlc.prev_hop.short_channel_id) {
4103-
valid_mpp = false;
4104-
break;
4105-
}
4106-
if expected_amt_msat.is_some() && expected_amt_msat != Some(htlc.total_msat) {
4107-
log_error!(self.logger, "Somehow ended up with an MPP payment with different total amounts - this should not be reachable!");
4108-
debug_assert!(false);
4109-
valid_mpp = false;
4110-
break;
4111-
}
4112-
expected_amt_msat = Some(htlc.total_msat);
4113-
if let OnionPayload::Spontaneous(_) = &htlc.onion_payload {
4114-
// We don't currently support MPP for spontaneous payments, so just check
4115-
// that there's one payment here and move on.
4116-
if sources.len() != 1 {
4117-
log_error!(self.logger, "Somehow ended up with an MPP spontaneous payment - this should not be reachable!");
4100+
let mut errs = Vec::new();
4101+
let mut claimed_any_htlcs = false;
4102+
{
4103+
let mut channel_state_lock = self.channel_state.lock().unwrap();
4104+
let channel_state = &mut *channel_state_lock;
4105+
for htlc in sources.iter() {
4106+
if let None = channel_state.short_to_chan_info.get(&htlc.prev_hop.short_channel_id) {
4107+
valid_mpp = false;
4108+
break;
4109+
}
4110+
if expected_amt_msat.is_some() && expected_amt_msat != Some(htlc.total_msat) {
4111+
log_error!(self.logger, "Somehow ended up with an MPP payment with different total amounts - this should not be reachable!");
41184112
debug_assert!(false);
41194113
valid_mpp = false;
41204114
break;
41214115
}
4122-
}
4116+
expected_amt_msat = Some(htlc.total_msat);
4117+
if let OnionPayload::Spontaneous(_) = &htlc.onion_payload {
4118+
// We don't currently support MPP for spontaneous payments, so just check
4119+
// that there's one payment here and move on.
4120+
if sources.len() != 1 {
4121+
log_error!(self.logger, "Somehow ended up with an MPP spontaneous payment - this should not be reachable!");
4122+
debug_assert!(false);
4123+
valid_mpp = false;
4124+
break;
4125+
}
4126+
}
41234127

4124-
claimable_amt_msat += htlc.value;
4125-
}
4126-
if sources.is_empty() || expected_amt_msat.is_none() {
4127-
log_info!(self.logger, "Attempted to claim an incomplete payment which no longer had any available HTLCs!");
4128-
return;
4129-
}
4130-
if claimable_amt_msat != expected_amt_msat.unwrap() {
4131-
log_info!(self.logger, "Attempted to claim an incomplete payment, expected {} msat, had {} available to claim.",
4132-
expected_amt_msat.unwrap(), claimable_amt_msat);
4133-
return;
4128+
claimable_amt_msat += htlc.value;
4129+
}
4130+
if sources.is_empty() || expected_amt_msat.is_none() {
4131+
log_info!(self.logger, "Attempted to claim an incomplete payment which no longer had any available HTLCs!");
4132+
return;
4133+
}
4134+
if claimable_amt_msat != expected_amt_msat.unwrap() {
4135+
log_info!(self.logger, "Attempted to claim an incomplete payment, expected {} msat, had {} available to claim.",
4136+
expected_amt_msat.unwrap(), claimable_amt_msat);
4137+
return;
4138+
}
4139+
if valid_mpp {
4140+
for htlc in sources.drain(..) {
4141+
match self.claim_funds_from_hop(&mut channel_state_lock, htlc.prev_hop, payment_preimage) {
4142+
ClaimFundsFromHop::MonitorUpdateFail(pk, err, _) => {
4143+
if let msgs::ErrorAction::IgnoreError = err.err.action {
4144+
// We got a temporary failure updating monitor, but will claim the
4145+
// HTLC when the monitor updating is restored (or on chain).
4146+
log_error!(self.logger, "Temporary failure claiming HTLC, treating as success: {}", err.err.err);
4147+
claimed_any_htlcs = true;
4148+
} else { errs.push((pk, err)); }
4149+
},
4150+
ClaimFundsFromHop::PrevHopForceClosed => unreachable!("We already checked for channel existence, we can't fail here!"),
4151+
ClaimFundsFromHop::DuplicateClaim => {
4152+
// While we should never get here in most cases, if we do, it likely
4153+
// indicates that the HTLC was timed out some time ago and is no longer
4154+
// available to be claimed. Thus, it does not make sense to set
4155+
// `claimed_any_htlcs`.
4156+
},
4157+
ClaimFundsFromHop::Success(_) => claimed_any_htlcs = true,
4158+
}
4159+
}
4160+
}
41344161
}
4135-
4136-
let mut errs = Vec::new();
4137-
let mut claimed_any_htlcs = false;
4138-
for htlc in sources.drain(..) {
4139-
if !valid_mpp {
4140-
if channel_state.is_none() { channel_state = Some(self.channel_state.lock().unwrap()); }
4162+
if !valid_mpp {
4163+
for htlc in sources.drain(..) {
41414164
let mut htlc_msat_height_data = byte_utils::be64_to_array(htlc.value).to_vec();
41424165
htlc_msat_height_data.extend_from_slice(&byte_utils::be32_to_array(
4143-
self.best_block.read().unwrap().height()));
4166+
self.best_block.read().unwrap().height()));
41444167
self.fail_htlc_backwards_internal(
4145-
HTLCSource::PreviousHopData(htlc.prev_hop), &payment_hash,
4146-
HTLCFailReason::Reason { failure_code: 0x4000|15, data: htlc_msat_height_data },
4147-
HTLCDestination::FailedPayment { payment_hash } );
4148-
} else {
4149-
match self.claim_funds_from_hop(channel_state.as_mut().unwrap(), htlc.prev_hop, payment_preimage) {
4150-
ClaimFundsFromHop::MonitorUpdateFail(pk, err, _) => {
4151-
if let msgs::ErrorAction::IgnoreError = err.err.action {
4152-
// We got a temporary failure updating monitor, but will claim the
4153-
// HTLC when the monitor updating is restored (or on chain).
4154-
log_error!(self.logger, "Temporary failure claiming HTLC, treating as success: {}", err.err.err);
4155-
claimed_any_htlcs = true;
4156-
} else { errs.push((pk, err)); }
4157-
},
4158-
ClaimFundsFromHop::PrevHopForceClosed => unreachable!("We already checked for channel existence, we can't fail here!"),
4159-
ClaimFundsFromHop::DuplicateClaim => {
4160-
// While we should never get here in most cases, if we do, it likely
4161-
// indicates that the HTLC was timed out some time ago and is no longer
4162-
// available to be claimed. Thus, it does not make sense to set
4163-
// `claimed_any_htlcs`.
4164-
},
4165-
ClaimFundsFromHop::Success(_) => claimed_any_htlcs = true,
4166-
}
4168+
HTLCSource::PreviousHopData(htlc.prev_hop), &payment_hash,
4169+
HTLCFailReason::Reason { failure_code: 0x4000|15, data: htlc_msat_height_data },
4170+
HTLCDestination::FailedPayment { payment_hash } );
41674171
}
41684172
}
41694173

@@ -4175,10 +4179,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
41754179
});
41764180
}
41774181

4178-
// Now that we've done the entire above loop in one lock, we can handle any errors
4179-
// which were generated.
4180-
channel_state.take();
4181-
4182+
// Now we can handle any errors which were generated.
41824183
for (counterparty_node_id, err) in errs.drain(..) {
41834184
let res: Result<(), _> = Err(err);
41844185
let _ = handle_error!(self, res, counterparty_node_id);

0 commit comments

Comments
 (0)