-
Notifications
You must be signed in to change notification settings - Fork 419
Emit SplicePending
and SpliceFailed
events
#4077
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
base: main
Are you sure you want to change the base?
Conversation
Applications need to be notified when splice transactions are pending confirmation to properly track channel state transitions and update their UIs accordingly. This event allows applications to distinguish between initial channel funding (ChannelPending) and splice operations. The SplicePending event contains the essential channel information needed by applications: channel ID, user channel ID, counterparty node ID, funding transaction outpoint, and channel type features. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
👋 Thanks for assigning @TheBlueMatt as a reviewer! |
Looking for high-level feedback on the approach and if all scenarios were covered. Specifically, is |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #4077 +/- ##
==========================================
- Coverage 87.81% 87.68% -0.13%
==========================================
Files 176 176
Lines 131770 132034 +264
Branches 131770 132034 +264
==========================================
+ Hits 115719 115780 +61
- Misses 13416 13615 +199
- Partials 2635 2639 +4
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Add Event::SplicePending emission whenever a FundingScope is pushed into PendingSplice::negotiated_candidates. This allows applications to be notified when a splice transaction has been constructed and signed but is not yet confirmed on-chain. Creates SpliceFundingNegotiated struct to carry event data from channel operations to ChannelManager, where it's converted to the appropriate Event. Updates function signatures in the channel layer to return this information and modifies all callers in ChannelManager to handle the new return values and emit the events. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
Introduce SpliceFailed event to notify applications when splice transaction construction or negotiation fails. This allows applications to handle failures gracefully and take corrective action or retry. The event includes similar fields to SplicePending but with optional funding_txo and channel_type fields since they may not be available when failures occur early in the process. Additionally includes contributed_inputs and contributed_outputs vectors to provide information about what inputs and outputs were attempted. Uses TLV ID 52 for serialization to maintain proper event ordering and avoid conflicts with other event types. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
When interactive transaction construction fails during splice funding negotiation, emit Event::SpliceFailed to notify users of the failure. This introduces a SpliceFundingFailed struct to carry failure information from channel functions to ChannelManager, where it is converted to the appropriate event. The struct includes channel metadata and placeholders for contributed inputs/outputs (currently empty pending access to private InteractiveTxConstructor fields). Updates all interactive transaction functions (tx_add_input, tx_add_output, tx_remove_input, tx_remove_output, tx_complete) to return failure information alongside abort messages, enabling proper event emission when splice negotiations fail. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
When splice_ack validation or interactive transaction construction fails, emit Event::SpliceFailed to notify users of the failure. This reuses the SpliceFundingFailed struct introduced for interactive transaction failures, providing consistent failure reporting across all splice operations. The implementation handles two failure scenarios: - Early validation failure: Sets funding_txo and channel_type to None since no splice funding was established - Late construction failure: Includes actual funding information since validation passed but transaction construction failed The SpliceFundingFailed struct provides placeholders for contributed inputs/outputs that can be populated when access to interactive transaction constructor internals becomes available. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
When a tx_abort message is successfully processed for a funded channel with an active splice negotiation, emit Event::SpliceFailed to notify users that the splice operation was aborted by the counterparty. This extends the SpliceFailed event coverage to handle abort scenarios, providing comprehensive splice failure notifications across all stages: - AwaitingAck: funding_txo and channel_type are None since funding parameters were not yet established - ConstructingTransaction/AwaitingSignatures: Include actual funding information since negotiation had progressed to funding establishment The implementation captures splice context before taking the funding negotiation state, ensuring accurate failure information is available for event emission while maintaining proper tx_abort acknowledgment behavior per the Lightning specification. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
…lice negotiations Adds SpliceFailed event emission immediately after ChannelClosed events when a FundedChannel is shut down while having an active splice negotiation. This ensures users are notified when splice operations are terminated due to channel closure. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
…cence Users need to be notified when splice operations fail at any stage. Previously, splice failures during the quiescence initialization phase were not reported, leaving users unaware of failed splice attempts. Now emits Event::SpliceFailed when send_splice_init fails during stfu processing of QuiescentAction::Splice, ensuring consistent splice failure reporting across all phases of the splice lifecycle. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
Users need to be notified when splice operations are cancelled due to channel closure, regardless of the splice phase. Previously, splice operations that were scheduled but not yet in active negotiation were silently lost during channel shutdown, leaving users unaware of the failed splice attempt. Now emits Event::SpliceFailed when a channel shuts down with a pending QuiescentAction::Splice, ensuring comprehensive splice failure reporting across all phases of the splice lifecycle. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
0db24f3
to
41c1e60
Compare
let splice_funding = self.validate_splice_ack(msg)?; | ||
let splice_funding = self.validate_splice_ack(msg).map_err(|err| { | ||
let splice_failed = SpliceFundingFailed { | ||
channel_id: self.context.channel_id, | ||
counterparty_node_id: self.context.counterparty_node_id, | ||
user_channel_id: self.context.user_id, | ||
funding_txo: None, | ||
channel_type: None, | ||
contributed_inputs: Vec::new(), | ||
contributed_outputs: Vec::new(), | ||
}; | ||
(err, splice_failed) | ||
})?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This commit will likely need to be re-worked to have validate_splice_ack
return Option<SpliceFundingFailed>
as part of its error. But it seems we never clear pending_splice.funding_negotiation
here.
@wpaulino Should we? I'd imagine if we ever emit Event::SpliceFailed
then pending_splice.funding_negotiation
should no longer be set.
ChannelError::WarnAndDisconnect(format!( | ||
let splice_failed = SpliceFundingFailed { | ||
channel_id: self.context.channel_id, | ||
counterparty_node_id: self.context.counterparty_node_id, | ||
user_channel_id: self.context.user_id, | ||
funding_txo: splice_funding.get_funding_txo().map(|txo| txo.into_bitcoin_outpoint()), | ||
channel_type: Some(splice_funding.get_channel_type().clone()), | ||
contributed_inputs: Vec::new(), | ||
contributed_outputs: Vec::new(), | ||
}; | ||
let channel_error = ChannelError::WarnAndDisconnect(format!( | ||
"Failed to start interactive transaction construction, {:?}", | ||
err | ||
)) | ||
)); | ||
(channel_error, splice_failed) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Likewise here.
fn is_initiator(&self) -> bool { | ||
match self { | ||
FundingNegotiation::AwaitingAck { context } => context.is_initiator, | ||
FundingNegotiation::ConstructingTransaction { interactive_tx_constructor, .. } => { | ||
interactive_tx_constructor.is_initiator() | ||
}, | ||
FundingNegotiation::AwaitingSignatures { is_initiator, .. } => *is_initiator, | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if there is a preferred way to go about this. It's nice being able to filter like is done in this commit and later fixups:
.filter(|funding_negotiation| funding_negotiation.is_initiator())
But it requires tracking is_initiator
both in InteractiveTxConstructor
and FundingNegotiation::AwaitingSignatures
, at least as currently written.
@@ -1848,6 +1848,7 @@ impl InteractiveTxInput { | |||
|
|||
pub(super) struct InteractiveTxConstructor { | |||
state_machine: StateMachine, | |||
is_initiator: bool, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be able to get this from the StateMachine
, but not if it transitioned to NegotiationAborted
, it seems.
contributed_inputs: Vec::new(), | ||
contributed_outputs: Vec::new(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One issue with populating these is if we are in FundingNegotiation::AwaitingSignatures
, then we'd need to get them from ChannelContext::interactive_tx_signing_session
, which may not have been set yet in FundedChannel::funding_tx_constructed
depending on the error.
lightning/src/ln/channel.rs
Outdated
let signing_session = interactive_tx_constructor.into_signing_session(); | ||
let commitment_signed = chan.context.funding_tx_constructed( | ||
let commitment_signed_result = chan.context.funding_tx_constructed( | ||
&mut funding, | ||
signing_session, | ||
true, | ||
chan.holder_commitment_point.next_transaction_number(), | ||
&&logger, | ||
)?; | ||
); | ||
|
||
// This must be set even if returning an Err. Otherwise, | ||
// fail_interactive_tx_negotiation won't produce a SpliceFailed event. | ||
pending_splice.funding_negotiation = | ||
Some(FundingNegotiation::AwaitingSignatures { funding }); | ||
|
||
return Ok(commitment_signed); | ||
return commitment_signed_result; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here, specifically, we may not have set ChannelContext::interactive_tx_signing_session
for some errors.
🔔 1st Reminder Hey @TheBlueMatt @wpaulino! This PR has been waiting for your review. |
1 similar comment
🔔 1st Reminder Hey @TheBlueMatt @wpaulino! This PR has been waiting for your review. |
When a splice has been negotiated, it remains pending until the funding transaction has been confirmed and locked by both sides. Emit an
Event::SplicePending
when it reaches this state. At this point, the inputs used for the splice cannot be reused except for an RBF attempt. Once the splice is locked, anEvent::DiscardFunding
will be emitted for any unsuccessful candidates.Similarly, a splice may fail before a splice has finished negotiation for various reasons. Emit an
Event::SpliceFailed
in these cases so the user may reuse the inputs.The commits were generated by Claude Code, so leaving the PR in draft for now.
TODO:
Event::SpliceFailed
with inputs and outputs.