Skip to content

Commit 9724d19

Browse files
authored
Merge pull request #4007 from TheBlueMatt/2025-08-splice-quiescent
Simplify Quiescence and prepare for splice integration
2 parents c2d9b97 + c7e4887 commit 9724d19

File tree

3 files changed

+194
-64
lines changed

3 files changed

+194
-64
lines changed

lightning/src/ln/channel.rs

Lines changed: 73 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1863,6 +1863,7 @@ where
18631863
holder_commitment_point,
18641864
#[cfg(splicing)]
18651865
pending_splice: None,
1866+
quiescent_action: None,
18661867
};
18671868
let res = funded_channel.initial_commitment_signed_v2(msg, best_block, signer_provider, logger)
18681869
.map(|monitor| (Some(monitor), None))
@@ -2429,6 +2430,15 @@ impl PendingSplice {
24292430
}
24302431
}
24312432

2433+
pub(crate) enum QuiescentAction {
2434+
// TODO: Make this test-only once we have another variant (as some code requires *a* variant).
2435+
DoNothing,
2436+
}
2437+
2438+
impl_writeable_tlv_based_enum_upgradable!(QuiescentAction,
2439+
(99, DoNothing) => {},
2440+
);
2441+
24322442
/// Wrapper around a [`Transaction`] useful for caching the result of [`Transaction::compute_txid`].
24332443
struct ConfirmedTransaction<'a> {
24342444
tx: &'a Transaction,
@@ -2728,10 +2738,6 @@ where
27282738
/// If we can't release a [`ChannelMonitorUpdate`] until some external action completes, we
27292739
/// store it here and only release it to the `ChannelManager` once it asks for it.
27302740
blocked_monitor_updates: Vec<PendingChannelMonitorUpdate>,
2731-
2732-
/// Only set when a counterparty `stfu` has been processed to track which node is allowed to
2733-
/// propose "something fundamental" upon becoming quiescent.
2734-
is_holder_quiescence_initiator: Option<bool>,
27352741
}
27362742

27372743
/// A channel struct implementing this trait can receive an initial counterparty commitment
@@ -3306,8 +3312,6 @@ where
33063312
blocked_monitor_updates: Vec::new(),
33073313

33083314
is_manual_broadcast: false,
3309-
3310-
is_holder_quiescence_initiator: None,
33113315
};
33123316

33133317
Ok((funding, channel_context))
@@ -3544,8 +3548,6 @@ where
35443548
blocked_monitor_updates: Vec::new(),
35453549
local_initiated_shutdown: None,
35463550
is_manual_broadcast: false,
3547-
3548-
is_holder_quiescence_initiator: None,
35493551
};
35503552

35513553
Ok((funding, channel_context))
@@ -6058,6 +6060,12 @@ where
60586060
/// Info about an in-progress, pending splice (if any), on the pre-splice channel
60596061
#[cfg(splicing)]
60606062
pending_splice: Option<PendingSplice>,
6063+
6064+
/// Once we become quiescent, if we're the initiator, there's some action we'll want to take.
6065+
/// This keeps track of that action. Note that if we become quiescent and we're not the
6066+
/// initiator we may be able to merge this action into what the counterparty wanted to do (e.g.
6067+
/// in the case of splicing).
6068+
quiescent_action: Option<QuiescentAction>,
60616069
}
60626070

60636071
#[cfg(splicing)]
@@ -8198,11 +8206,13 @@ where
81988206

81998207
// Reset any quiescence-related state as it is implicitly terminated once disconnected.
82008208
if matches!(self.context.channel_state, ChannelState::ChannelReady(_)) {
8201-
self.context.channel_state.clear_awaiting_quiescence();
8209+
if self.quiescent_action.is_some() {
8210+
// If we were trying to get quiescent, try again after reconnection.
8211+
self.context.channel_state.set_awaiting_quiescence();
8212+
}
82028213
self.context.channel_state.clear_local_stfu_sent();
82038214
self.context.channel_state.clear_remote_stfu_sent();
82048215
self.context.channel_state.clear_quiescent();
8205-
self.context.is_holder_quiescence_initiator.take();
82068216
}
82078217

