Skip to content

Commit 5e14a3f

Browse files
committed
Handle inferred splice_locked on reestablish first prior to updates
Upon channel reestablishment, we free our holding cells to send any pending updates to our peer. If we happened to implicitly lock a pending splice during reestablishment, we want to make sure any updates we send after the fact are considering the new channel state (post-splice), even if the update was queued while the splice was still pending. Therefore, we must always handle the inferred `splice_locked` first. Found by the `chanmon_consistency` fuzz target.
1 parent 7165827 commit 5e14a3f

2 files changed

Lines changed: 257 additions & 116 deletions

File tree

lightning/src/ln/channelmanager.rs

Lines changed: 172 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -12368,43 +12368,13 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1236812368
match peer_state.channel_by_id.entry(msg.channel_id) {
1236912369
hash_map::Entry::Occupied(mut chan_entry) => {
1237012370
if let Some(chan) = chan_entry.get_mut().as_funded_mut() {
12371-
let logger = WithChannelContext::from(&self.logger, &chan.context, None);
12372-
let res = chan.channel_ready(
12373-
&msg,
12374-
&self.node_signer,
12375-
self.chain_hash,
12376-
&self.config.read().unwrap(),
12377-
&self.best_block.read().unwrap(),
12378-
&&logger
12371+
let res = self.internal_channel_ready_with_funded_channel(
12372+
counterparty_node_id,
12373+
msg,
12374+
chan,
12375+
&mut peer_state.pending_msg_events,
1237912376
);
12380-
let announcement_sigs_opt =
12381-
try_channel_entry!(self, peer_state, res, chan_entry);
12382-
if let Some(announcement_sigs) = announcement_sigs_opt {
12383-
log_trace!(logger, "Sending announcement_signatures");
12384-
peer_state.pending_msg_events.push(MessageSendEvent::SendAnnouncementSignatures {
12385-
node_id: counterparty_node_id.clone(),
12386-
msg: announcement_sigs,
12387-
});
12388-
} else if chan.context.is_usable() {
12389-
// If we're sending an announcement_signatures, we'll send the (public)
12390-
// channel_update after sending a channel_announcement when we receive our
12391-
// counterparty's announcement_signatures. Thus, we only bother to send a
12392-
// channel_update here if the channel is not public, i.e. we're not sending an
12393-
// announcement_signatures.
12394-
log_trace!(logger, "Sending private initial channel_update for our counterparty");
12395-
if let Ok((msg, _, _)) = self.get_channel_update_for_unicast(chan) {
12396-
peer_state.pending_msg_events.push(MessageSendEvent::SendChannelUpdate {
12397-
node_id: counterparty_node_id.clone(),
12398-
msg,
12399-
});
12400-
}
12401-
}
12402-
12403-
{
12404-
let mut pending_events = self.pending_events.lock().unwrap();
12405-
emit_initial_channel_ready_event!(pending_events, chan);
12406-
}
12407-
12377+
try_channel_entry!(self, peer_state, res, chan_entry);
1240812378
Ok(())
1240912379
} else {
1241012380
try_channel_entry!(self, peer_state, Err(ChannelError::close(
@@ -12417,6 +12387,49 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1241712387
}
1241812388
}
1241912389

12390+
#[rustfmt::skip]
12391+
fn internal_channel_ready_with_funded_channel(
12392+
&self, counterparty_node_id: &PublicKey, msg: &msgs::ChannelReady,
12393+
chan: &mut FundedChannel<SP>, pending_msg_events: &mut Vec<MessageSendEvent>,
12394+
) -> Result<(), ChannelError> {
12395+
let logger = WithChannelContext::from(&self.logger, &chan.context, None);
12396+
let announcement_sigs_opt = chan.channel_ready(
12397+
&msg,
12398+
&self.node_signer,
12399+
self.chain_hash,
12400+
&self.config.read().unwrap(),
12401+
&self.best_block.read().unwrap(),
12402+
&&logger
12403+
)?;
12404+
if let Some(announcement_sigs) = announcement_sigs_opt {
12405+
log_trace!(logger, "Sending announcement_signatures");
12406+
pending_msg_events.push(MessageSendEvent::SendAnnouncementSignatures {
12407+
node_id: counterparty_node_id.clone(),
12408+
msg: announcement_sigs,
12409+
});
12410+
} else if chan.context.is_usable() {
12411+
// If we're sending an announcement_signatures, we'll send the (public)
12412+
// channel_update after sending a channel_announcement when we receive our
12413+
// counterparty's announcement_signatures. Thus, we only bother to send a
12414+
// channel_update here if the channel is not public, i.e. we're not sending an
12415+
// announcement_signatures.
12416+
log_trace!(logger, "Sending private initial channel_update for our counterparty");
12417+
if let Ok((msg, _, _)) = self.get_channel_update_for_unicast(chan) {
12418+
pending_msg_events.push(MessageSendEvent::SendChannelUpdate {
12419+
node_id: counterparty_node_id.clone(),
12420+
msg,
12421+
});
12422+
}
12423+
}
12424+
12425+
{
12426+
let mut pending_events = self.pending_events.lock().unwrap();
12427+
emit_initial_channel_ready_event!(pending_events, chan);
12428+
}
12429+
12430+
Ok(())
12431+
}
12432+
1242012433
fn internal_shutdown(
1242112434
&self, counterparty_node_id: &PublicKey, msg: &msgs::Shutdown,
1242212435
) -> Result<(), MsgHandleErrInternal> {
@@ -13240,7 +13253,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1324013253

1324113254
#[rustfmt::skip]
1324213255
fn internal_channel_reestablish(&self, counterparty_node_id: &PublicKey, msg: &msgs::ChannelReestablish) -> Result<(), MsgHandleErrInternal> {
13243-
let (inferred_splice_locked, need_lnd_workaround, holding_cell_res) = {
13256+
let (post_splice_locked_update, holding_cell_res) = {
1324413257
let per_peer_state = self.per_peer_state.read().unwrap();
1324513258

1324613259
let peer_state_mutex = per_peer_state.get(counterparty_node_id).ok_or_else(|| {
@@ -13249,7 +13262,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1324913262
let logger = WithContext::from(&self.logger, Some(*counterparty_node_id), Some(msg.channel_id), None);
1325013263
let mut peer_state_lock = peer_state_mutex.lock().unwrap();
1325113264
let peer_state = &mut *peer_state_lock;
13252-
match peer_state.channel_by_id.entry(msg.channel_id) {
13265+
let post_splice_locked_update = match peer_state.channel_by_id.entry(msg.channel_id) {
1325313266
hash_map::Entry::Occupied(mut chan_entry) => {
1325413267
if let Some(chan) = chan_entry.get_mut().as_funded_mut() {
1325513268
// Currently, we expect all holding cell update_adds to be dropped on peer
@@ -13285,6 +13298,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1328513298
}
1328613299
}
1328713300
let need_lnd_workaround = chan.context.workaround_lnd_bug_4006.take();
13301+
let inferred_splice_locked = responses.inferred_splice_locked;
1328813302
let funding_tx_signed = if responses.tx_signatures.is_some() || responses.splice_locked.is_some() {
1328913303
Some(FundingTxSigned {
1329013304
tx_signatures: responses.tx_signatures,
@@ -13305,8 +13319,33 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1330513319
peer_state.pending_msg_events.push(upd);
1330613320
}
1330713321

13308-
let holding_cell_res = self.check_free_peer_holding_cells(peer_state);
13309-
(responses.inferred_splice_locked, need_lnd_workaround, holding_cell_res)
13322+
if let Some(channel_ready_msg) = need_lnd_workaround {
13323+
let res = self.internal_channel_ready_with_funded_channel(
13324+
counterparty_node_id,
13325+
&channel_ready_msg,
13326+
chan,
13327+
&mut peer_state.pending_msg_events,
13328+
);
13329+
try_channel_entry!(self, peer_state, res, chan_entry);
13330+
}
13331+
13332+
// A reestablish may infer a missed `splice_locked`; apply it before freeing
13333+
// holding cells so we don't generate commitment updates against stale splice
13334+
// state.
13335+
if let Some(splice_locked) = inferred_splice_locked {
13336+
let result = self.internal_splice_locked_with_funded_channel(
13337+
counterparty_node_id,
13338+
&splice_locked,
13339+
chan,
13340+
&mut peer_state.in_flight_monitor_updates,
13341+
&mut peer_state.monitor_update_blocked_actions,
13342+
&mut peer_state.pending_msg_events,
13343+
peer_state.is_connected,
13344+
);
13345+
try_channel_entry!(self, peer_state, result, chan_entry)
13346+
} else {
13347+
None
13348+
}
1331013349
} else {
1331113350
return try_channel_entry!(self, peer_state, Err(ChannelError::close(
1331213351
"Got a channel_reestablish message for an unfunded channel!".into())), chan_entry);
@@ -13344,18 +13383,16 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1334413383
return Err(MsgHandleErrInternal::no_such_channel_for_peer(counterparty_node_id, msg.channel_id)
1334513384
)
1334613385
}
13347-
}
13348-
};
13349-
13350-
self.handle_holding_cell_free_result(holding_cell_res);
13386+
};
1335113387

13352-
if let Some(channel_ready_msg) = need_lnd_workaround {
13353-
self.internal_channel_ready(counterparty_node_id, &channel_ready_msg)?;
13354-
}
13388+
let holding_cell_res = self.check_free_peer_holding_cells(peer_state);
13389+
(post_splice_locked_update, holding_cell_res)
13390+
};
1335513391

13356-
if let Some(splice_locked) = inferred_splice_locked {
13357-
self.internal_splice_locked(counterparty_node_id, &splice_locked)?;
13392+
if let Some(data) = post_splice_locked_update {
13393+
self.handle_post_monitor_update_chan_resume(data);
1335813394
}
13395+
self.handle_holding_cell_free_result(holding_cell_res);
1335913396

1336013397
Ok(())
1336113398
}
@@ -13585,9 +13622,8 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1358513622
})?;
1358613623
let mut peer_state_lock = peer_state_mutex.lock().unwrap();
1358713624
let peer_state = &mut *peer_state_lock;
13588-
1358913625
// Look for the channel
13590-
match peer_state.channel_by_id.entry(msg.channel_id) {
13626+
let post_update_data = match peer_state.channel_by_id.entry(msg.channel_id) {
1359113627
hash_map::Entry::Vacant(_) => {
1359213628
return Err(MsgHandleErrInternal::no_such_channel_for_peer(
1359313629
counterparty_node_id,
@@ -13596,73 +13632,16 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1359613632
},
1359713633
hash_map::Entry::Occupied(mut chan_entry) => {
1359813634
if let Some(chan) = chan_entry.get_mut().as_funded_mut() {
13599-
let logger = WithChannelContext::from(&self.logger, &chan.context, None);
13600-
let result = chan.splice_locked(
13635+
let result = self.internal_splice_locked_with_funded_channel(
13636+
counterparty_node_id,
1360113637
msg,
13602-
&self.node_signer,
13603-
self.chain_hash,
13604-
&self.config.read().unwrap(),
13605-
self.best_block.read().unwrap().height,
13606-
&&logger,
13638+
chan,
13639+
&mut peer_state.in_flight_monitor_updates,
13640+
&mut peer_state.monitor_update_blocked_actions,
13641+
&mut peer_state.pending_msg_events,
13642+
peer_state.is_connected,
1360713643
);
13608-
let splice_promotion = try_channel_entry!(self, peer_state, result, chan_entry);
13609-
if let Some(splice_promotion) = splice_promotion {
13610-
{
13611-
let mut short_to_chan_info = self.short_to_chan_info.write().unwrap();
13612-
insert_short_channel_id!(short_to_chan_info, chan);
13613-
}
13614-
13615-
{
13616-
let mut pending_events = self.pending_events.lock().unwrap();
13617-
pending_events.push_back((
13618-
events::Event::ChannelReady {
13619-
channel_id: chan.context.channel_id(),
13620-
user_channel_id: chan.context.get_user_id(),
13621-
counterparty_node_id: chan.context.get_counterparty_node_id(),
13622-
funding_txo: Some(
13623-
splice_promotion.funding_txo.into_bitcoin_outpoint(),
13624-
),
13625-
channel_type: chan.funding.get_channel_type().clone(),
13626-
},
13627-
None,
13628-
));
13629-
splice_promotion.discarded_funding.into_iter().for_each(
13630-
|funding_info| {
13631-
let event = Event::DiscardFunding {
13632-
channel_id: chan.context.channel_id(),
13633-
funding_info,
13634-
};
13635-
pending_events.push_back((event, None));
13636-
},
13637-
);
13638-
}
13639-
13640-
if let Some(announcement_sigs) = splice_promotion.announcement_sigs {
13641-
log_trace!(logger, "Sending announcement_signatures",);
13642-
peer_state.pending_msg_events.push(
13643-
MessageSendEvent::SendAnnouncementSignatures {
13644-
node_id: counterparty_node_id.clone(),
13645-
msg: announcement_sigs,
13646-
},
13647-
);
13648-
}
13649-
13650-
if let Some(monitor_update) = splice_promotion.monitor_update {
13651-
if let Some(data) = self.handle_new_monitor_update(
13652-
&mut peer_state.in_flight_monitor_updates,
13653-
&mut peer_state.monitor_update_blocked_actions,
13654-
&mut peer_state.pending_msg_events,
13655-
peer_state.is_connected,
13656-
chan,
13657-
splice_promotion.funding_txo,
13658-
monitor_update,
13659-
) {
13660-
mem::drop(peer_state_lock);
13661-
mem::drop(per_peer_state);
13662-
self.handle_post_monitor_update_chan_resume(data);
13663-
}
13664-
}
13665-
}
13644+
try_channel_entry!(self, peer_state, result, chan_entry)
1366613645
} else {
1366713646
return Err(MsgHandleErrInternal::send_err_msg_no_close(
1366813647
"Channel is not funded, cannot splice".to_owned(),
@@ -13671,10 +13650,87 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1367113650
}
1367213651
},
1367313652
};
13653+
mem::drop(peer_state_lock);
13654+
mem::drop(per_peer_state);
13655+
13656+
if let Some(data) = post_update_data {
13657+
self.handle_post_monitor_update_chan_resume(data);
13658+
}
1367413659

1367513660
Ok(())
1367613661
}
1367713662

13663+
fn internal_splice_locked_with_funded_channel(
13664+
&self, counterparty_node_id: &PublicKey, msg: &msgs::SpliceLocked,
13665+
chan: &mut FundedChannel<SP>,
13666+
in_flight_monitor_updates: &mut BTreeMap<ChannelId, (OutPoint, Vec<ChannelMonitorUpdate>)>,
13667+
monitor_update_blocked_actions: &mut BTreeMap<
13668+
ChannelId,
13669+
Vec<MonitorUpdateCompletionAction>,
13670+
>,
13671+
pending_msg_events: &mut Vec<MessageSendEvent>, is_connected: bool,
13672+
) -> Result<Option<PostMonitorUpdateChanResume>, ChannelError> {
13673+
let logger = WithChannelContext::from(&self.logger, &chan.context, None);
13674+
let splice_promotion = chan.splice_locked(
13675+
msg,
13676+
&self.node_signer,
13677+
self.chain_hash,
13678+
&self.config.read().unwrap(),
13679+
self.best_block.read().unwrap().height,
13680+
&&logger,
13681+
)?;
13682+
let mut post_update_data = None;
13683+
if let Some(splice_promotion) = splice_promotion {
13684+
{
13685+
let mut short_to_chan_info = self.short_to_chan_info.write().unwrap();
13686+
insert_short_channel_id!(short_to_chan_info, chan);
13687+
}
13688+
13689+
{
13690+
let mut pending_events = self.pending_events.lock().unwrap();
13691+
pending_events.push_back((
13692+
events::Event::ChannelReady {
13693+
channel_id: chan.context.channel_id(),
13694+
user_channel_id: chan.context.get_user_id(),
13695+
counterparty_node_id: chan.context.get_counterparty_node_id(),
13696+
funding_txo: Some(splice_promotion.funding_txo.into_bitcoin_outpoint()),
13697+
channel_type: chan.funding.get_channel_type().clone(),
13698+
},
13699+
None,
13700+
));
13701+
splice_promotion.discarded_funding.into_iter().for_each(|funding_info| {
13702+
let event = Event::DiscardFunding {
13703+
channel_id: chan.context.channel_id(),
13704+
funding_info,
13705+
};
13706+
pending_events.push_back((event, None));
13707+
});
13708+
}
13709+
13710+
if let Some(announcement_sigs) = splice_promotion.announcement_sigs {
13711+
log_trace!(logger, "Sending announcement_signatures",);
13712+
pending_msg_events.push(MessageSendEvent::SendAnnouncementSignatures {
13713+
node_id: counterparty_node_id.clone(),
13714+
msg: announcement_sigs,
13715+
});
13716+
}
13717+
13718+
if let Some(monitor_update) = splice_promotion.monitor_update {
13719+
post_update_data = self.handle_new_monitor_update(
13720+
in_flight_monitor_updates,
13721+
monitor_update_blocked_actions,
13722+
pending_msg_events,
13723+
is_connected,
13724+
chan,
13725+
splice_promotion.funding_txo,
13726+
monitor_update,
13727+
);
13728+
}
13729+
}
13730+
13731+
Ok(post_update_data)
13732+
}
13733+
1367813734
/// Process pending events from the [`chain::Watch`], returning whether any events were processed.
1367913735
fn process_pending_monitor_events(&self) -> bool {
1368013736
debug_assert!(self.total_consistency_lock.try_write().is_err()); // Caller holds read lock

0 commit comments

Comments
 (0)