Skip to content

Commit b79631d

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 caf1a9c commit b79631d

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"))]
@@ -802,7 +802,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
802802
tx_broadcaster,
803803

804804
latest_block_height: AtomicUsize::new(params.latest_height),
805-
last_block_hash: Mutex::new(params.latest_hash),
805+
last_block_hash: RwLock::new(params.latest_hash),
806806
secp_ctx,
807807

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

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

25112511
fn internal_funding_signed(&self, counterparty_node_id: &PublicKey, msg: &msgs::FundingSigned) -> Result<(), MsgHandleErrInternal> {
25122512
let (funding_txo, user_id) = {
2513+
let last_block_hash = *self.last_block_hash.read().unwrap();
25132514
let mut channel_lock = self.channel_state.lock().unwrap();
25142515
let channel_state = &mut *channel_lock;
25152516
match channel_state.by_id.entry(msg.channel_id) {
25162517
hash_map::Entry::Occupied(mut chan) => {
25172518
if chan.get().get_counterparty_node_id() != *counterparty_node_id {
25182519
return Err(MsgHandleErrInternal::send_err_msg_no_close("Got a message for a channel from the wrong node!".to_owned(), msg.channel_id));
25192520
}
2520-
let last_block_hash = *self.last_block_hash.lock().unwrap();
25212521
let monitor = match chan.get_mut().funding_signed(&msg, last_block_hash, &self.logger) {
25222522
Ok(update) => update,
25232523
Err(e) => try_chan_entry!(self, Err(e), channel_state, chan),
@@ -3256,7 +3256,12 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
32563256
// See the docs for `ChannelManagerReadArgs` for more.
32573257
let block_hash = header.block_hash();
32583258
log_trace!(self.logger, "Block {} at height {} connected", block_hash, height);
3259+
32593260
let _persistence_guard = PersistenceNotifierGuard::new(&self.total_consistency_lock, &self.persistence_notifier);
3261+
3262+
self.latest_block_height.store(height as usize, Ordering::Release);
3263+
*self.last_block_hash.write().unwrap() = block_hash;
3264+
32603265
let mut failed_channels = Vec::new();
32613266
let mut timed_out_htlcs = Vec::new();
32623267
{
@@ -3345,8 +3350,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
33453350
for (source, payment_hash, reason) in timed_out_htlcs.drain(..) {
33463351
self.fail_htlc_backwards_internal(self.channel_state.lock().unwrap(), source, &payment_hash, reason);
33473352
}
3348-
self.latest_block_height.store(height as usize, Ordering::Release);
3349-
*self.last_block_hash.try_lock().expect("block_(dis)connected must not be called in parallel") = block_hash;
3353+
33503354
loop {
33513355
// Update last_node_announcement_serial to be the max of its current value and the
33523356
// block timestamp. This should keep us close to the current time without relying on
@@ -3370,6 +3374,10 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
33703374
// during initialization prior to the chain_monitor being fully configured in some cases.
33713375
// See the docs for `ChannelManagerReadArgs` for more.
33723376
let _persistence_guard = PersistenceNotifierGuard::new(&self.total_consistency_lock, &self.persistence_notifier);
3377+
3378+
self.latest_block_height.fetch_sub(1, Ordering::AcqRel);
3379+
*self.last_block_hash.write().unwrap() = header.block_hash();
3380+
33733381
let mut failed_channels = Vec::new();
33743382
{
33753383
let mut channel_lock = self.channel_state.lock().unwrap();
@@ -3393,9 +3401,8 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
33933401
}
33943402
});
33953403
}
3404+
33963405
self.handle_init_event_channel_failures(failed_channels);
3397-
self.latest_block_height.fetch_sub(1, Ordering::AcqRel);
3398-
*self.last_block_hash.try_lock().expect("block_(dis)connected must not be called in parallel") = header.block_hash();
33993406
}
34003407

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

39523959
self.genesis_hash.write(writer)?;
39533960
(self.latest_block_height.load(Ordering::Acquire) as u32).write(writer)?;
3954-
self.last_block_hash.lock().unwrap().write(writer)?;
3961+
self.last_block_hash.read().unwrap().write(writer)?;
39553962

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

42554262
latest_block_height: AtomicUsize::new(latest_block_height as usize),
4256-
last_block_hash: Mutex::new(last_block_hash),
4263+
last_block_hash: RwLock::new(last_block_hash),
42574264
secp_ctx,
42584265

42594266
channel_state: Mutex::new(ChannelHolder {

0 commit comments

Comments
 (0)