82088218
self.context.channel_state.set_peer_disconnected();
@@ -11540,30 +11550,36 @@ where
1154011550
#[cfg(any(test, fuzzing))]
1154111551
#[rustfmt::skip]
1154211552
pub fn propose_quiescence<L: Deref>(
11543-
&mut self, logger: &L,
11553+
&mut self, logger: &L, action: QuiescentAction,
1154411554
) -> Result<Option<msgs::Stfu>, ChannelError>
1154511555
where
1154611556
L::Target: Logger,
1154711557
{
1154811558
log_debug!(logger, "Attempting to initiate quiescence");
1154911559

11550-
if !self.context.is_live() {
11560+
if !self.context.is_usable() {
1155111561
return Err(ChannelError::Ignore(
11552-
"Channel is not in a live state to propose quiescence".to_owned()
11562+
"Channel is not in a usable state to propose quiescence".to_owned()
1155311563
));
1155411564
}
11555-
if self.context.channel_state.is_quiescent() {
11556-
return Err(ChannelError::Ignore("Channel is already quiescent".to_owned()));
11565+
if self.quiescent_action.is_some() {
11566+
return Err(ChannelError::Ignore("Channel is already quiescing".to_owned()));
1155711567
}
1155811568

11559-
if self.context.channel_state.is_awaiting_quiescence()
11569+
self.quiescent_action = Some(action);
11570+
if self.context.channel_state.is_quiescent()
11571+
|| self.context.channel_state.is_awaiting_quiescence()
1156011572
|| self.context.channel_state.is_local_stfu_sent()
1156111573
{
1156211574
return Ok(None);
1156311575
}
1156411576

1156511577
self.context.channel_state.set_awaiting_quiescence();
11566-
Ok(Some(self.send_stfu(logger)?))
11578+
if self.context.is_live() {
11579+
Ok(Some(self.send_stfu(logger)?))
11580+
} else {
11581+
Ok(None)
11582+
}
1156711583
}
1156811584

1156911585
// Assumes we are either awaiting quiescence or our counterparty has requested quiescence.
@@ -11573,7 +11589,6 @@ where
1157311589
L::Target: Logger,
1157411590
{
1157511591
debug_assert!(!self.context.channel_state.is_local_stfu_sent());
11576-
// Either state being set implies the channel is live.
1157711592
debug_assert!(
1157811593
self.context.channel_state.is_awaiting_quiescence()
1157911594
|| self.context.channel_state.is_remote_stfu_sent()
@@ -11593,18 +11608,10 @@ where
1159311608
self.context.channel_state.clear_awaiting_quiescence();
1159411609
self.context.channel_state.clear_remote_stfu_sent();
1159511610
self.context.channel_state.set_quiescent();
11596-
if let Some(initiator) = self.context.is_holder_quiescence_initiator.as_ref() {
11597-
log_debug!(
11598-
logger,
11599-
"Responding to counterparty stfu with our own, channel is now quiescent and we are{} the initiator",
11600-
if !initiator { " not" } else { "" }
11601-
);
11602-
11603-
*initiator
11604-
} else {
11605-
debug_assert!(false, "Quiescence initiator must have been set when we received stfu");
11606-
false
11607-
}
11611+
// We are sending an stfu in response to our couterparty's stfu, but had not yet sent
11612+
// our own stfu (even if `awaiting_quiescence` was set). Thus, the counterparty is the
11613+
// initiator and they can do "something fundamental".
11614+
false
1160811615
} else {
1160911616
log_debug!(logger, "Sending stfu as quiescence initiator");
1161011617
debug_assert!(self.context.channel_state.is_awaiting_quiescence());
@@ -11635,9 +11642,7 @@ where
1163511642
));
1163611643
}
1163711644

11638-
if self.context.channel_state.is_awaiting_quiescence()
11639-
|| !self.context.channel_state.is_local_stfu_sent()
11640-
{
11645+
if !self.context.channel_state.is_local_stfu_sent() {
1164111646
if !msg.initiator {
1164211647
return Err(ChannelError::WarnAndDisconnect(
1164311648
"Peer sent unexpected `stfu` without signaling as initiator".to_owned()
@@ -11651,23 +11656,13 @@ where
1165111656
// then.
1165211657
self.context.channel_state.set_remote_stfu_sent();
1165311658

11654-
let is_holder_initiator = if self.context.channel_state.is_awaiting_quiescence() {
11655-
// We were also planning to propose quiescence, let the tie-breaker decide the
11656-
// initiator.
11657-
self.funding.is_outbound()
11658-
} else {
11659-
false
11660-
};
11661-
self.context.is_holder_quiescence_initiator = Some(is_holder_initiator);
11662-
1166311659
log_debug!(logger, "Received counterparty stfu proposing quiescence");
1166411660
return self.send_stfu(logger).map(|stfu| Some(stfu));
1166511661
}
1166611662

1166711663
// We already sent `stfu` and are now processing theirs. It may be in response to ours, or
1166811664
// we happened to both send `stfu` at the same time and a tie-break is needed.
1166911665
let is_holder_quiescence_initiator = !msg.initiator || self.funding.is_outbound();
11670-
self.context.is_holder_quiescence_initiator = Some(is_holder_quiescence_initiator);
1167111666

1167211667
// We were expecting to receive `stfu` because we already sent ours.
1167311668
self.mark_response_received();
@@ -11695,6 +11690,21 @@ where
1169511690
if !is_holder_quiescence_initiator { " not" } else { "" }
1169611691
);
1169711692

11693+
if is_holder_quiescence_initiator {
11694+
match self.quiescent_action.take() {
11695+
None => {
11696+
debug_assert!(false);
11697+
return Err(ChannelError::WarnAndDisconnect(
11698+
"Internal Error: Didn't have anything to do after reaching quiescence".to_owned()
11699+
));
11700+
},
11701+
Some(QuiescentAction::DoNothing) => {
11702+
// In quiescence test we want to just hang out here, letting the test manually
11703+
// leave quiescence.
11704+
},
11705+
}
11706+
}
11707+
1169811708
Ok(None)
1169911709
}
1170011710

@@ -11710,6 +11720,10 @@ where
1171011720
&& self.context.channel_state.is_remote_stfu_sent())
1171111721
);
1171211722

11723+
if !self.context.is_live() {
11724+
return Ok(None);
11725+
}
11726+
1171311727
// We need to send our `stfu`, either because we're trying to initiate quiescence, or the
1171411728
// counterparty is and we've yet to send ours.
1171511729
if self.context.channel_state.is_awaiting_quiescence()
@@ -11735,13 +11749,10 @@ where
1173511749
debug_assert!(!self.context.channel_state.is_local_stfu_sent());
1173611750
debug_assert!(!self.context.channel_state.is_remote_stfu_sent());
1173711751

11738-
if self.context.channel_state.is_quiescent() {
11739-
self.mark_response_received();
11740-
self.context.channel_state.clear_quiescent();
11741-
self.context.is_holder_quiescence_initiator.take().expect("Must always be set while quiescent")
11742-
} else {
11743-
false
11744-
}
11752+
self.mark_response_received();
11753+
let was_quiescent = self.context.channel_state.is_quiescent();
11754+
self.context.channel_state.clear_quiescent();
11755+
was_quiescent
1174511756
}
1174611757

