Skip to content

Commit 32fdeb7

Browse files
authored
Merge pull request #1772 from ViktorTigerstrom/2022-10-move-claimable-htlcs-to-seperate-lock
Move `claimable_htlcs` to separate lock
2 parents a4c4301 + 782eb36 commit 32fdeb7

File tree

1 file changed

+85
-80
lines changed

1 file changed

+85
-80
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 85 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -398,13 +398,6 @@ pub(super) enum RAACommitmentOrder {
398398
// Note this is only exposed in cfg(test):
399399
pub(super) struct ChannelHolder<Signer: Sign> {
400400
pub(super) by_id: HashMap<[u8; 32], Channel<Signer>>,
401-
/// Map from payment hash to the payment data and any HTLCs which are to us and can be
402-
/// failed/claimed by the user.
403-
///
404-
/// Note that while this is held in the same mutex as the channels themselves, no consistency
405-
/// guarantees are made about the channels given here actually existing anymore by the time you
406-
/// go to read them!
407-
claimable_htlcs: HashMap<PaymentHash, (events::PaymentPurpose, Vec<ClaimableHTLC>)>,
408401
/// Messages to send to peers - pushed to in the same lock that they are generated in (except
409402
/// for broadcast messages, where ordering isn't as strict).
410403
pub(super) pending_msg_events: Vec<MessageSendEvent>,
@@ -673,19 +666,21 @@ pub type SimpleRefChannelManager<'a, 'b, 'c, 'd, 'e, M, T, F, L> = ChannelManage
673666
// |
674667
// |__`forward_htlcs`
675668
// |
676-
// |__`channel_state`
669+
// |__`pending_inbound_payments`
677670
// | |
678-
// | |__`id_to_peer`
671+
// | |__`claimable_htlcs`
679672
// | |
680-
// | |__`short_to_chan_info`
681-
// | |
682-
// | |__`per_peer_state`
683-
// | |
684-
// | |__`outbound_scid_aliases`
673+
// | |__`pending_outbound_payments`
685674
// | |
686-
// | |__`pending_inbound_payments`
675+
// | |__`channel_state`
676+
// | |
677+
// | |__`id_to_peer`
687678
// | |
688-
// | |__`pending_outbound_payments`
679+
// | |__`short_to_chan_info`
680+
// | |
681+
// | |__`per_peer_state`
682+
// | |
683+
// | |__`outbound_scid_aliases`
689684
// | |
690685
// | |__`best_block`
691686
// | |
@@ -756,6 +751,15 @@ pub struct ChannelManager<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
756751
#[cfg(not(test))]
757752
forward_htlcs: Mutex<HashMap<u64, Vec<HTLCForwardInfo>>>,
758753

754+
/// Map from payment hash to the payment data and any HTLCs which are to us and can be
755+
/// failed/claimed by the user.
756+
///
757+
/// Note that, no consistency guarantees are made about the channels given here actually
758+
/// existing anymore by the time you go to read them!
759+
///
760+
/// See `ChannelManager` struct-level documentation for lock order requirements.
761+
claimable_htlcs: Mutex<HashMap<PaymentHash, (events::PaymentPurpose, Vec<ClaimableHTLC>)>>,
762+
759763
/// The set of outbound SCID aliases across all our channels, including unconfirmed channels
760764
/// and some closed channels which reached a usable state prior to being closed. This is used
761765
/// only to avoid duplicates, and is not persisted explicitly to disk, but rebuilt from the
@@ -1678,13 +1682,13 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
16781682

16791683
channel_state: Mutex::new(ChannelHolder{
16801684
by_id: HashMap::new(),
1681-
claimable_htlcs: HashMap::new(),
16821685
pending_msg_events: Vec::new(),
16831686
}),
16841687
outbound_scid_aliases: Mutex::new(HashSet::new()),
16851688
pending_inbound_payments: Mutex::new(HashMap::new()),
16861689
pending_outbound_payments: Mutex::new(HashMap::new()),
16871690
forward_htlcs: Mutex::new(HashMap::new()),
1691+
claimable_htlcs: Mutex::new(HashMap::new()),
16881692
id_to_peer: Mutex::new(HashMap::new()),
16891693
short_to_chan_info: FairRwLock::new(HashMap::new()),
16901694

@@ -1922,14 +1926,16 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
19221926
if *counterparty_node_id != chan_entry.get().get_counterparty_node_id(){
19231927
return Err(APIError::APIMisuseError { err: "The passed counterparty_node_id doesn't match the channel's counterparty node_id".to_owned() });
19241928
}
1925-
let per_peer_state = self.per_peer_state.read().unwrap();
1926-
let (shutdown_msg, monitor_update, htlcs) = match per_peer_state.get(&counterparty_node_id) {
1927-
Some(peer_state) => {
1928-
let peer_state = peer_state.lock().unwrap();
1929-
let their_features = &peer_state.latest_features;
1930-
chan_entry.get_mut().get_shutdown(&self.keys_manager, their_features, target_feerate_sats_per_1000_weight)?
1931-
},
1932-
None => return Err(APIError::ChannelUnavailable { err: format!("Not connected to node: {}", counterparty_node_id) }),
1929+
let (shutdown_msg, monitor_update, htlcs) = {
1930+
let per_peer_state = self.per_peer_state.read().unwrap();
1931+
match per_peer_state.get(&counterparty_node_id) {
1932+
Some(peer_state) => {
1933+
let peer_state = peer_state.lock().unwrap();
1934+
let their_features = &peer_state.latest_features;
1935+
chan_entry.get_mut().get_shutdown(&self.keys_manager, their_features, target_feerate_sats_per_1000_weight)?
1936+
},
1937+
None => return Err(APIError::ChannelUnavailable { err: format!("Not connected to node: {}", counterparty_node_id) }),
1938+
}
19331939
};
19341940
failed_htlcs = htlcs;
19351941

@@ -3154,8 +3160,6 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
31543160
mem::swap(&mut forward_htlcs, &mut self.forward_htlcs.lock().unwrap());
31553161

31563162
for (short_chan_id, mut pending_forwards) in forward_htlcs {
3157-
let mut channel_state_lock = self.channel_state.lock().unwrap();
3158-
let channel_state = &mut *channel_state_lock;
31593163
if short_chan_id != 0 {
31603164
macro_rules! forwarding_channel_not_found {
31613165
() => {
@@ -3258,6 +3262,8 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
32583262
continue;
32593263
}
32603264
};
3265+
let mut channel_state_lock = self.channel_state.lock().unwrap();
3266+
let channel_state = &mut *channel_state_lock;
32613267
match channel_state.by_id.entry(forward_chan_id) {
32623268
hash_map::Entry::Vacant(_) => {
32633269
forwarding_channel_not_found!();
@@ -3455,7 +3461,8 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
34553461
payment_secret: $payment_data.payment_secret,
34563462
}
34573463
};
3458-
let (_, htlcs) = channel_state.claimable_htlcs.entry(payment_hash)
3464+
let mut claimable_htlcs = self.claimable_htlcs.lock().unwrap();
3465+
let (_, htlcs) = claimable_htlcs.entry(payment_hash)
34593466
.or_insert_with(|| (purpose(), Vec::new()));
34603467
if htlcs.len() == 1 {
34613468
if let OnionPayload::Spontaneous(_) = htlcs[0].onion_payload {
@@ -3523,7 +3530,7 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
35233530
check_total_value!(payment_data, payment_preimage);
35243531
},
35253532
OnionPayload::Spontaneous(preimage) => {
3526-
match channel_state.claimable_htlcs.entry(payment_hash) {
3533+
match self.claimable_htlcs.lock().unwrap().entry(payment_hash) {
35273534
hash_map::Entry::Vacant(e) => {
35283535
let purpose = events::PaymentPurpose::SpontaneousPayment(preimage);
35293536
e.insert((purpose.clone(), vec![claimable_htlc]));
@@ -3812,29 +3819,29 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
38123819

38133820
true
38143821
});
3822+
}
38153823

3816-
channel_state.claimable_htlcs.retain(|payment_hash, (_, htlcs)| {
3817-
if htlcs.is_empty() {
3818-
// This should be unreachable
3819-
debug_assert!(false);
3824+
self.claimable_htlcs.lock().unwrap().retain(|payment_hash, (_, htlcs)| {
3825+
if htlcs.is_empty() {
3826+
// This should be unreachable
3827+
debug_assert!(false);
3828+
return false;
3829+
}
3830+
if let OnionPayload::Invoice { .. } = htlcs[0].onion_payload {
3831+
// Check if we've received all the parts we need for an MPP (the value of the parts adds to total_msat).
3832+
// In this case we're not going to handle any timeouts of the parts here.
3833+
if htlcs[0].total_msat == htlcs.iter().fold(0, |total, htlc| total + htlc.value) {
3834+
return true;
3835+
} else if htlcs.into_iter().any(|htlc| {
3836+
htlc.timer_ticks += 1;
3837+
return htlc.timer_ticks >= MPP_TIMEOUT_TICKS
3838+
}) {
3839+
timed_out_mpp_htlcs.extend(htlcs.into_iter().map(|htlc| (htlc.prev_hop.clone(), payment_hash.clone())));
38203840
return false;
38213841
}
3822-
if let OnionPayload::Invoice { .. } = htlcs[0].onion_payload {
3823-
// Check if we've received all the parts we need for an MPP (the value of the parts adds to total_msat).
3824-
// In this case we're not going to handle any timeouts of the parts here.
3825-
if htlcs[0].total_msat == htlcs.iter().fold(0, |total, htlc| total + htlc.value) {
3826-
return true;
3827-
} else if htlcs.into_iter().any(|htlc| {
3828-
htlc.timer_ticks += 1;
3829-
return htlc.timer_ticks >= MPP_TIMEOUT_TICKS
3830-
}) {
3831-
timed_out_mpp_htlcs.extend(htlcs.into_iter().map(|htlc| (htlc.prev_hop.clone(), payment_hash.clone())));
3832-
return false;
3833-
}
3834-
}
3835-
true
3836-
});
3837-
}
3842+
}
3843+
true
3844+
});
38383845

38393846
for htlc_source in timed_out_mpp_htlcs.drain(..) {
38403847
let receiver = HTLCDestination::FailedPayment { payment_hash: htlc_source.1 };
@@ -3867,10 +3874,7 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
38673874
pub fn fail_htlc_backwards(&self, payment_hash: &PaymentHash) {
38683875
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
38693876

3870-
let removed_source = {
3871-
let mut channel_state = self.channel_state.lock().unwrap();
3872-
channel_state.claimable_htlcs.remove(payment_hash)
3873-
};
3877+
let removed_source = self.claimable_htlcs.lock().unwrap().remove(payment_hash);
38743878
if let Some((_, mut sources)) = removed_source {
38753879
for htlc in sources.drain(..) {
38763880
let mut htlc_msat_height_data = byte_utils::be64_to_array(htlc.value).to_vec();
@@ -4172,7 +4176,7 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
41724176

41734177
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
41744178

4175-
let removed_source = self.channel_state.lock().unwrap().claimable_htlcs.remove(&payment_hash);
4179+
let removed_source = self.claimable_htlcs.lock().unwrap().remove(&payment_hash);
41764180
if let Some((payment_purpose, mut sources)) = removed_source {
41774181
assert!(!sources.is_empty());
41784182

@@ -6093,28 +6097,28 @@ where
60936097
}
60946098
true
60956099
});
6100+
}
60966101

6097-
if let Some(height) = height_opt {
6098-
channel_state.claimable_htlcs.retain(|payment_hash, (_, htlcs)| {
6099-
htlcs.retain(|htlc| {
6100-
// If height is approaching the number of blocks we think it takes us to get
6101-
// our commitment transaction confirmed before the HTLC expires, plus the
6102-
// number of blocks we generally consider it to take to do a commitment update,
6103-
// just give up on it and fail the HTLC.
6104-
if height >= htlc.cltv_expiry - HTLC_FAIL_BACK_BUFFER {
6105-
let mut htlc_msat_height_data = byte_utils::be64_to_array(htlc.value).to_vec();
6106-
htlc_msat_height_data.extend_from_slice(&byte_utils::be32_to_array(height));
6107-
6108-
timed_out_htlcs.push((HTLCSource::PreviousHopData(htlc.prev_hop.clone()), payment_hash.clone(), HTLCFailReason::Reason {
6109-
failure_code: 0x4000 | 15,
6110-
data: htlc_msat_height_data
6111-
}, HTLCDestination::FailedPayment { payment_hash: payment_hash.clone() }));
6112-
false
6113-
} else { true }
6114-
});
6115-
!htlcs.is_empty() // Only retain this entry if htlcs has at least one entry.
6102+
if let Some(height) = height_opt {
6103+
self.claimable_htlcs.lock().unwrap().retain(|payment_hash, (_, htlcs)| {
6104+
htlcs.retain(|htlc| {
6105+
// If height is approaching the number of blocks we think it takes us to get
6106+
// our commitment transaction confirmed before the HTLC expires, plus the
6107+
// number of blocks we generally consider it to take to do a commitment update,
6108+
// just give up on it and fail the HTLC.
6109+
if height >= htlc.cltv_expiry - HTLC_FAIL_BACK_BUFFER {
6110+
let mut htlc_msat_height_data = byte_utils::be64_to_array(htlc.value).to_vec();
6111+
htlc_msat_height_data.extend_from_slice(&byte_utils::be32_to_array(height));
6112+
6113+
timed_out_htlcs.push((HTLCSource::PreviousHopData(htlc.prev_hop.clone()), payment_hash.clone(), HTLCFailReason::Reason {
6114+
failure_code: 0x4000 | 15,
6115+
data: htlc_msat_height_data
6116+
}, HTLCDestination::FailedPayment { payment_hash: payment_hash.clone() }));
6117+
false
6118+
} else { true }
61166119
});
6117-
}
6120+
!htlcs.is_empty() // Only retain this entry if htlcs has at least one entry.
6121+
});
61186122
}
61196123

61206124
self.handle_init_event_channel_failures(failed_channels);
@@ -6934,10 +6938,13 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> Writeable for ChannelMana
69346938
}
69356939
}
69366940

6937-
let channel_state = self.channel_state.lock().unwrap();
6941+
let pending_inbound_payments = self.pending_inbound_payments.lock().unwrap();
6942+
let claimable_htlcs = self.claimable_htlcs.lock().unwrap();
6943+
let pending_outbound_payments = self.pending_outbound_payments.lock().unwrap();
6944+
69386945
let mut htlc_purposes: Vec<&events::PaymentPurpose> = Vec::new();
6939-
(channel_state.claimable_htlcs.len() as u64).write(writer)?;
6940-
for (payment_hash, (purpose, previous_hops)) in channel_state.claimable_htlcs.iter() {
6946+
(claimable_htlcs.len() as u64).write(writer)?;
6947+
for (payment_hash, (purpose, previous_hops)) in claimable_htlcs.iter() {
69416948
payment_hash.write(writer)?;
69426949
(previous_hops.len() as u64).write(writer)?;
69436950
for htlc in previous_hops.iter() {
@@ -6954,8 +6961,6 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> Writeable for ChannelMana
69546961
peer_state.latest_features.write(writer)?;
69556962
}
69566963

6957-
let pending_inbound_payments = self.pending_inbound_payments.lock().unwrap();
6958-
let pending_outbound_payments = self.pending_outbound_payments.lock().unwrap();
69596964
let events = self.pending_events.lock().unwrap();
69606965
(events.len() as u64).write(writer)?;
69616966
for event in events.iter() {
@@ -7548,14 +7553,14 @@ impl<'a, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
75487553

75497554
channel_state: Mutex::new(ChannelHolder {
75507555
by_id,
7551-
claimable_htlcs,
75527556
pending_msg_events: Vec::new(),
75537557
}),
75547558
inbound_payment_key: expanded_inbound_key,
75557559
pending_inbound_payments: Mutex::new(pending_inbound_payments),
75567560
pending_outbound_payments: Mutex::new(pending_outbound_payments.unwrap()),
75577561

75587562
forward_htlcs: Mutex::new(forward_htlcs),
7563+
claimable_htlcs: Mutex::new(claimable_htlcs),
75597564
outbound_scid_aliases: Mutex::new(outbound_scid_aliases),
75607565
id_to_peer: Mutex::new(id_to_peer),
75617566
short_to_chan_info: FairRwLock::new(short_to_chan_info),

0 commit comments

Comments
 (0)