Skip to content

Commit 035dda6

Browse files
committed
Hold ChannelManager locks independently
ChannelManager reads channel_state and last_block_hash while processing funding_created and funding_signed messages. It writes these while processing block_connected and block_disconnected events. To avoid any potential deadlocks, have each site hold these locks independent of one another and in a consistent order. Additionally, use a RwLock instead of Mutex for last_block_hash since exclusive access is not needed in funding_created / funding_signed and cannot be guaranteed in block_connected / block_disconnected because of the reads in the former.
1 parent d21d8b3 commit 035dda6

File tree

1 file changed

+17
-10
lines changed

1 file changed

+17
-10
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@ pub struct ChannelManager<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref,
423423
pub(super) latest_block_height: AtomicUsize,
424424
#[cfg(not(test))]
425425
latest_block_height: AtomicUsize,
426-
last_block_hash: Mutex<BlockHash>,
426+
last_block_hash: RwLock<BlockHash>,
427427
secp_ctx: Secp256k1<secp256k1::All>,
428428

429429
#[cfg(any(test, feature = "_test_utils"))]
@@ -803,7 +803,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
803803
tx_broadcaster,
804804

805805
latest_block_height: AtomicUsize::new(params.latest_height),
806-
last_block_hash: Mutex::new(params.latest_hash),
806+
last_block_hash: RwLock::new(params.latest_hash),
807807
secp_ctx,
808808

809809
channel_state: Mutex::new(ChannelHolder{
@@ -2454,14 +2454,14 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
24542454

24552455
fn internal_funding_created(&self, counterparty_node_id: &PublicKey, msg: &msgs::FundingCreated) -> Result<(), MsgHandleErrInternal> {
24562456
let ((funding_msg, monitor), mut chan) = {
2457+
let last_block_hash = *self.last_block_hash.read().unwrap();
24572458
let mut channel_lock = self.channel_state.lock().unwrap();
24582459
let channel_state = &mut *channel_lock;
24592460
match channel_state.by_id.entry(msg.temporary_channel_id.clone()) {
24602461
hash_map::Entry::Occupied(mut chan) => {
24612462
if chan.get().get_counterparty_node_id() != *counterparty_node_id {
24622463
return Err(MsgHandleErrInternal::send_err_msg_no_close("Got a message for a channel from the wrong node!".to_owned(), msg.temporary_channel_id));
24632464
}
2464-
let last_block_hash = *self.last_block_hash.lock().unwrap();
24652465
(try_chan_entry!(self, chan.get_mut().funding_created(msg, last_block_hash, &self.logger), channel_state, chan), chan.remove())
24662466
},
24672467
hash_map::Entry::Vacant(_) => return Err(MsgHandleErrInternal::send_err_msg_no_close("Failed to find corresponding channel".to_owned(), msg.temporary_channel_id))
@@ -2511,14 +2511,14 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
25112511

25122512
fn internal_funding_signed(&self, counterparty_node_id: &PublicKey, msg: &msgs::FundingSigned) -> Result<(), MsgHandleErrInternal> {
25132513
let (funding_txo, user_id) = {
2514+
let last_block_hash = *self.last_block_hash.read().unwrap();
25142515
let mut channel_lock = self.channel_state.lock().unwrap();
25152516
let channel_state = &mut *channel_lock;
25162517
match channel_state.by_id.entry(msg.channel_id) {
25172518
hash_map::Entry::Occupied(mut chan) => {
25182519
if chan.get().get_counterparty_node_id() != *counterparty_node_id {
25192520
return Err(MsgHandleErrInternal::send_err_msg_no_close("Got a message for a channel from the wrong node!".to_owned(), msg.channel_id));
25202521
}
2521-
let last_block_hash = *self.last_block_hash.lock().unwrap();
25222522
let monitor = match chan.get_mut().funding_signed(&msg, last_block_hash, &self.logger) {
25232523
Ok(update) => update,
25242524
Err(e) => try_chan_entry!(self, Err(e), channel_state, chan),
@@ -3257,7 +3257,12 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
32573257
// See the docs for `ChannelManagerReadArgs` for more.
32583258
let block_hash = header.block_hash();
32593259
log_trace!(self.logger, "Block {} at height {} connected", block_hash, height);
3260+
32603261
let _persistence_guard = PersistenceNotifierGuard::new(&self.total_consistency_lock, &self.persistence_notifier);
3262+
3263+
self.latest_block_height.store(height as usize, Ordering::Release);
3264+
*self.last_block_hash.write().unwrap() = block_hash;
3265+
32613266
let mut failed_channels = Vec::new();
32623267
let mut timed_out_htlcs = Vec::new();
32633268
{
@@ -3346,8 +3351,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
33463351
for (source, payment_hash, reason) in timed_out_htlcs.drain(..) {
33473352
self.fail_htlc_backwards_internal(self.channel_state.lock().unwrap(), source, &payment_hash, reason);
33483353
}
3349-
self.latest_block_height.store(height as usize, Ordering::Release);
3350-
*self.last_block_hash.try_lock().expect("block_(dis)connected must not be called in parallel") = block_hash;
3354+
33513355
loop {
33523356
// Update last_node_announcement_serial to be the max of its current value and the
33533357
// block timestamp. This should keep us close to the current time without relying on
@@ -3371,6 +3375,10 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
33713375
// during initialization prior to the chain_monitor being fully configured in some cases.
33723376
// See the docs for `ChannelManagerReadArgs` for more.
33733377
let _persistence_guard = PersistenceNotifierGuard::new(&self.total_consistency_lock, &self.persistence_notifier);
3378+
3379+
self.latest_block_height.fetch_sub(1, Ordering::AcqRel);
3380+
*self.last_block_hash.write().unwrap() = header.block_hash();
3381+
33743382
let mut failed_channels = Vec::new();
33753383
{
33763384
let mut channel_lock = self.channel_state.lock().unwrap();
@@ -3394,9 +3402,8 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
33943402
}
33953403
});
33963404
}
3405+
33973406
self.handle_init_event_channel_failures(failed_channels);
3398-
self.latest_block_height.fetch_sub(1, Ordering::AcqRel);
3399-
*self.last_block_hash.try_lock().expect("block_(dis)connected must not be called in parallel") = header.block_hash();
34003407
}
34013408

34023409
/// Blocks until ChannelManager needs to be persisted or a timeout is reached. It returns a bool
@@ -3952,7 +3959,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> Writeable f
39523959

39533960
self.genesis_hash.write(writer)?;
39543961
(self.latest_block_height.load(Ordering::Acquire) as u32).write(writer)?;
3955-
self.last_block_hash.lock().unwrap().write(writer)?;
3962+
self.last_block_hash.read().unwrap().write(writer)?;
39563963

39573964
let channel_state = self.channel_state.lock().unwrap();
39583965
let mut unfunded_channels = 0;
@@ -4254,7 +4261,7 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
42544261
tx_broadcaster: args.tx_broadcaster,
42554262

42564263
latest_block_height: AtomicUsize::new(latest_block_height as usize),
4257-
last_block_hash: Mutex::new(last_block_hash),
4264+
last_block_hash: RwLock::new(last_block_hash),
42584265
secp_ctx,
42594266

42604267
channel_state: Mutex::new(ChannelHolder {

0 commit comments

Comments
 (0)