Skip to content

Commit 1165217

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 400f795 commit 1165217

File tree

3 files changed

+122
-72
lines changed

3 files changed

+122
-72
lines changed

lightning/src/ln/channel.rs

Lines changed: 90 additions & 66 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
@@ -6808,37 +6847,38 @@ where
68086847
}
68096848

68106849
pub fn force_shutdown(&mut self, closure_reason: ClosureReason) -> ShutdownResult {
6811-
let splice_funding_failed =
6812-
if matches!(self.context.channel_state, ChannelState::ChannelReady(_)) {
6813-
self.reset_pending_splice_state().or_else(|| {
6814-
self.quiescent_action.take().and_then(|quiescent_action| match quiescent_action
6815-
{
6816-
QuiescentAction::Splice(instructions) => {
6817-
let (inputs, outputs) =
6818-
instructions.into_contributed_inputs_and_outputs();
6819-
Some(SpliceFundingFailed {
6820-
funding_txo: None,
6821-
channel_type: None,
6822-
contributed_inputs: inputs,
6823-
contributed_outputs: outputs,
6824-
})
6825-
},
6826-
#[cfg(any(test, fuzzing))]
6827-
_ => {
6828-
self.quiescent_action = Some(quiescent_action);
6829-
None
6830-
},
6831-
})
6832-
})
6833-
} else {
6834-
None
6835-
};
6850+
let splice_funding_failed = self.maybe_fail_splice_negotiation();
68366851

68376852
let mut shutdown_result = self.context.force_shutdown(&self.funding, closure_reason);
68386853
shutdown_result.splice_funding_failed = splice_funding_failed;
68396854
shutdown_result
68406855
}
68416856

6857+
fn maybe_fail_splice_negotiation(&mut self) -> Option<SpliceFundingFailed> {
6858+
if matches!(self.context.channel_state, ChannelState::ChannelReady(_)) {
6859+
self.reset_pending_splice_state().or_else(|| {
6860+
self.quiescent_action.take().and_then(|quiescent_action| match quiescent_action {
6861+
QuiescentAction::Splice(instructions) => {
6862+
let (inputs, outputs) = instructions.into_contributed_inputs_and_outputs();
6863+
Some(SpliceFundingFailed {
6864+
funding_txo: None,
6865+
channel_type: None,
6866+
contributed_inputs: inputs,
6867+
contributed_outputs: outputs,
6868+
})
6869+
},
6870+
#[cfg(any(test, fuzzing))]
6871+
_ => {
6872+
self.quiescent_action = Some(quiescent_action);
6873+
None
6874+
},
6875+
})
6876+
})
6877+
} else {
6878+
None
6879+
}
6880+
}
6881+
68426882
fn interactive_tx_constructor_mut(&mut self) -> Option<&mut InteractiveTxConstructor> {
68436883
self.pending_splice
68446884
.as_mut()
@@ -9095,24 +9135,6 @@ where
90959135
}
90969136
}
90979137

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

