Skip to content

Commit 245bd15

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 a4c3461 commit 245bd15

File tree

3 files changed

+219
-170
lines changed

3 files changed

+219
-170
lines changed

lightning/src/ln/channel.rs

Lines changed: 91 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1193,6 +1193,14 @@ pub(crate) struct ShutdownResult {
11931193
pub(crate) splice_funding_failed: Option<SpliceFundingFailed>,
11941194
}
11951195

1196+
/// The result of a peer disconnection.
1197+
pub(crate) struct DisconnectResult {
1198+
pub(crate) is_resumable: bool,
1199+
/// If a splice was in progress when the channel was shut down, this contains
1200+
/// the splice funding information for emitting a SpliceFailed event.
1201+
pub(crate) splice_funding_failed: Option<SpliceFundingFailed>,
1202+
}
1203+
11961204
/// Tracks the transaction number, along with current and next commitment points.
11971205
/// This consolidates the logic to advance our commitment number and request new
11981206
/// commitment points from our signer.
@@ -1585,11 +1593,15 @@ where
15851593
/// Should be called when the peer is disconnected. Returns true if the channel can be resumed
15861594
/// when the peer reconnects (via [`Self::peer_connected_get_handshake`]). If not, the channel
15871595
/// must be immediately closed.
1588-
#[rustfmt::skip]
1589-
pub fn peer_disconnected_is_resumable<L: Deref>(&mut self, logger: &L) -> bool where L::Target: Logger {
1590-
match &mut self.phase {
1596+
pub fn peer_disconnected_is_resumable<L: Deref>(&mut self, logger: &L) -> DisconnectResult
1597+
where
1598+
L::Target: Logger,
1599+
{
1600+
let is_resumable = match &mut self.phase {
15911601
ChannelPhase::Undefined => unreachable!(),
1592-
ChannelPhase::Funded(chan) => chan.remove_uncommitted_htlcs_and_mark_paused(logger).is_ok(),
1602+
ChannelPhase::Funded(chan) => {
1603+
chan.remove_uncommitted_htlcs_and_mark_paused(logger).is_ok()
1604+
},
15931605
// If we get disconnected and haven't yet committed to a funding
15941606
// transaction, we can replay the `open_channel` on reconnection, so don't
15951607
// bother dropping the channel here. However, if we already committed to
@@ -1599,7 +1611,34 @@ where
15991611
ChannelPhase::UnfundedOutboundV1(chan) => chan.is_resumable(),
16001612
ChannelPhase::UnfundedInboundV1(_) => false,
16011613
ChannelPhase::UnfundedV2(_) => false,
1602-
}
1614+
};
1615+
1616+
let splice_funding_failed = if let ChannelPhase::Funded(chan) = &mut self.phase {
1617+
// Reset any quiescence-related state as it is implicitly terminated once disconnected.
1618+
if matches!(chan.context.channel_state, ChannelState::ChannelReady(_)) {
1619+
if chan.quiescent_action.is_some() {
1620+
// If we were trying to get quiescent, try again after reconnection.
1621+
chan.context.channel_state.set_awaiting_quiescence();
1622+
}
1623+
chan.context.channel_state.clear_local_stfu_sent();
1624+
chan.context.channel_state.clear_remote_stfu_sent();
1625+
if chan.should_reset_pending_splice_funding_negotiation().unwrap_or(true) {
1626+
// If we were in quiescence but a splice was never negotiated, or the negotiation
1627+
// failed due to disconnecting, we shouldn't be quiescent anymore upon reconnecting.
1628+
// If there was a pending splice negotiation that has failed due to disconnecting,
1629+
// we also take the opportunity to clean up our state.
1630+
chan.reset_pending_splice_state()
1631+
} else {
1632+
None
1633+
}
1634+
} else {
1635+
None
1636+
}
1637+
} else {
1638+
None
1639+
};
1640+
1641+
DisconnectResult { is_resumable, splice_funding_failed }
16031642
}
16041643

16051644
/// Should be called when the peer re-connects, returning an initial message which we should
@@ -6818,38 +6857,39 @@ where
68186857
}
68196858

68206859
pub fn force_shutdown(&mut self, closure_reason: ClosureReason) -> ShutdownResult {
6821-
let splice_funding_failed =
6822-
if matches!(self.context.channel_state, ChannelState::ChannelReady(_)) {
6823-
self.reset_pending_splice_state().or_else(|| {
6824-
self.quiescent_action.take().and_then(|quiescent_action| match quiescent_action
6825-
{
6826-
QuiescentAction::Splice(instructions) => {
6827-
self.context.channel_state.clear_awaiting_quiescence();
6828-
let (inputs, outputs) =
6829-
instructions.into_contributed_inputs_and_outputs();
6830-
Some(SpliceFundingFailed {
6831-
funding_txo: None,
6832-
channel_type: None,
6833-
contributed_inputs: inputs,
6834-
contributed_outputs: outputs,
6835-
})
6836-
},
6837-
#[cfg(any(test, fuzzing))]
6838-
_ => {
6839-
self.quiescent_action = Some(quiescent_action);
6840-
None
6841-
},
6842-
})
6843-
})
6844-
} else {
6845-
None
6846-
};
6860+
let splice_funding_failed = self.maybe_fail_splice_negotiation();
68476861

68486862
let mut shutdown_result = self.context.force_shutdown(&self.funding, closure_reason);
68496863
shutdown_result.splice_funding_failed = splice_funding_failed;
68506864
shutdown_result
68516865
}
68526866