1174711758
pub fn remove_legacy_scids_before_block(&mut self, height: u32) -> alloc::vec::Drain<'_, u64> {
@@ -12063,6 +12074,7 @@ where
1206312074
holder_commitment_point,
1206412075
#[cfg(splicing)]
1206512076
pending_splice: None,
12077+
quiescent_action: None,
1206612078
};
1206712079

1206812080
let need_channel_ready = channel.check_get_channel_ready(0, logger).is_some()
@@ -12349,6 +12361,7 @@ where
1234912361
holder_commitment_point,
1235012362
#[cfg(splicing)]
1235112363
pending_splice: None,
12364+
quiescent_action: None,
1235212365
};
1235312366
let need_channel_ready = channel.check_get_channel_ready(0, logger).is_some()
1235412367
|| channel.context.signer_pending_channel_ready;
@@ -12850,7 +12863,11 @@ where
1285012863
match channel_state {
1285112864
ChannelState::AwaitingChannelReady(_) => {},
1285212865
ChannelState::ChannelReady(_) => {
12853-
channel_state.clear_awaiting_quiescence();
12866+
if self.quiescent_action.is_some() {
12867+
// If we're trying to get quiescent to do something, try again when we
12868+
// reconnect to the peer.
12869+
channel_state.set_awaiting_quiescence();
12870+
}
1285412871
channel_state.clear_local_stfu_sent();
1285512872
channel_state.clear_remote_stfu_sent();
1285612873
channel_state.clear_quiescent();
@@ -13258,6 +13275,7 @@ where
1325813275
(60, self.context.historical_scids, optional_vec), // Added in 0.2
1325913276
(61, fulfill_attribution_data, optional_vec), // Added in 0.2
1326013277
(63, holder_commitment_point_current, option), // Added in 0.2
13278+
(65, self.quiescent_action, option), // Added in 0.2
1326113279
});
1326213280