11782-
fn send_splice_init(
11783-
&mut self, instructions: SpliceInstructions,
11784-
) -> Result<msgs::SpliceInit, String> {
11804+
fn send_splice_init(&mut self, instructions: SpliceInstructions) -> msgs::SpliceInit {
11805+
debug_assert!(self.pending_splice.is_none());
11806+
1178511807
let SpliceInstructions {
1178611808
adjusted_funding_contribution,
1178711809
our_funding_inputs,
@@ -11791,15 +11813,6 @@ where
1179111813
locktime,
1179211814
} = instructions;
1179311815

11794-
// Check if a splice has been initiated already.
11795-
// Note: only a single outstanding splice is supported (per spec)
11796-
if self.pending_splice.is_some() {
11797-
return Err(format!(
11798-
"Channel {} cannot be spliced, as it has already a splice pending",
11799-
self.context.channel_id(),
11800-
));
11801-
}
11802-
1180311816
let prev_funding_input = self.funding.to_splice_funding_input();
1180411817
let context = FundingNegotiationContext {
1180511818
is_initiator: true,
@@ -11823,14 +11836,14 @@ where
1182311836
let prev_funding_txid = self.funding.get_funding_txid();
1182411837
let funding_pubkey = self.context.holder_pubkeys(prev_funding_txid).funding_pubkey;
1182511838

11826-
Ok(msgs::SpliceInit {
11839+
msgs::SpliceInit {
1182711840
channel_id: self.context.channel_id,
1182811841
funding_contribution_satoshis: adjusted_funding_contribution.to_sat(),
1182911842
funding_feerate_per_kw,
1183011843
locktime,
1183111844
funding_pubkey,
1183211845
require_confirmed_inputs: None,
11833-
})
11846+
}
1183411847
}
1183511848

1183611849
/// Checks during handling splice_init
@@ -12975,10 +12988,21 @@ where
1297512988
"Internal Error: Didn't have anything to do after reaching quiescence".to_owned()
1297612989
));
1297712990
},
12978-
Some(QuiescentAction::Splice(_instructions)) => {
12979-
return self.send_splice_init(_instructions)
12980-
.map(|splice_init| Some(StfuResponse::SpliceInit(splice_init)))
12981-
.map_err(|e| ChannelError::WarnAndDisconnect(e.to_owned()));
12991+
Some(QuiescentAction::Splice(instructions)) => {
12992+
if self.pending_splice.is_some() {
12993+
debug_assert!(false);
12994+
self.quiescent_action = Some(QuiescentAction::Splice(instructions));
12995+
12996+
return Err(ChannelError::WarnAndDisconnect(
12997+
format!(
12998+
"Channel {} cannot be spliced as it already has a splice pending",
12999+
self.context.channel_id(),
13000+
),
13001+
));
13002+
}
13003+
13004+
let splice_init = self.send_splice_init(instructions);
13005+
return Ok(Some(StfuResponse::SpliceInit(splice_init)));
1298213006
},
1298313007
#[cfg(any(test, fuzzing))]
1298413008
Some(QuiescentAction::DoNothing) => {

lightning/src/ln/channelmanager.rs

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,10 @@ use crate::ln::chan_utils::selected_commitment_sat_per_1000_weight;
5959
#[cfg(any(test, fuzzing))]
6060
use crate::ln::channel::QuiescentAction;
6161
use crate::ln::channel::{
62-
self, hold_time_since, Channel, ChannelError, ChannelUpdateStatus, FundedChannel,
63-
InboundV1Channel, OutboundV1Channel, PendingV2Channel, ReconnectionMsg, ShutdownResult,
64-
SpliceFundingFailed, StfuResponse, UpdateFulfillCommitFetch, WithChannelContext,
62+
self, hold_time_since, Channel, ChannelError, ChannelUpdateStatus, DisconnectResult,
63+
FundedChannel, InboundV1Channel, OutboundV1Channel, PendingV2Channel, ReconnectionMsg,
64+
ShutdownResult, SpliceFundingFailed, StfuResponse, UpdateFulfillCommitFetch,
65+
WithChannelContext,
6566
};
6667
use crate::ln::channel_state::ChannelDetails;
6768
use crate::ln::funding::SpliceContribution;
@@ -13447,8 +13448,8 @@ where
1344713448

1344813449
#[rustfmt::skip]
1344913450
fn peer_disconnected(&self, counterparty_node_id: PublicKey) {
13450-
let _persistence_guard = PersistenceNotifierGuard::optionally_notify(
13451-
self, || NotifyOption::SkipPersistHandleEvents);
13451+
let _persistence_guard = PersistenceNotifierGuard::optionally_notify(self, || {
13452+
let mut persist = NotifyOption::SkipPersistHandleEvents;
1345213453
let mut failed_channels: Vec<(Result<Infallible, _>, _)> = Vec::new();
1345313454
let mut per_peer_state = self.per_peer_state.write().unwrap();
1345413455
let remove_peer = {
@@ -13461,11 +13462,29 @@ where
1346113462
let mut peer_state_lock = peer_state_mutex.lock().unwrap();
1346213463
let peer_state = &mut *peer_state_lock;
1346313464
let pending_msg_events = &mut peer_state.pending_msg_events;
13465+
let pending_events = &mut self.pending_events.lock().unwrap();
1346413466
peer_state.channel_by_id.retain(|_, chan| {
1346513467
let logger = WithChannelContext::from(&self.logger, &chan.context(), None);
13466-
if chan.peer_disconnected_is_resumable(&&logger) {
13468+
let DisconnectResult { is_resumable, splice_funding_failed } =
13469+
chan.peer_disconnected_is_resumable(&&logger);
13470+
13471+
if let Some(splice_funding_failed) = splice_funding_failed {
13472+
pending_events.push_back((events::Event::SpliceFailed {
13473+
channel_id: chan.context().channel_id(),
13474+
counterparty_node_id,
13475+
user_channel_id: chan.context().get_user_id(),
13476+
funding_txo: splice_funding_failed.funding_txo,
13477+
channel_type: splice_funding_failed.channel_type,
13478+
contributed_inputs: splice_funding_failed.contributed_inputs,
13479+
contributed_outputs: splice_funding_failed.contributed_outputs,
13480+
}, None));
13481+
persist = NotifyOption::DoPersist;
13482+
}
13483+
13484+
if is_resumable {
1346713485
return true;
1346813486
}
13487+
1346913488
// Clean up for removal.
1347013489
let reason = ClosureReason::DisconnectedPeer;
1347113490
let err = ChannelError::Close((reason.to_string(), reason));
@@ -13548,6 +13567,9 @@ where
1354813567
for (err, counterparty_node_id) in failed_channels.drain(..) {
1354913568
let _ = handle_error!(self, err, counterparty_node_id);
1355013569
}
13570+
13571+
persist
13572+
});
1355113573
}
1355213574

1355313575
#[rustfmt::skip]

lightning/src/ln/splicing_tests.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,8 @@ fn do_test_splice_state_reset_on_disconnect(reload: bool) {
401401
} else {
402402
nodes[0].node.peer_disconnected(node_id_1);
403403
nodes[1].node.peer_disconnected(node_id_0);
404+
405+
let _event = get_event!(nodes[0], Event::SpliceFailed);
404406
}
405407

406408
let mut reconnect_args = ReconnectArgs::new(&nodes[0], &nodes[1]);
@@ -466,6 +468,8 @@ fn do_test_splice_state_reset_on_disconnect(reload: bool) {
466468
} else {
467469
nodes[0].node.peer_disconnected(node_id_1);
468470
nodes[1].node.peer_disconnected(node_id_0);
471+
472+
let _event = get_event!(nodes[0], Event::SpliceFailed);
469473
}
470474

471475
let mut reconnect_args = ReconnectArgs::new(&nodes[0], &nodes[1]);

0 commit comments

Comments
 (0)