Skip to content

Commit 0f85dd8

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 03f632a commit 0f85dd8

File tree

2 files changed

+77
-34
lines changed

2 files changed

+77
-34
lines changed

lightning/src/ln/channel.rs

Lines changed: 55 additions & 30 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,15 @@ 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+
chan.maybe_fail_splice_negotiation()
1618+
} else {
1619+
None
1620+
};
1621+
1622+
DisconnectResult { is_resumable, splice_funding_failed }
16031623
}
16041624

16051625
/// Should be called when the peer re-connects, returning an initial message which we should
@@ -6836,8 +6856,15 @@ where
68366856
}
68376857

68386858
pub fn force_shutdown(&mut self, closure_reason: ClosureReason) -> ShutdownResult {
6839-
let splice_funding_failed = self
6840-
.pending_splice
6859+
let splice_funding_failed = self.maybe_fail_splice_negotiation();
6860+
6861+
let mut shutdown_result = self.context.force_shutdown(&self.funding, closure_reason);
6862+
shutdown_result.splice_funding_failed = splice_funding_failed;
6863+
shutdown_result
6864+
}
6865+
6866+
fn maybe_fail_splice_negotiation(&mut self) -> Option<SpliceFundingFailed> {
6867+
self.pending_splice
68416868
.as_mut()
68426869
.and_then(|pending_splice| pending_splice.funding_negotiation.take())
68436870
.filter(|funding_negotiation| funding_negotiation.is_initiator())
@@ -6867,11 +6894,7 @@ where
68676894
None
68686895
},
68696896
})
6870-
});
6871-
6872-
let mut shutdown_result = self.context.force_shutdown(&self.funding, closure_reason);
6873-
shutdown_result.splice_funding_failed = splice_funding_failed;
6874-
shutdown_result
6897+
})
68756898
}
68766899

68776900
fn interactive_tx_constructor_mut(&mut self) -> Option<&mut InteractiveTxConstructor> {
@@ -11708,9 +11731,9 @@ where
1170811731
.map_err(|e| APIError::APIMisuseError { err: e.to_owned() })
1170911732
}
1171011733

11711-
fn send_splice_init(
11712-
&mut self, instructions: SpliceInstructions,
11713-
) -> Result<msgs::SpliceInit, String> {
11734+
fn send_splice_init(&mut self, instructions: SpliceInstructions) -> msgs::SpliceInit {
11735+
debug_assert!(self.pending_splice.is_none());
11736+
1171411737
let SpliceInstructions {
1171511738
adjusted_funding_contribution,
1171611739
our_funding_inputs,
@@ -11720,15 +11743,6 @@ where
1172011743
locktime,
1172111744
} = instructions;
1172211745

11723-
// Check if a splice has been initiated already.
11724-
// Note: only a single outstanding splice is supported (per spec)
11725-
if self.pending_splice.is_some() {
11726-
return Err(format!(
11727-
"Channel {} cannot be spliced, as it has already a splice pending",
11728-
self.context.channel_id(),
11729-
));
11730-
}
11731-
1173211746
let prev_funding_input = self.funding.to_splice_funding_input();
1173311747
let context = FundingNegotiationContext {
1173411748
is_initiator: true,
@@ -11752,14 +11766,14 @@ where
1175211766
let prev_funding_txid = self.funding.get_funding_txid();
1175311767
let funding_pubkey = self.context.holder_pubkeys(prev_funding_txid).funding_pubkey;
1175411768

11755-
Ok(msgs::SpliceInit {
11769+
msgs::SpliceInit {
1175611770
channel_id: self.context.channel_id,
1175711771
funding_contribution_satoshis: adjusted_funding_contribution.to_sat(),
1175811772
funding_feerate_per_kw,
1175911773
locktime,
1176011774
funding_pubkey,
1176111775
require_confirmed_inputs: None,
11762-
})
11776+
}
1176311777
}
1176411778

1176511779
/// Checks during handling splice_init
@@ -12904,10 +12918,21 @@ where
1290412918
"Internal Error: Didn't have anything to do after reaching quiescence".to_owned()
1290512919
));
1290612920
},
12907-
Some(QuiescentAction::Splice(_instructions)) => {
12908-
return self.send_splice_init(_instructions)
12909-
.map(|splice_init| Some(StfuResponse::SpliceInit(splice_init)))
12910-
.map_err(|e| ChannelError::WarnAndDisconnect(e.to_owned()));
12921+
Some(QuiescentAction::Splice(instructions)) => {
12922+
if self.pending_splice.is_some() {
12923+
debug_assert!(false);
12924+
self.quiescent_action = Some(QuiescentAction::Splice(instructions));
12925+
12926+
return Err(ChannelError::WarnAndDisconnect(
12927+
format!(
12928+
"Channel {} cannot be spliced as it already has a splice pending",
12929+
self.context.channel_id(),
12930+
),
12931+
));
12932+
}
12933+
12934+
let splice_init = self.send_splice_init(instructions);
12935+
return Ok(Some(StfuResponse::SpliceInit(splice_init)));
1291112936
},
1291212937
#[cfg(any(test, fuzzing))]
1291312938
Some(QuiescentAction::DoNothing) => {

lightning/src/ln/channelmanager.rs

Lines changed: 22 additions & 4 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;
@@ -13397,11 +13398,28 @@ where
1339713398
let mut peer_state_lock = peer_state_mutex.lock().unwrap();
1339813399
let peer_state = &mut *peer_state_lock;
1339913400
let pending_msg_events = &mut peer_state.pending_msg_events;
13401+
let pending_events = &mut self.pending_events.lock().unwrap();
1340013402
peer_state.channel_by_id.retain(|_, chan| {
1340113403
let logger = WithChannelContext::from(&self.logger, &chan.context(), None);
13402-
if chan.peer_disconnected_is_resumable(&&logger) {
13404+
let DisconnectResult { is_resumable, splice_funding_failed } =
13405+
chan.peer_disconnected_is_resumable(&&logger);
13406+
13407+
if let Some(splice_funding_failed) = splice_funding_failed {
13408+
pending_events.push_back((events::Event::SpliceFailed {
13409+
channel_id: chan.context().channel_id(),
13410+
counterparty_node_id,
13411+
user_channel_id: chan.context().get_user_id(),
13412+
funding_txo: splice_funding_failed.funding_txo,
13413+
channel_type: splice_funding_failed.channel_type,
13414+
contributed_inputs: splice_funding_failed.contributed_inputs,
13415+
contributed_outputs: splice_funding_failed.contributed_outputs,
13416+
}, None));
13417+
}
13418+
13419+
if is_resumable {
1340313420
return true;
1340413421
}
13422+
1340513423
// Clean up for removal.
1340613424
let reason = ClosureReason::DisconnectedPeer;
1340713425
let err = ChannelError::Close((reason.to_string(), reason));

0 commit comments

Comments
 (0)