Skip to content

Commit 60a87ab

Browse files
committed
Emit SpliceFailed upon disconnect while quiescent
Since quiescence is terminated upon disconnection, any outstanding splice negotiation should result in emitting a SpliceFailed event as long as we haven't reached FundingNegotiation::AwaitingSignatures. This may occur if we explicitly disconnect the peer (e.g., when failing to process splice_ack) or if the connection is lost.
1 parent d82abc2 commit 60a87ab

File tree

3 files changed

+229
-175
lines changed

3 files changed

+229
-175
lines changed

lightning/src/ln/channel.rs

Lines changed: 101 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1196,6 +1196,14 @@ pub(crate) struct ShutdownResult {
11961196
pub(crate) splice_funding_failed: Option<SpliceFundingFailed>,
11971197
}
11981198

1199+
/// The result of a peer disconnection.
1200+
pub(crate) struct DisconnectResult {
1201+
pub(crate) is_resumable: bool,
1202+
/// If a splice was in progress when the channel was shut down, this contains
1203+
/// the splice funding information for emitting a SpliceFailed event.
1204+
pub(crate) splice_funding_failed: Option<SpliceFundingFailed>,
1205+
}
1206+
11991207
/// Tracks the transaction number, along with current and next commitment points.
12001208
/// This consolidates the logic to advance our commitment number and request new
12011209
/// commitment points from our signer.
@@ -1588,11 +1596,15 @@ where
15881596
/// Should be called when the peer is disconnected. Returns true if the channel can be resumed
15891597
/// when the peer reconnects (via [`Self::peer_connected_get_handshake`]). If not, the channel
15901598
/// must be immediately closed.
1591-
#[rustfmt::skip]
1592-
pub fn peer_disconnected_is_resumable<L: Deref>(&mut self, logger: &L) -> bool where L::Target: Logger {
1593-
match &mut self.phase {
1599+
pub fn peer_disconnected_is_resumable<L: Deref>(&mut self, logger: &L) -> DisconnectResult
1600+
where
1601+
L::Target: Logger,
1602+
{
1603+
let is_resumable = match &mut self.phase {
15941604
ChannelPhase::Undefined => unreachable!(),
1595-
ChannelPhase::Funded(chan) => chan.remove_uncommitted_htlcs_and_mark_paused(logger).is_ok(),
1605+
ChannelPhase::Funded(chan) => {
1606+
chan.remove_uncommitted_htlcs_and_mark_paused(logger).is_ok()
1607+
},
15961608
// If we get disconnected and haven't yet committed to a funding
15971609
// transaction, we can replay the `open_channel` on reconnection, so don't
15981610
// bother dropping the channel here. However, if we already committed to
@@ -1602,7 +1614,40 @@ where
16021614
ChannelPhase::UnfundedOutboundV1(chan) => chan.is_resumable(),
16031615
ChannelPhase::UnfundedInboundV1(_) => false,
16041616
ChannelPhase::UnfundedV2(_) => false,
1605-
}
1617+
};
1618+
1619+
let splice_funding_failed = if let ChannelPhase::Funded(chan) = &mut self.phase {
1620+
// Reset any quiescence-related state as it is implicitly terminated once disconnected.
1621+
if matches!(chan.context.channel_state, ChannelState::ChannelReady(_)) {
1622+
if chan.quiescent_action.is_some() {
1623+
// If we were trying to get quiescent, try again after reconnection.
1624+
chan.context.channel_state.set_awaiting_quiescence();
1625+
}
1626+
chan.context.channel_state.clear_local_stfu_sent();
1627+
chan.context.channel_state.clear_remote_stfu_sent();
1628+
if chan.should_reset_pending_splice_state() {
1629+
// If there was a pending splice negotiation that failed due to disconnecting, we
1630+
// also take the opportunity to clean up our state.
1631+
let splice_funding_failed = chan.reset_pending_splice_state();
1632+
debug_assert!(!chan.context.channel_state.is_quiescent());
1633+
splice_funding_failed
1634+
} else if !chan.has_pending_splice_awaiting_signatures() {
1635+
// We shouldn't be quiescent anymore upon reconnecting if:
1636+
// - We were in quiescence but a splice/RBF was never negotiated or
1637+
// - We were in quiescence but the splice negotiation failed due to disconnecting
1638+
chan.context.channel_state.clear_quiescent();
1639+
None
1640+
} else {
1641+
None
1642+
}
1643+
} else {
1644+
None
1645+
}
1646+
} else {
1647+
None
1648+
};
1649+
1650+
DisconnectResult { is_resumable, splice_funding_failed }
16061651
}
16071652

16081653
/// Should be called when the peer re-connects, returning an initial message which we should
@@ -6837,40 +6882,43 @@ where
68376882
}
68386883

