Skip to content

Commit 7597140

Browse files
committed
Address ChannelState inconsistency throughout splicing
Once a channel open has become locked (i.e., we've entered `ChannelState::ChannelReady`), the channel is intended to remain within this state for the rest of its lifetime until shutdown. Previously, we had assumed a channel being spliced would go through the `ChannelState` lifecycle again starting from `NegotiatingFunding` but skipping `AwaitingChannelReady`. This inconsistency departs from what we strive to achieve with `ChannelState` and also makes the state of a channel harder to reason about. This commit ensures a channel undergoing a splice remains in `ChannelReady`, clearing the quiescent flag once the negotiation is complete. Dual funding is unaffected by this change as the channel is being opened and we want to maintain the same `ChannelState` lifecycle.
1 parent 67aef54 commit 7597140

File tree

1 file changed

+73
-24
lines changed

1 file changed

+73
-24
lines changed

lightning/src/ln/channel.rs

Lines changed: 73 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -718,9 +718,9 @@ enum ChannelState {
718718
/// `AwaitingChannelReady`. Note that this is nonsense for an inbound channel as we immediately generate
719719
/// `funding_signed` upon receipt of `funding_created`, so simply skip this state.
720720
///
721-
/// For inbound and outbound interactively funded channels (dual-funding/splicing), this flag indicates
722-
/// that interactive transaction construction has been completed and we are now interactively signing
723-
/// the funding/splice transaction.
721+
/// For inbound and outbound interactively funded channels (dual-funding), this state indicates
722+
/// that interactive transaction construction has been completed and we are now interactively
723+
/// signing the initial funding transaction.
724724
FundingNegotiated(FundingNegotiatedFlags),
725725
/// We've received/sent `funding_created` and `funding_signed` and are thus now waiting on the
726726
/// funding transaction to confirm.
@@ -1932,6 +1932,14 @@ where
19321932
let logger = WithChannelContext::from(logger, self.context(), None);
19331933
match &mut self.phase {
19341934
ChannelPhase::UnfundedV2(chan) => {
1935+
debug_assert_eq!(
1936+
chan.context.channel_state,
1937+
ChannelState::NegotiatingFunding(
1938+
NegotiatingFundingFlags::OUR_INIT_SENT
1939+
| NegotiatingFundingFlags::THEIR_INIT_SENT
1940+
),
1941+
);
1942+
19351943
let signing_session = chan
19361944
.interactive_tx_constructor
19371945
.take()
@@ -6116,7 +6124,6 @@ where
61166124
funding
61176125
.channel_transaction_parameters.funding_outpoint = Some(outpoint);
61186126
self.interactive_tx_signing_session = Some(signing_session);
6119-
self.channel_state = ChannelState::FundingNegotiated(FundingNegotiatedFlags::new());
61206127

61216128
if is_splice {
61226129
debug_assert_eq!(
@@ -6127,6 +6134,7 @@ where
61276134
return Err(AbortReason::InternalError("Splicing not yet supported"));
61286135
} else {
61296136
self.assert_no_commitment_advancement(holder_commitment_transaction_number, "initial commitment_signed");
6137+
self.channel_state = ChannelState::FundingNegotiated(FundingNegotiatedFlags::new());
61306138
}
61316139

61326140
let commitment_signed = self.get_initial_commitment_signed_v2(&funding, logger);
@@ -6211,9 +6219,7 @@ where
62116219
SP::Target: SignerProvider,
62126220
L::Target: Logger,
62136221
{
6214-
assert!(
6215-
matches!(self.channel_state, ChannelState::FundingNegotiated(_) if self.interactive_tx_signing_session.is_some())
6216-
);
6222+
debug_assert!(self.interactive_tx_signing_session.is_some());
62176223

62186224
let signature = self.get_initial_counterparty_commitment_signature(funding, logger);
62196225
if let Some(signature) = signature {
@@ -8573,11 +8579,43 @@ where
85738579
}
85748580
}
85758581

8582+
fn on_tx_signatures_exchange(&mut self, funding_tx: Transaction) {
8583+
debug_assert!(!self.context.channel_state.is_monitor_update_in_progress());
8584+
debug_assert!(!self.context.channel_state.is_awaiting_remote_revoke());
8585+
8586+
if let Some(pending_splice) = self.pending_splice.as_mut() {
8587+
if let Some(FundingNegotiation::AwaitingSignatures { mut funding }) =
8588+
pending_splice.funding_negotiation.take()
8589+
{
8590+
funding.funding_transaction = Some(funding_tx);
8591+
pending_splice.negotiated_candidates.push(funding);
8592+
} else {
8593+
debug_assert!(false);
8594+
}
8595+
self.context.channel_state.clear_quiescent();
8596+
} else {
8597+
self.funding.funding_transaction = Some(funding_tx);
8598+
self.context.channel_state =
8599+
ChannelState::AwaitingChannelReady(AwaitingChannelReadyFlags::new());
8600+
}
8601+
}
8602+
85768603
pub fn funding_transaction_signed(
85778604
&mut self, funding_txid_signed: Txid, witnesses: Vec<Witness>,
85788605
) -> Result<(Option<msgs::TxSignatures>, Option<Transaction>), APIError> {
85798606
let signing_session =
85808607
if let Some(signing_session) = self.context.interactive_tx_signing_session.as_mut() {
8608+
if let Some(pending_splice) = self.pending_splice.as_ref() {
8609+
debug_assert!(pending_splice
8610+
.funding_negotiation
8611+
.as_ref()
8612+
.map(|funding_negotiation| matches!(
8613+
funding_negotiation,
8614+
FundingNegotiation::AwaitingSignatures { .. }
8615+
))
8616+
.unwrap_or(false));
8617+
}
8618+
85818619
signing_session
85828620
} else {
85838621
let err =
@@ -8620,24 +8658,40 @@ where
86208658
.provide_holder_witnesses(tx_signatures, &self.context.secp_ctx)
86218659
.map_err(|err| APIError::APIMisuseError { err })?;
86228660

8623-
if funding_tx_opt.is_some() {
8624-
self.funding.funding_transaction = funding_tx_opt.clone();
8625-
self.context.channel_state =
8626-
ChannelState::AwaitingChannelReady(AwaitingChannelReadyFlags::new());
8661+
if let Some(funding_tx) = funding_tx_opt.clone() {
8662+
debug_assert!(tx_signatures_opt.is_some());
8663+
self.on_tx_signatures_exchange(funding_tx);
86278664
}
86288665

86298666
Ok((tx_signatures_opt, funding_tx_opt))
86308667
}
86318668

8632-
#[rustfmt::skip]
8633-
pub fn tx_signatures(&mut self, msg: &msgs::TxSignatures) -> Result<(Option<msgs::TxSignatures>, Option<Transaction>), ChannelError> {
8634-
let signing_session = if let Some(signing_session) = self.context.interactive_tx_signing_session.as_mut() {
8669+
pub fn tx_signatures(
8670+
&mut self, msg: &msgs::TxSignatures,
8671+
) -> Result<(Option<msgs::TxSignatures>, Option<Transaction>), ChannelError> {
8672+
let signing_session = if let Some(signing_session) =
8673+
self.context.interactive_tx_signing_session.as_mut()
8674+
{
86358675
if signing_session.has_received_tx_signatures() {
86368676
return Err(ChannelError::Ignore("Ignoring duplicate tx_signatures".to_owned()));
86378677
}
86388678
if !signing_session.has_received_commitment_signed() {
8639-
return Err(ChannelError::close("Received tx_signatures before initial commitment_signed".to_owned()));
8679+
return Err(ChannelError::close(
8680+
"Received tx_signatures before initial commitment_signed".to_owned(),
8681+
));
8682+
}
8683+
8684+
if let Some(pending_splice) = self.pending_splice.as_ref() {
8685+
debug_assert!(pending_splice
8686+
.funding_negotiation
8687+
.as_ref()
8688+
.map(|funding_negotiation| matches!(
8689+
funding_negotiation,
8690+
FundingNegotiation::AwaitingSignatures { .. }
8691+
))
8692+
.unwrap_or(false));
86408693
}
8694+
86418695
signing_session
86428696
} else {
86438697
return Err(ChannelError::Ignore("Ignoring unexpected tx_signatures".to_owned()));
@@ -8657,16 +8711,11 @@ where
86578711
}
86588712
}
86598713

8660-
let (holder_tx_signatures_opt, funding_tx_opt) = signing_session.received_tx_signatures(msg)
8661-
.map_err(|msg| ChannelError::Warn(msg))?;
8714+
let (holder_tx_signatures_opt, funding_tx_opt) =
8715+
signing_session.received_tx_signatures(msg).map_err(|msg| ChannelError::Warn(msg))?;
86628716

8663-
if funding_tx_opt.is_some() {
8664-
// TODO(splicing): Transition back to `ChannelReady` and not `AwaitingChannelReady`
8665-
// We will also need to use the pending `FundingScope` in the splicing case.
8666-
//
8667-
// We have a finalized funding transaction, so we can set the funding transaction.
8668-
self.funding.funding_transaction = funding_tx_opt.clone();
8669-
self.context.channel_state = ChannelState::AwaitingChannelReady(AwaitingChannelReadyFlags::new());
8717+
if let Some(funding_tx) = funding_tx_opt.clone() {
8718+
self.on_tx_signatures_exchange(funding_tx);
86708719
}
86718720

86728721
Ok((holder_tx_signatures_opt, funding_tx_opt))

0 commit comments

Comments
 (0)