6867+
fn maybe_fail_splice_negotiation(&mut self) -> Option<SpliceFundingFailed> {
6868+
if matches!(self.context.channel_state, ChannelState::ChannelReady(_)) {
6869+
self.reset_pending_splice_state().or_else(|| {
6870+
self.quiescent_action.take().and_then(|quiescent_action| match quiescent_action {
6871+
QuiescentAction::Splice(instructions) => {
6872+
self.context.channel_state.clear_awaiting_quiescence();
6873+
let (inputs, outputs) = instructions.into_contributed_inputs_and_outputs();
6874+
Some(SpliceFundingFailed {
6875+
funding_txo: None,
6876+
channel_type: None,
6877+
contributed_inputs: inputs,
6878+
contributed_outputs: outputs,
6879+
})
6880+
},
6881+
#[cfg(any(test, fuzzing))]
6882+
_ => {
6883+
self.quiescent_action = Some(quiescent_action);
6884+
None
6885+
},
6886+
})
6887+
})
6888+
} else {
6889+
None
6890+
}
6891+
}
6892+
68536893
fn interactive_tx_constructor_mut(&mut self) -> Option<&mut InteractiveTxConstructor> {
68546894
self.pending_splice
68556895
.as_mut()
@@ -9100,24 +9140,6 @@ where
91009140
}
91019141
}
91029142

9103-
// Reset any quiescence-related state as it is implicitly terminated once disconnected.
9104-
if matches!(self.context.channel_state, ChannelState::ChannelReady(_)) {
9105-
if self.quiescent_action.is_some() {
9106-
// If we were trying to get quiescent, try again after reconnection.
9107-
self.context.channel_state.set_awaiting_quiescence();
9108-
}
9109-
self.context.channel_state.clear_local_stfu_sent();
9110-
self.context.channel_state.clear_remote_stfu_sent();
9111-
if self.should_reset_pending_splice_funding_negotiation().unwrap_or(true) {
9112-
// If we were in quiescence but a splice was never negotiated, or the negotiation
9113-
// failed due to disconnecting, we shouldn't be quiescent anymore upon reconnecting.
9114-
// If there was a pending splice negotiation that has failed due to disconnecting,
9115-
// we also take the opportunity to clean up our state.
9116-
self.reset_pending_splice_state();
9117-
debug_assert!(!self.context.channel_state.is_quiescent());
9118-
}
9119-
}
9120-
91219143
self.context.channel_state.set_peer_disconnected();
91229144
log_trace!(logger, "Peer disconnection resulted in {} remote-announced HTLC drops on channel {}", inbound_drop_count, &self.context.channel_id());
91239145
Ok(())
@@ -11784,9 +11806,9 @@ where
1178411806
.map_err(|e| APIError::APIMisuseError { err: e.to_owned() })
1178511807
}
1178611808

11787-
fn send_splice_init(
11788-
&mut self, instructions: SpliceInstructions,
11789-
) -> Result<msgs::SpliceInit, String> {
11809+
fn send_splice_init(&mut self, instructions: SpliceInstructions) -> msgs::SpliceInit {
11810+
debug_assert!(self.pending_splice.is_none());
11811+
1179011812
let SpliceInstructions {
1179111813
adjusted_funding_contribution,
1179211814
our_funding_inputs,
@@ -11796,15 +11818,6 @@ where
1179611818
locktime,
1179711819
} = instructions;
1179811820

11799-
// Check if a splice has been initiated already.
11800-
// Note: only a single outstanding splice is supported (per spec)
11801-
if self.pending_splice.is_some() {
11802-
return Err(format!(
11803-
"Channel {} cannot be spliced, as it has already a splice pending",
11804-
self.context.channel_id(),
11805-
));
11806-
}
11807-
1180811821
let prev_funding_input = self.funding.to_splice_funding_input();
1180911822
let context = FundingNegotiationContext {
1181011823
is_initiator: true,
@@ -11828,14 +11841,14 @@ where
1182811841
let prev_funding_txid = self.funding.get_funding_txid();
1182911842
let funding_pubkey = self.context.holder_pubkeys(prev_funding_txid).funding_pubkey;
1183011843

11831-
Ok(msgs::SpliceInit {
11844+
msgs::SpliceInit {
1183211845
channel_id: self.context.channel_id,
1183311846
funding_contribution_satoshis: adjusted_funding_contribution.to_sat(),
1183411847
funding_feerate_per_kw,
1183511848
locktime,
1183611849
funding_pubkey,
1183711850
require_confirmed_inputs: None,
11838-
})
11851+
}
1183911852
}
1184011853

1184111854
#[cfg(test)]
@@ -13006,10 +13019,21 @@ where
1300613019
"Internal Error: Didn't have anything to do after reaching quiescence".to_owned()
1300713020
));
1300813021
},
13009-
Some(QuiescentAction::Splice(_instructions)) => {
13010-
return self.send_splice_init(_instructions)
13011-
.map(|splice_init| Some(StfuResponse::SpliceInit(splice_init)))
13012-
.map_err(|e| ChannelError::WarnAndDisconnect(e.to_owned()));
13022+
Some(QuiescentAction::Splice(instructions)) => {
13023+
if self.pending_splice.is_some() {
13024+
debug_assert!(false);
13025+
self.quiescent_action = Some(QuiescentAction::Splice(instructions));
13026+
13027+
return Err(ChannelError::WarnAndDisconnect(
13028+
format!(
13029+
"Channel {} cannot be spliced as it already has a splice pending",
13030+
self.context.channel_id(),
13031+
),
13032+
));
13033+
}
13034+
13035+
let splice_init = self.send_splice_init(instructions);
13036+
return Ok(Some(StfuResponse::SpliceInit(splice_init)));
1301313037
},
1301413038
#[cfg(any(test, fuzzing))]
1301513039
Some(QuiescentAction::DoNothing) => {

0 commit comments

Comments
 (0)