Skip to content

Conversation

wpaulino
Copy link
Contributor

@wpaulino wpaulino commented Sep 5, 2025

This was pulled out of #4054 to ease review. It depends on #4060 to not bother with cfg(splicing) anymore.

@ldk-reviews-bot
Copy link

ldk-reviews-bot commented Sep 5, 2025

👋 Thanks for assigning @TheBlueMatt as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

// FIXME: Either we bring back the `OUR_TX_SIGNATURES_READY` flag for this specific
// case, or we somehow access the signing session to check it instead.
ChannelState::FundingNegotiated(flags) => !flags.is_interactive_signing(),
Copy link
Contributor

Choose a reason for hiding this comment

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

The current implementation has a potential logic issue. The FIXME comment correctly identifies that is_interactive_signing() is being used as a replacement for the removed OUR_TX_SIGNATURES_READY flag, but these represent different states:

  • is_interactive_signing() is true during the entire interactive signing process
  • OUR_TX_SIGNATURES_READY was specifically true only after our signatures were ready to send

This semantic difference could cause funding transactions to be incorrectly marked as non-broadcastable when they should be broadcastable. Consider either:

  1. Restoring the OUR_TX_SIGNATURES_READY flag for this specific use case, or
  2. Accessing the signing session directly to check if holder signatures are ready via something like signing_session.holder_tx_signatures().is_some()

This would more accurately represent the original intent of the code.

Suggested change
// FIXME: Either we bring back the `OUR_TX_SIGNATURES_READY` flag for this specific
// case, or we somehow access the signing session to check it instead.
ChannelState::FundingNegotiated(flags) => !flags.is_interactive_signing(),
// We need to check if our signatures are ready to send, which means the transaction
// is ready to be broadcast.
ChannelState::FundingNegotiated(flags) => {
if let Some(signing_session) = &self.funding_tx_signing_session {
signing_session.holder_tx_signatures().is_none()
} else {
!flags.is_interactive_signing()
}
},

Spotted by Diamond

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

@ldk-reviews-bot
Copy link

🔔 1st Reminder

Hey @valentinewallace! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

@wpaulino wpaulino removed the request for review from valentinewallace September 8, 2025 20:42
@wpaulino wpaulino force-pushed the splice-channel-state-rework branch from 9272b39 to 23a1c29 Compare September 8, 2025 21:49
Copy link

codecov bot commented Sep 8, 2025

Codecov Report

❌ Patch coverage is 40.24390% with 98 lines in your changes missing coverage. Please review.
✅ Project coverage is 88.39%. Comparing base (867f084) to head (0cbeb51).

Files with missing lines Patch % Lines
lightning/src/ln/channel.rs 39.13% 85 Missing and 13 partials ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main    #4061   +/-   ##
=======================================
  Coverage   88.39%   88.39%           
=======================================
  Files         177      177           
  Lines      131314   131355   +41     
  Branches   131314   131355   +41     
=======================================
+ Hits       116069   116113   +44     
+ Misses      12596    12594    -2     
+ Partials     2649     2648    -1     
Flag Coverage Δ
fuzzing 21.99% <0.00%> (-0.02%) ⬇️
tests 88.23% <40.24%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@wpaulino wpaulino self-assigned this Sep 9, 2025
@wpaulino wpaulino added this to the 0.2 milestone Sep 9, 2025
This commit addresses an overlap of state between
`InteractiveTxSigningSession` and `ChannelState::FundingNegotiated`. The
signing session already tracks whether both holder and counterparty
`tx_signatures` have been produced, so tracking the state duplicatively
at the `ChannelState` level is unnecessary.
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.
@wpaulino wpaulino force-pushed the splice-channel-state-rework branch from 23a1c29 to 0cbeb51 Compare September 9, 2025 19:59
Comment on lines +8606 to 8612
debug_assert!(
false,
"A signing session must always be present while interactive signing"
);
let err =
format!("Channel {} not expecting funding signatures", self.context.channel_id);
return Err(APIError::APIMisuseError { err });
Copy link
Contributor

Choose a reason for hiding this comment

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

The code contains a pattern where a debug assertion claims a signing session must always be present during interactive signing, but then includes error handling for when it's None. This creates a logical contradiction - either:

  1. The assertion is correct and the error handling is unnecessary, or
  2. The error handling is necessary and the assertion is incorrect

This pattern appears multiple times throughout the code. Consider either:

  • Removing the error handling if the assertion truly holds
  • Adjusting the assertion to reflect the actual conditions where a signing session might be absent

This would make the code's intent clearer and avoid potential confusion about the expected state during interactive signing.

Suggested change
debug_assert!(
false,
"A signing session must always be present while interactive signing"
);
let err =
format!("Channel {} not expecting funding signatures", self.context.channel_id);
return Err(APIError::APIMisuseError { err });
// A signing session should typically be present during interactive signing,
// but handle the case where it's not
let err =
format!("Channel {} not expecting funding signatures", self.context.channel_id);
return Err(APIError::APIMisuseError { err });

Spotted by Diamond

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants