Skip to content

Integrate Splicing with Quiescence #4007

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 42 additions & 4 deletions lightning/src/ln/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2443,6 +2443,15 @@ impl PendingSplice {
}
}

pub(crate) enum QuiescentAction {
// TODO: Make this test-only once we have another variant (as some code requires *a* variant).
DoNothing,
}

impl_writeable_tlv_based_enum_upgradable!(QuiescentAction,
(99, DoNothing) => {},
);

/// Wrapper around a [`Transaction`] useful for caching the result of [`Transaction::compute_txid`].
struct ConfirmedTransaction<'a> {
tx: &'a Transaction,
Expand Down Expand Up @@ -2742,6 +2751,12 @@ where
/// If we can't release a [`ChannelMonitorUpdate`] until some external action completes, we
/// store it here and only release it to the `ChannelManager` once it asks for it.
blocked_monitor_updates: Vec<PendingChannelMonitorUpdate>,

/// Once we become quiescent, if we're the initiator, there's some action we'll want to take.
/// This keeps track of that action. Note that if we become quiescent and we're not the
/// initiator we may be able to merge this action into what the counterparty wanted to do (e.g.
/// in the case of splicing).
post_quiescence_action: Option<QuiescentAction>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: "post" makes it seem like something we'd do after quiescence and not while

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since it only applies to funded channels, it could maybe go there instead of ChannelContext (unless we need it in some ChannelContext method)

}

/// A channel struct implementing this trait can receive an initial counterparty commitment
Expand Down Expand Up @@ -3316,6 +3331,8 @@ where
blocked_monitor_updates: Vec::new(),

is_manual_broadcast: false,

post_quiescence_action: None,
};

Ok((funding, channel_context))
Expand Down Expand Up @@ -3552,6 +3569,8 @@ where
blocked_monitor_updates: Vec::new(),
local_initiated_shutdown: None,
is_manual_broadcast: false,

post_quiescence_action: None,
};

Ok((funding, channel_context))
Expand Down Expand Up @@ -11548,7 +11567,7 @@ where
#[cfg(any(test, fuzzing))]
#[rustfmt::skip]
pub fn propose_quiescence<L: Deref>(
&mut self, logger: &L,
&mut self, logger: &L, action: QuiescentAction,
) -> Result<Option<msgs::Stfu>, ChannelError>
where
L::Target: Logger,
Expand All @@ -11560,11 +11579,13 @@ where
"Channel is not in a live state to propose quiescence".to_owned()
));
}
if self.context.channel_state.is_quiescent() {
return Err(ChannelError::Ignore("Channel is already quiescent".to_owned()));
if self.context.post_quiescence_action.is_some() {
return Err(ChannelError::Ignore("Channel is already quiescing".to_owned()));
}

if self.context.channel_state.is_awaiting_quiescence()
self.context.post_quiescence_action = Some(action);
if self.context.channel_state.is_quiescent()
|| self.context.channel_state.is_awaiting_quiescence()
|| self.context.channel_state.is_local_stfu_sent()
{
return Ok(None);
Expand Down Expand Up @@ -11683,6 +11704,21 @@ where
if !is_holder_quiescence_initiator { " not" } else { "" }
);

if is_holder_quiescence_initiator {
match self.context.post_quiescence_action.take() {
None => {
debug_assert!(false);
return Err(ChannelError::WarnAndDisconnect(
"Internal Error: Didn't have anything to do after reaching quiescence".to_owned()
));
},
Some(QuiescentAction::DoNothing) => {
// In quiescence test we want to just hang out here, letting the test manually
// leave quiescence.
},
}
}

Ok(None)
}

Expand Down Expand Up @@ -13986,6 +14022,8 @@ where

blocked_monitor_updates: blocked_monitor_updates.unwrap(),
is_manual_broadcast: is_manual_broadcast.unwrap_or(false),

post_quiescence_action: None,
},
interactive_tx_signing_session,
holder_commitment_point,
Expand Down
6 changes: 3 additions & 3 deletions lightning/src/ln/channelmanager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ use crate::events::{
};
use crate::events::{FundingInfo, PaidBolt12Invoice};
use crate::ln::chan_utils::selected_commitment_sat_per_1000_weight;
// Since this struct is returned in `list_channels` methods, expose it here in case users want to
// construct one themselves.
#[cfg(any(test, fuzzing))]
use crate::ln::channel::QuiescentAction;
use crate::ln::channel::{
self, hold_time_since, Channel, ChannelError, ChannelUpdateStatus, FundedChannel,
InboundV1Channel, OutboundV1Channel, PendingV2Channel, ReconnectionMsg, ShutdownResult,
Expand Down Expand Up @@ -11660,7 +11660,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
&self.logger, Some(*counterparty_node_id), Some(*channel_id), None
);

match chan.propose_quiescence(&&logger) {
match chan.propose_quiescence(&&logger, QuiescentAction::DoNothing) {
Ok(None) => {},
Ok(Some(stfu)) => {
peer_state.pending_msg_events.push(MessageSendEvent::SendStfu {
Expand Down