1326313281
Ok(())
@@ -13619,6 +13637,8 @@ where
1361913637

1362013638
let mut minimum_depth_override: Option<u32> = None;
1362113639

13640+
let mut quiescent_action = None;
13641+
1362213642
read_tlv_fields!(reader, {
1362313643
(0, announcement_sigs, option),
1362413644
(1, minimum_depth, option),
@@ -13662,6 +13682,7 @@ where
1366213682
(60, historical_scids, optional_vec), // Added in 0.2
1366313683
(61, fulfill_attribution_data, optional_vec), // Added in 0.2
1366413684
(63, holder_commitment_point_current_opt, option), // Added in 0.2
13685+
(65, quiescent_action, upgradable_option), // Added in 0.2
1366513686
});
1366613687

1366713688
let holder_signer = signer_provider.derive_channel_signer(channel_keys_id);
@@ -14003,13 +14024,12 @@ where
1400314024

1400414025
blocked_monitor_updates: blocked_monitor_updates.unwrap(),
1400514026
is_manual_broadcast: is_manual_broadcast.unwrap_or(false),
14006-
14007-
is_holder_quiescence_initiator: None,
1400814027
},
1400914028
interactive_tx_signing_session,
1401014029
holder_commitment_point,
1401114030
#[cfg(splicing)]
1401214031
pending_splice: None,
14032+
quiescent_action,
1401314033
})
1401414034
}
1401514035
}

lightning/src/ln/channelmanager.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ use crate::events::{
5858
};
5959
use crate::events::{FundingInfo, PaidBolt12Invoice};
6060
use crate::ln::chan_utils::selected_commitment_sat_per_1000_weight;
61-
// Since this struct is returned in `list_channels` methods, expose it here in case users want to
62-
// construct one themselves.
61+
#[cfg(any(test, fuzzing))]
62+
use crate::ln::channel::QuiescentAction;
6363
use crate::ln::channel::{
6464
self, hold_time_since, Channel, ChannelError, ChannelUpdateStatus, FundedChannel,
6565
InboundV1Channel, OutboundV1Channel, PendingV2Channel, ReconnectionMsg, ShutdownResult,
@@ -11712,7 +11712,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1171211712
&self.logger, Some(*counterparty_node_id), Some(*channel_id), None
1171311713
);
1171411714

11715-
match chan.propose_quiescence(&&logger) {
11715+
match chan.propose_quiescence(&&logger, QuiescentAction::DoNothing) {
1171611716
Ok(None) => {},
1171711717
Ok(Some(stfu)) => {
1171811718
peer_state.pending_msg_events.push(MessageSendEvent::SendStfu {

0 commit comments

Comments
 (0)