Skip to content

Commit fc9dd39

Browse files
jkczyzclaude
andcommitted
Emit SplicePending event when splice funding is negotiated
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]>
1 parent 3f8c6b8 commit fc9dd39

File tree

2 files changed

+88
-17
lines changed

2 files changed

+88
-17
lines changed

lightning/src/ln/channel.rs

Lines changed: 47 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,21 @@ pub struct ChannelValueStat {
111111
pub counterparty_dust_limit_msat: u64,
112112
}
113113

114+
/// Information about a splice funding negotiation that has been completed.
115+
/// This is returned from channel operations and converted to an Event::SplicePending in ChannelManager.
116+
pub struct SpliceFundingNegotiated {
117+
/// The channel_id of the channel being spliced.
118+
pub channel_id: ChannelId,
119+
/// The counterparty's node_id.
120+
pub counterparty_node_id: PublicKey,
121+
/// The user_channel_id value.
122+
pub user_channel_id: u128,
123+
/// The outpoint of the channel's splice funding transaction.
124+
pub funding_txo: bitcoin::OutPoint,
125+
/// The features that this channel will operate with.
126+
pub channel_type: ChannelTypeFeatures,
127+
}
128+
114129
pub struct AvailableBalances {
115130
/// Total amount available for our counterparty to send to us.
116131
pub inbound_capacity_msat: u64,
@@ -8579,30 +8594,46 @@ where
85798594
}
85808595
}
85818596