68396884
pub fn force_shutdown(&mut self, closure_reason: ClosureReason) -> ShutdownResult {
6840-
let splice_funding_failed =
6841-
if matches!(self.context.channel_state, ChannelState::ChannelReady(_)) {
6842-
if self.should_reset_pending_splice_state() {
6843-
self.reset_pending_splice_state()
6844-
} else {
6845-
match self.quiescent_action.take() {
6846-
Some(QuiescentAction::Splice(instructions)) => {
6847-
self.context.channel_state.clear_awaiting_quiescence();
6848-
let (inputs, outputs) =
6849-
instructions.into_contributed_inputs_and_outputs();
6850-
Some(SpliceFundingFailed {
6851-
funding_txo: None,
6852-
channel_type: None,
6853-
contributed_inputs: inputs,
6854-
contributed_outputs: outputs,
6855-
})
6856-
},
6857-
#[cfg(any(test, fuzzing))]
6858-
Some(quiescent_action) => {
6859-
self.quiescent_action = Some(quiescent_action);
6860-
None
6861-
},
6862-
None => None,
6863-
}
6864-
}
6865-
} else {
6866-
None
6867-
};
6885+
let splice_funding_failed = self.maybe_fail_splice_negotiation();
68686886

68696887
let mut shutdown_result = self.context.force_shutdown(&self.funding, closure_reason);
68706888
shutdown_result.splice_funding_failed = splice_funding_failed;
68716889
shutdown_result
68726890
}
68736891

6892+
fn maybe_fail_splice_negotiation(&mut self) -> Option<SpliceFundingFailed> {
6893+
if matches!(self.context.channel_state, ChannelState::ChannelReady(_)) {
6894+
if self.should_reset_pending_splice_state() {
6895+
self.reset_pending_splice_state()
6896+
} else {
6897+
match self.quiescent_action.take() {
6898+
Some(QuiescentAction::Splice(instructions)) => {
6899+
self.context.channel_state.clear_awaiting_quiescence();
6900+
let (inputs, outputs) =
6901+
instructions.into_contributed_inputs_and_outputs();
6902+
Some(SpliceFundingFailed {
6903+
funding_txo: None,
6904+
channel_type: None,
6905+
contributed_inputs: inputs,
6906+
contributed_outputs: outputs,
6907+
})
6908+
},
6909+
#[cfg(any(test, fuzzing))]
6910+
Some(quiescent_action) => {
6911+
self.quiescent_action = Some(quiescent_action);
6912+
None
6913+
},
6914+
None => None,
6915+
}
6916+
}
6917+
} else {
6918+
None
6919+
}
6920+
}
6921+
68746922
fn interactive_tx_constructor_mut(&mut self) -> Option<&mut InteractiveTxConstructor> {
68756923
self.pending_splice
68766924
.as_mut()
@@ -9130,27 +9178,6 @@ where
91309178
}
91319179
}
91329180

