Skip to content

Commit b45d2de

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 5b2cd64 commit b45d2de

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
@@ -6800,8 +6820,15 @@ where
68006820
}
68016821

68026822
pub fn force_shutdown(&mut self, closure_reason: ClosureReason) -> ShutdownResult {
6803-
let splice_funding_failed = self
6804-
.pending_splice
6823+
let splice_funding_failed = self.maybe_fail_splice_negotiation();
6824+
6825+
let mut shutdown_result = self.context.force_shutdown(&self.funding, closure_reason);
6826+
shutdown_result.splice_funding_failed = splice_funding_failed;
6827+
shutdown_result
6828+
}
6829+
6830+
fn maybe_fail_splice_negotiation(&mut self) -> Option<SpliceFundingFailed> {
6831+
self.pending_splice
68056832
.as_mut()
68066833
.and_then(|pending_splice| pending_splice.funding_negotiation.take())
68076834
.filter(|funding_negotiation| funding_negotiation.is_initiator())
@@ -6831,11 +6858,7 @@ where
68316858
None
68326859
},
68336860
})
6834-
});
6835-
6836-
let mut shutdown_result = self.context.force_shutdown(&self.funding, closure_reason);
6837-
shutdown_result.splice_funding_failed = splice_funding_failed;
6838-
shutdown_result
6861+
})
68396862
}
68406863

68416864
fn interactive_tx_constructor_mut(&mut self) -> Option<&mut InteractiveTxConstructor> {
@@ -11672,9 +11695,9 @@ where
1167211695
.map_err(|e| APIError::APIMisuseError { err: e.to_owned() })
1167311696
}
1167411697

11675-
fn send_splice_init(
11676-
&mut self, instructions: SpliceInstructions,
11677-
) -> Result<msgs::SpliceInit, String> {
11698+
fn send_splice_init(&mut self, instructions: SpliceInstructions) -> msgs::SpliceInit {
11699+
debug_assert!(self.pending_splice.is_none());
11700+
1167811701
let SpliceInstructions {
1167911702
adjusted_funding_contribution,
1168011703
our_funding_inputs,
@@ -11684,15 +11707,6 @@ where
1168411707
locktime,
1168511708
} = instructions;
1168611709

11687-
// Check if a splice has been initiated already.
11688-
// Note: only a single outstanding splice is supported (per spec)
11689-
if self.pending_splice.is_some() {
11690-
return Err(format!(
11691-
"Channel {} cannot be spliced, as it has already a splice pending",
11692-
self.context.channel_id(),
11693-
));
11694-
}
11695-
1169611710
let prev_funding_input = self.funding.to_splice_funding_input();
1169711711
let context = FundingNegotiationContext {
1169811712
is_initiator: true,
@@ -11716,14 +11730,14 @@ where
1171611730
let prev_funding_txid = self.funding.get_funding_txid();
1171711731
let funding_pubkey = self.context.holder_pubkeys(prev_funding_txid).funding_pubkey;
1171811732

11719-
Ok(msgs::SpliceInit {
11733+
msgs::SpliceInit {
1172011734
channel_id: self.context.channel_id,
1172111735
funding_contribution_satoshis: adjusted_funding_contribution.to_sat(),
1172211736
funding_feerate_per_kw,
1172311737
locktime,
1172411738
funding_pubkey,
1172511739
require_confirmed_inputs: None,
11726-
})
11740+
}
1172711741
}
1172811742

1172911743
/// Checks during handling splice_init
@@ -12868,10 +12882,21 @@ where
1286812882
"Internal Error: Didn't have anything to do after reaching quiescence".to_owned()
1286912883
));
1287012884
},
12871-
Some(QuiescentAction::Splice(_instructions)) => {
12872-
return self.send_splice_init(_instructions)
12873-
.map(|splice_init| Some(StfuResponse::SpliceInit(splice_init)))
12874-
.map_err(|e| ChannelError::WarnAndDisconnect(e.to_owned()));
12885+
Some(QuiescentAction::Splice(instructions)) => {
12886+
if self.pending_splice.is_some() {
12887+
debug_assert!(false);
12888+
self.quiescent_action = Some(QuiescentAction::Splice(instructions));
12889+
12890+
return Err(ChannelError::WarnAndDisconnect(
12891+
format!(
12892+
"Channel {} cannot be spliced as it already has a splice pending",
12893+
self.context.channel_id(),
12894+
),
12895+
));
12896+
}
12897+
12898+
let splice_init = self.send_splice_init(instructions);
12899+
return Ok(Some(StfuResponse::SpliceInit(splice_init)));
1287512900
},
1287612901
#[cfg(any(test, fuzzing))]
1287712902
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)