Skip to content

Commit e502ce3

Browse files
committed
Delay processing splice initial commitment signed from counterparty
We delay processing it until the user manually approves the splice via `Channel::funding_transaction_signed`, as otherwise, there would be a [`ChannelMonitorUpdateStep::RenegotiatedFunding`] committed that we would need to undo if they no longer wish to proceed. Note that this doesn't need to be done with dual-funded channels as there is no equivalent monitor update for them.
1 parent 51380bf commit e502ce3

File tree

2 files changed

+128
-52
lines changed

2 files changed

+128
-52
lines changed

lightning/src/ln/channel.rs

Lines changed: 63 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2192,6 +2192,7 @@ where
21922192
Some(FundingNegotiation::AwaitingSignatures {
21932193
is_initiator,
21942194
funding,
2195+
initial_commit_sig_from_counterparty: None,
21952196
});
21962197
interactive_tx_constructor
21972198
})?
@@ -2277,6 +2278,12 @@ where
22772278
})
22782279
.map(|funding_negotiation| funding_negotiation.as_funding().is_some())
22792280
.unwrap_or(false);
2281+
let has_holder_tx_signatures = funded_channel
2282+
.context
2283+
.interactive_tx_signing_session
2284+
.as_ref()
2285+
.map(|session| session.holder_tx_signatures().is_some())
2286+
.unwrap_or(false);
22802287
let session_received_commitment_signed = funded_channel
22812288
.context
22822289
.interactive_tx_signing_session
@@ -2286,9 +2293,26 @@ where
22862293
// which must always come after the initial commitment signed is sent.
22872294
.unwrap_or(true);
22882295
let res = if has_negotiated_pending_splice && !session_received_commitment_signed {
2289-
funded_channel
2290-
.splice_initial_commitment_signed(msg, fee_estimator, logger)
2291-
.map(|monitor_update_opt| (None, monitor_update_opt))
2296+
// We delay processing this until the user manually approves the splice via
2297+
// [`Channel::funding_transaction_signed`], as otherwise, there would be a
2298+
// [`ChannelMonitorUpdateStep::RenegotiatedFunding`] committed that we would
2299+
// need to undo if they no longer wish to proceed.
2300+
if has_holder_tx_signatures {
2301+
funded_channel
2302+
.splice_initial_commitment_signed(msg, fee_estimator, logger)
2303+
.map(|monitor_update_opt| (None, monitor_update_opt))
2304+
} else {
2305+
let pending_splice = funded_channel.pending_splice.as_mut()
2306+
.expect("We have a pending splice negotiated");
2307+
let funding_negotiation = pending_splice.funding_negotiation.as_mut()
2308+
.expect("We have a pending splice negotiated");
2309+
if let FundingNegotiation::AwaitingSignatures {
2310+
ref mut initial_commit_sig_from_counterparty, ..
2311+
} = funding_negotiation {
2312+
*initial_commit_sig_from_counterparty = Some(msg.clone());
2313+
}
2314+
Ok((None, None))
2315+
}
22922316
} else {
22932317
funded_channel.commitment_signed(msg, fee_estimator, logger)
22942318
.map(|monitor_update_opt| (None, monitor_update_opt))
@@ -2772,13 +2796,25 @@ enum FundingNegotiation {
27722796
AwaitingSignatures {
27732797
funding: FundingScope,
27742798
is_initiator: bool,
2799+
/// The initial `commitment_signed` message received for the [`FundingScope`] above. We
2800+
/// delay processing this until the user manually approves the splice via
2801+
/// [`Channel::funding_transaction_signed`], as otherwise, there would be a
2802+
/// [`ChannelMonitorUpdateStep::RenegotiatedFunding`] committed that we would need to undo
2803+
/// if they no longer wish to proceed.
2804+
///
2805+
/// Note that this doesn't need to be done with dual-funded channels as there is no
2806+
/// equivalent monitor update for them.
2807+
///
2808+
/// This field is not persisted as the message should be resent on reconnections.
2809+
initial_commit_sig_from_counterparty: Option<msgs::CommitmentSigned>,
27752810
},
27762811
}
27772812

27782813
impl_writeable_tlv_based_enum_upgradable!(FundingNegotiation,
27792814
(0, AwaitingSignatures) => {
27802815
(1, funding, required),
27812816
(3, is_initiator, required),
2817+
(_unused, initial_commit_sig_from_counterparty, (static_value, None)),
27822818
},
27832819
unread_variants: AwaitingAck, ConstructingTransaction
27842820
);
@@ -7033,16 +7069,16 @@ where
70337069

70347070
pub(crate) fn maybe_handle_funding_transaction_signed_post_action<F: Deref, L: Deref>(
70357071
&mut self, fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &L,
7036-
) -> Result<Option<msgs::CommitmentSigned>, ChannelError>
7072+
) -> Result<(Option<msgs::CommitmentSigned>, Option<ChannelMonitorUpdate>), ChannelError>
70377073
where
70387074
F::Target: FeeEstimator,
70397075
L::Target: Logger,
70407076
{
70417077
let Some(signing_session) = self.context.interactive_tx_signing_session.as_ref() else {
7042-
return Ok(None);
7078+
return Ok((None, None));
70437079
};
70447080
if signing_session.holder_tx_signatures().is_none() {
7045-
return Ok(None);
7081+
return Ok((None, None));
70467082
}
70477083

70487084
let mut commit_sig = None;
@@ -7065,7 +7101,27 @@ where
70657101
}
70667102
}
70677103