9133-
// Reset any quiescence-related state as it is implicitly terminated once disconnected.
9134-
if matches!(self.context.channel_state, ChannelState::ChannelReady(_)) {
9135-
if self.quiescent_action.is_some() {
9136-
// If we were trying to get quiescent, try again after reconnection.
9137-
self.context.channel_state.set_awaiting_quiescence();
9138-
}
9139-
self.context.channel_state.clear_local_stfu_sent();
9140-
self.context.channel_state.clear_remote_stfu_sent();
9141-
if self.should_reset_pending_splice_state() {
9142-
// If there was a pending splice negotiation that failed due to disconnecting, we
9143-
// also take the opportunity to clean up our state.
9144-
self.reset_pending_splice_state();
9145-
debug_assert!(!self.context.channel_state.is_quiescent());
9146-
} else if !self.has_pending_splice_awaiting_signatures() {
9147-
// We shouldn't be quiescent anymore upon reconnecting if:
9148-
// - We were in quiescence but a splice/RBF was never negotiated or
9149-
// - We were in quiescence but the splice negotiation failed due to disconnecting
9150-
self.context.channel_state.clear_quiescent();
9151-
}
9152-
}
9153-
91549181
self.context.channel_state.set_peer_disconnected();
91559182
log_trace!(logger, "Peer disconnection resulted in {} remote-announced HTLC drops on channel {}", inbound_drop_count, &self.context.channel_id());
91569183
Ok(())
@@ -11823,9 +11850,9 @@ where
1182311850
.map_err(|e| APIError::APIMisuseError { err: e.to_owned() })
1182411851
}
1182511852

11826-
fn send_splice_init(
11827-
&mut self, instructions: SpliceInstructions,
11828-
) -> Result<msgs::SpliceInit, String> {
11853+
fn send_splice_init(&mut self, instructions: SpliceInstructions) -> msgs::SpliceInit {
11854+
debug_assert!(self.pending_splice.is_none());
11855+
1182911856
let SpliceInstructions {
1183011857
adjusted_funding_contribution,
1183111858
our_funding_inputs,
@@ -11835,15 +11862,6 @@ where
1183511862
locktime,
1183611863
} = instructions;
1183711864

11838-
// Check if a splice has been initiated already.
11839-
// Note: only a single outstanding splice is supported (per spec)
11840-
if self.pending_splice.is_some() {
11841-
return Err(format!(
11842-
"Channel {} cannot be spliced, as it has already a splice pending",
11843-
self.context.channel_id(),
11844-
));
11845-
}
11846-
1184711865
let prev_funding_input = self.funding.to_splice_funding_input();
1184811866
let context = FundingNegotiationContext {
1184911867
is_initiator: true,
@@ -11867,14 +11885,14 @@ where
1186711885
let prev_funding_txid = self.funding.get_funding_txid();
1186811886
let funding_pubkey = self.context.holder_pubkeys(prev_funding_txid).funding_pubkey;
1186911887

11870-
Ok(msgs::SpliceInit {
11888+
msgs::SpliceInit {
1187111889
channel_id: self.context.channel_id,
1187211890
funding_contribution_satoshis: adjusted_funding_contribution.to_sat(),
1187311891
funding_feerate_per_kw,
1187411892
locktime,
1187511893
funding_pubkey,
1187611894
require_confirmed_inputs: None,
11877-
})
11895+
}
1187811896
}
1187911897

1188011898
#[cfg(test)]
@@ -13045,10 +13063,21 @@ where
1304513063
"Internal Error: Didn't have anything to do after reaching quiescence".to_owned()
1304613064
));
1304713065
},
13048-
Some(QuiescentAction::Splice(_instructions)) => {
13049-
return self.send_splice_init(_instructions)
13050-
.map(|splice_init| Some(StfuResponse::SpliceInit(splice_init)))
13051-
.map_err(|e| ChannelError::WarnAndDisconnect(e.to_owned()));
13066+
Some(QuiescentAction::Splice(instructions)) => {
13067+
if self.pending_splice.is_some() {
13068+
debug_assert!(false);
13069+
self.quiescent_action = Some(QuiescentAction::Splice(instructions));
13070+
13071+
return Err(ChannelError::WarnAndDisconnect(
13072+
format!(
13073+
"Channel {} cannot be spliced as it already has a splice pending",
13074+
self.context.channel_id(),
13075+
),
13076+
));
13077+
}
13078+
13079+
let splice_init = self.send_splice_init(instructions);
13080+
return Ok(Some(StfuResponse::SpliceInit(splice_init)));
1305213081
},
1305313082
#[cfg(any(test, fuzzing))]
1305413083
Some(QuiescentAction::DoNothing) => {

0 commit comments

Comments
 (0)