8582-
fn on_tx_signatures_exchange(&mut self, funding_tx: Transaction) {
8597+
fn on_tx_signatures_exchange(&mut self, funding_tx: Transaction) -> Option<SpliceFundingNegotiated> {
85838598
debug_assert!(!self.context.channel_state.is_monitor_update_in_progress());
85848599
debug_assert!(!self.context.channel_state.is_awaiting_remote_revoke());
85858600

85868601
if let Some(pending_splice) = self.pending_splice.as_mut() {
8602+
self.context.channel_state.clear_quiescent();
85878603
if let Some(FundingNegotiation::AwaitingSignatures { mut funding }) =
85888604
pending_splice.funding_negotiation.take()
85898605
{
85908606
funding.funding_transaction = Some(funding_tx);
8607+
8608+
let funding_txo = funding.get_funding_txo().expect("funding outpoint should be set");
8609+
let channel_type = funding.get_channel_type().clone();
8610+
85918611
pending_splice.negotiated_candidates.push(funding);
8612+
8613+
let splice_negotiated = SpliceFundingNegotiated {
8614+
channel_id: self.context.channel_id,
8615+
counterparty_node_id: self.context.counterparty_node_id,
8616+
user_channel_id: self.context.user_id,
8617+
funding_txo: funding_txo.into_bitcoin_outpoint(),
8618+
channel_type,
8619+
};
8620+
8621+
Some(splice_negotiated)
85928622
} else {
85938623
debug_assert!(false);
8624+
None
85948625
}
8595-
self.context.channel_state.clear_quiescent();
85968626
} else {
85978627
self.funding.funding_transaction = Some(funding_tx);
85988628
self.context.channel_state =
85998629
ChannelState::AwaitingChannelReady(AwaitingChannelReadyFlags::new());
8630+
None
86008631
}
86018632
}
86028633

86038634
pub fn funding_transaction_signed(
86048635
&mut self, funding_txid_signed: Txid, witnesses: Vec<Witness>,
8605-
) -> Result<(Option<msgs::TxSignatures>, Option<Transaction>), APIError> {
8636+
) -> Result<(Option<msgs::TxSignatures>, Option<Transaction>, Option<SpliceFundingNegotiated>), APIError> {
86068637
let signing_session =
86078638
if let Some(signing_session) = self.context.interactive_tx_signing_session.as_mut() {
86088639
if let Some(pending_splice) = self.pending_splice.as_ref() {
@@ -8658,17 +8689,19 @@ where
86588689
.provide_holder_witnesses(tx_signatures, &self.context.secp_ctx)
86598690
.map_err(|err| APIError::APIMisuseError { err })?;
86608691

8661-
if let Some(funding_tx) = funding_tx_opt.clone() {
8692+
let splice_negotiated = if let Some(funding_tx) = funding_tx_opt.clone() {
86628693
debug_assert!(tx_signatures_opt.is_some());
8663-
self.on_tx_signatures_exchange(funding_tx);
8664-
}
8694+
self.on_tx_signatures_exchange(funding_tx)
8695+
} else {
8696+
None
8697+
};
86658698

8666-
Ok((tx_signatures_opt, funding_tx_opt))
8699+
Ok((tx_signatures_opt, funding_tx_opt, splice_negotiated))
86678700
}
86688701

86698702
pub fn tx_signatures(
86708703
&mut self, msg: &msgs::TxSignatures,
8671-
) -> Result<(Option<msgs::TxSignatures>, Option<Transaction>), ChannelError> {
8704+
) -> Result<(Option<msgs::TxSignatures>, Option<Transaction>, Option<SpliceFundingNegotiated>), ChannelError> {
86728705
let signing_session = if let Some(signing_session) =
86738706
self.context.interactive_tx_signing_session.as_mut()
86748707
{
@@ -8714,11 +8747,13 @@ where
87148747
let (holder_tx_signatures_opt, funding_tx_opt) =
87158748
signing_session.received_tx_signatures(msg).map_err(|msg| ChannelError::Warn(msg))?;
87168749

8717-
if let Some(funding_tx) = funding_tx_opt.clone() {
8718-
self.on_tx_signatures_exchange(funding_tx);
8719-
}
8750+
let splice_negotiated = if let Some(funding_tx) = funding_tx_opt.clone() {
8751+
self.on_tx_signatures_exchange(funding_tx)
8752+
} else {
8753+
None
8754+
};
87208755

8721-
Ok((holder_tx_signatures_opt, funding_tx_opt))
8756+
Ok((holder_tx_signatures_opt, funding_tx_opt, splice_negotiated))
87228757
}
87238758

87248759
/// Queues up an outbound update fee by placing it in the holding cell. You should call

lightning/src/ln/channelmanager.rs

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ use crate::ln::channel::QuiescentAction;
6161
use crate::ln::channel::{
6262
self, hold_time_since, Channel, ChannelError, ChannelUpdateStatus, FundedChannel,
6363
InboundV1Channel, OutboundV1Channel, PendingV2Channel, ReconnectionMsg, ShutdownResult,
64-
StfuResponse, UpdateFulfillCommitFetch, WithChannelContext,
64+
SpliceFundingNegotiated, StfuResponse, UpdateFulfillCommitFetch, WithChannelContext,
6565
};
6666
use crate::ln::channel_state::ChannelDetails;
6767
use crate::ln::funding::SpliceContribution;
@@ -6098,10 +6098,22 @@ where
60986098
.filter(|witness| !witness.is_empty())
60996099
.collect();
61006100
match chan.funding_transaction_signed(txid, witnesses) {
6101-
Ok((Some(tx_signatures), funding_tx_opt)) => {
6101+
Ok((Some(tx_signatures), funding_tx_opt, splice_negotiated)) => {
61026102
if let Some(funding_tx) = funding_tx_opt {
61036103
self.broadcast_interactive_funding(chan, &funding_tx);
61046104
}
6105+
if let Some(splice_negotiated) = splice_negotiated {
6106+
self.pending_events.lock().unwrap().push_back((
6107+
events::Event::SplicePending {
6108+
channel_id: splice_negotiated.channel_id,
6109+
counterparty_node_id: splice_negotiated.counterparty_node_id,
6110+
user_channel_id: splice_negotiated.user_channel_id,
6111+
funding_txo: splice_negotiated.funding_txo,
6112+
channel_type: splice_negotiated.channel_type,
6113+
},
6114+
None,
6115+
));
6116+
}
61056117
peer_state.pending_msg_events.push(
61066118
MessageSendEvent::SendTxSignatures {
61076119
node_id: *counterparty_node_id,
@@ -9154,16 +9166,28 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
91549166
} else {
91559167
let txid = signing_session.unsigned_tx().compute_txid();
91569168
match channel.funding_transaction_signed(txid, vec![]) {
9157-
Ok((Some(tx_signatures), funding_tx_opt)) => {
9169+
Ok((Some(tx_signatures), funding_tx_opt, splice_negotiated)) => {
91589170
if let Some(funding_tx) = funding_tx_opt {
91599171
self.broadcast_interactive_funding(channel, &funding_tx);
91609172
}
9173+
if let Some(splice_negotiated) = splice_negotiated {
9174+
self.pending_events.lock().unwrap().push_back((
9175+
events::Event::SplicePending {
9176+
channel_id: splice_negotiated.channel_id,
9177+
counterparty_node_id: splice_negotiated.counterparty_node_id,
9178+
user_channel_id: splice_negotiated.user_channel_id,
9179+
funding_txo: splice_negotiated.funding_txo,
9180+
channel_type: splice_negotiated.channel_type,
9181+
},
9182+
None,
9183+
));
9184+
}
91619185
pending_msg_events.push(MessageSendEvent::SendTxSignatures {
91629186
node_id: counterparty_node_id,
91639187
msg: tx_signatures,
91649188
});
91659189
},
9166-
Ok((None, _)) => {
9190+
Ok((None, _, _)) => {
91679191
debug_assert!(false, "If our tx_signatures is empty, then we should send it first!");
91689192
},
91699193
Err(err) => {
@@ -10109,7 +10133,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1010910133
hash_map::Entry::Occupied(mut chan_entry) => {
1011010134
match chan_entry.get_mut().as_funded_mut() {
1011110135
Some(chan) => {
10112-
let (tx_signatures_opt, funding_tx_opt) = try_channel_entry!(self, peer_state, chan.tx_signatures(msg), chan_entry);
10136+
let (tx_signatures_opt, funding_tx_opt, splice_negotiated) = try_channel_entry!(self, peer_state, chan.tx_signatures(msg), chan_entry);
1011310137
if let Some(tx_signatures) = tx_signatures_opt {
1011410138
peer_state.pending_msg_events.push(MessageSendEvent::SendTxSignatures {
1011510139
node_id: *counterparty_node_id,
@@ -10123,6 +10147,18 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1012310147
emit_channel_pending_event!(pending_events, chan);
1012410148
}
1012510149
}
10150+
if let Some(splice_negotiated) = splice_negotiated {
10151+
self.pending_events.lock().unwrap().push_back((
10152+
events::Event::SplicePending {
10153+
channel_id: splice_negotiated.channel_id,
10154+
counterparty_node_id: splice_negotiated.counterparty_node_id,
10155+
user_channel_id: splice_negotiated.user_channel_id,
10156+
funding_txo: splice_negotiated.funding_txo,
10157+
channel_type: splice_negotiated.channel_type,
10158+
},
10159+
None,
10160+
));
10161+
}
1012610162
},
1012710163
None => {
1012810164
let msg = "Got an unexpected tx_signatures message";

0 commit comments

Comments
 (0)