7068-
Ok(commit_sig)
7104+
let mut monitor_update = None;
7105+
if let Some(initial_commit_sig) = self
7106+
.pending_splice
7107+
.as_mut()
7108+
.and_then(|pending_splice| pending_splice.funding_negotiation.as_mut())
7109+
.and_then(|funding_negotiation| {
7110+
if let FundingNegotiation::AwaitingSignatures {
7111+
ref mut initial_commit_sig_from_counterparty,
7112+
..
7113+
} = funding_negotiation
7114+
{
7115+
initial_commit_sig_from_counterparty.take()
7116+
} else {
7117+
None
7118+
}
7119+
}) {
7120+
monitor_update =
7121+
self.splice_initial_commitment_signed(&initial_commit_sig, fee_estimator, logger)?;
7122+
}
7123+
7124+
Ok((commit_sig, monitor_update))
70697125
}
70707126

70717127
fn maybe_fail_splice_negotiation(&mut self) -> Option<SpliceFundingFailed> {

lightning/src/ln/channelmanager.rs

Lines changed: 65 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -12637,57 +12637,77 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1263712637
let mut handle_errors: Vec<(PublicKey, ChannelId, Result<(), MsgHandleErrInternal>)> =
1263812638
Vec::new();
1263912639

12640-
let per_peer_state = self.per_peer_state.read().unwrap();
12641-
for (counterparty_node_id, peer_state_mutex) in per_peer_state.iter() {
12642-
let mut peer_state_lock = peer_state_mutex.lock().unwrap();
12643-
let peer_state = &mut *peer_state_lock;
12644-
let pending_msg_events = &mut peer_state.pending_msg_events;
12645-
for (channel_id, chan) in &mut peer_state.channel_by_id {
12646-
if let Some(funded_chan) = chan.as_funded_mut() {
12647-
let logger = WithChannelContext::from(&self.logger, &funded_chan.context, None);
12648-
match funded_chan.maybe_handle_funding_transaction_signed_post_action(
12649-
&self.fee_estimator,
12650-
&&logger,
12651-
) {
12652-
Ok(commit_sig) => {
12653-
if let Some(commit_sig) = commit_sig {
12654-
pending_msg_events.push(MessageSendEvent::UpdateHTLCs {
12655-
node_id: *counterparty_node_id,
12656-
channel_id: *channel_id,
12657-
updates: CommitmentUpdate {
12658-
update_add_htlcs: vec![],
12659-
update_fulfill_htlcs: vec![],
12660-
update_fail_htlcs: vec![],
12661-
update_fail_malformed_htlcs: vec![],
12662-
update_fee: None,
12663-
commitment_signed: vec![commit_sig],
12664-
},
12665-
});
12666-
}
12667-
},
12668-
Err(e) => {
12669-
let (_, err) = self.locked_handle_funded_force_close(
12670-
&mut peer_state.closed_channel_monitor_update_ids,
12671-
&mut peer_state.in_flight_monitor_updates,
12672-
e,
12673-
funded_chan,
12674-
);
12675-
handle_errors.push((*counterparty_node_id, *channel_id, Err(err)));
12676-
has_update = true;
12677-
},
12640+
// Handling a monitor update requires dropping peer state locks, so we use the labeled loop
12641+
// as a goto statement.
12642+
'peer_loop: loop {
12643+
let per_peer_state = self.per_peer_state.read().unwrap();
12644+
for (counterparty_node_id, peer_state_mutex) in per_peer_state.iter() {
12645+
let mut peer_state_lock = peer_state_mutex.lock().unwrap();
12646+
let peer_state = &mut *peer_state_lock;
12647+
let pending_msg_events = &mut peer_state.pending_msg_events;
12648+
for (channel_id, chan) in &mut peer_state.channel_by_id {
12649+
if let Some(funded_chan) = chan.as_funded_mut() {
12650+
let logger =
12651+
WithChannelContext::from(&self.logger, &funded_chan.context, None);
12652+
match funded_chan.maybe_handle_funding_transaction_signed_post_action(
12653+
&self.fee_estimator,
12654+
&&logger,
12655+
) {
12656+
Ok((commit_sig, monitor_update)) => {
12657+
if let Some(commit_sig) = commit_sig {
12658+
pending_msg_events.push(MessageSendEvent::UpdateHTLCs {
12659+
node_id: *counterparty_node_id,
12660+
channel_id: *channel_id,
12661+
updates: CommitmentUpdate {
12662+
update_add_htlcs: vec![],
12663+
update_fulfill_htlcs: vec![],
12664+
update_fail_htlcs: vec![],
12665+
update_fail_malformed_htlcs: vec![],
12666+
update_fee: None,
12667+
commitment_signed: vec![commit_sig],
12668+
},
12669+
});
12670+
}
12671+
12672+
if let Some(monitor_update) = monitor_update {
12673+
handle_new_monitor_update!(
12674+
self,
12675+
funded_chan.funding_outpoint(),
12676+
monitor_update,
12677+
peer_state_lock,
12678+
peer_state,
12679+
per_peer_state,
12680+
funded_chan
12681+
);
12682+
has_update = true;
12683+
continue 'peer_loop;
12684+
}
12685+
},
12686+
Err(e) => {
12687+
let (_, err) = self.locked_handle_funded_force_close(
12688+
&mut peer_state.closed_channel_monitor_update_ids,
12689+
&mut peer_state.in_flight_monitor_updates,
12690+
e,
12691+
funded_chan,
12692+
);
12693+
handle_errors.push((*counterparty_node_id, *channel_id, Err(err)));
12694+
has_update = true;
12695+
},
12696+
}
1267812697
}
1267912698
}
12680-
}
1268112699

12682-
for (cp_node_id, channel_id, _) in &handle_errors {
12683-
if cp_node_id == counterparty_node_id {
12684-
peer_state.channel_by_id.remove_entry(channel_id);
12700+
for (cp_node_id, channel_id, _) in &handle_errors {
12701+
if cp_node_id == counterparty_node_id {
12702+
peer_state.channel_by_id.remove_entry(channel_id);
12703+
}
1268512704
}
1268612705
}
12687-
}
1268812706

12689-
for (counterparty_node_id, _, err) in handle_errors {
12690-
let _ = self.handle_error(err, counterparty_node_id);
12707+
for (counterparty_node_id, _, err) in handle_errors {
12708+
let _ = self.handle_error(err, counterparty_node_id);
12709+
}
12710+
break;
1269112711
}
1269212712

1269312713
has_update

0 commit comments

Comments
 (0)