Skip to content

Commit 59dc3ca

Browse files
committed
Emit SplicePending event when splice funding is negotiated
Once a splice has been negotiated and its funding transaction has been broadcast, emit a SplicePending event. Once this occurs, the inputs contributed to the splice cannot be reused except by an RBF attempt.
1 parent 8e62b20 commit 59dc3ca

File tree

4 files changed

+147
-41
lines changed

4 files changed

+147
-41
lines changed

lightning/src/ln/channel.rs

Lines changed: 58 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6718,6 +6718,27 @@ type BestBlockUpdatedRes = (
67186718
Option<msgs::AnnouncementSignatures>,
67196719
);
67206720

6721+
/// The result of signing a funding transaction negotiated using the interactive-tx protocol.
6722+
pub struct FundingTxSigned {
6723+
/// Signatures that should be sent to the counterparty, if necessary.
6724+
pub tx_signatures: Option<msgs::TxSignatures>,
6725+
6726+
/// The fully-signed funding transaction to be broadcast.
6727+
pub funding_tx: Option<Transaction>,
6728+
6729+
/// Information about the completed funding negotiation.
6730+
pub splice_negotiated: Option<SpliceFundingNegotiated>,
6731+
}
6732+
6733+
/// Information about a splice funding negotiation that has been completed.
6734+
pub struct SpliceFundingNegotiated {
6735+
/// The outpoint of the channel's splice funding transaction.
6736+
pub funding_txo: bitcoin::OutPoint,
6737+
6738+
/// The features that this channel will operate with.
6739+
pub channel_type: ChannelTypeFeatures,
6740+
}
6741+
67216742
pub struct SpliceFundingPromotion {
67226743
pub funding_txo: OutPoint,
67236744
pub monitor_update: Option<ChannelMonitorUpdate>,
@@ -8636,30 +8657,46 @@ where
86368657
}
86378658
}
86388659

8639-
fn on_tx_signatures_exchange(&mut self, funding_tx: Transaction) {
8660+
fn on_tx_signatures_exchange(
8661+
&mut self, funding_tx: Transaction,
8662+
) -> Option<SpliceFundingNegotiated> {
86408663
debug_assert!(!self.context.channel_state.is_monitor_update_in_progress());
86418664
debug_assert!(!self.context.channel_state.is_awaiting_remote_revoke());
86428665

86438666
if let Some(pending_splice) = self.pending_splice.as_mut() {
8667+
self.context.channel_state.clear_quiescent();
86448668
if let Some(FundingNegotiation::AwaitingSignatures { mut funding }) =
86458669
pending_splice.funding_negotiation.take()
86468670
{
86478671
funding.funding_transaction = Some(funding_tx);
8672+
8673+
let funding_txo =
8674+
funding.get_funding_txo().expect("funding outpoint should be set");
8675+
let channel_type = funding.get_channel_type().clone();
8676+
86488677
pending_splice.negotiated_candidates.push(funding);
8678+
8679+
let splice_negotiated = SpliceFundingNegotiated {
8680+
funding_txo: funding_txo.into_bitcoin_outpoint(),
8681+
channel_type,
8682+
};
8683+
8684+
Some(splice_negotiated)
86498685
} else {
86508686
debug_assert!(false);
8687+
None
86518688
}
8652-
self.context.channel_state.clear_quiescent();
86538689
} else {
86548690
self.funding.funding_transaction = Some(funding_tx);
86558691
self.context.channel_state =
86568692
ChannelState::AwaitingChannelReady(AwaitingChannelReadyFlags::new());
8693+
None
86578694
}
86588695
}
86598696

86608697
pub fn funding_transaction_signed(
86618698
&mut self, funding_txid_signed: Txid, witnesses: Vec<Witness>,
8662-
) -> Result<(Option<msgs::TxSignatures>, Option<Transaction>), APIError> {
8699+
) -> Result<FundingTxSigned, APIError> {
86638700
let signing_session =
86648701
if let Some(signing_session) = self.context.interactive_tx_signing_session.as_mut() {
86658702
if let Some(pending_splice) = self.pending_splice.as_ref() {
@@ -8676,15 +8713,15 @@ where
86768713
if signing_session.holder_tx_signatures().is_some() {
86778714
// Our `tx_signatures` either should've been the first time we processed them,
86788715
// or we're waiting for our counterparty to send theirs first.
8679-
return Ok((None, None));
8716+
return Ok(FundingTxSigned { tx_signatures: None, funding_tx: None, splice_negotiated: None });
86808717
}
86818718

86828719
signing_session
86838720
} else {
86848721
if Some(funding_txid_signed) == self.funding.get_funding_txid() {
86858722
// We may be handling a duplicate call and the funding was already locked so we
86868723
// no longer have the signing session present.
8687-
return Ok((None, None));
8724+
return Ok(FundingTxSigned { tx_signatures: None, funding_tx: None, splice_negotiated: None });
86888725
}
86898726
let err =
86908727
format!("Channel {} not expecting funding signatures", self.context.channel_id);
@@ -8722,21 +8759,23 @@ where
87228759
witnesses,
87238760
shared_input_signature,
87248761
};
8725-
let (tx_signatures_opt, funding_tx_opt) = signing_session
8762+
let (tx_signatures, funding_tx) = signing_session
87268763
.provide_holder_witnesses(tx_signatures, &self.context.secp_ctx)
87278764
.map_err(|err| APIError::APIMisuseError { err })?;
87288765

8729-
if let Some(funding_tx) = funding_tx_opt.clone() {
8730-
debug_assert!(tx_signatures_opt.is_some());
8731-
self.on_tx_signatures_exchange(funding_tx);
8732-
}
8766+
let splice_negotiated = if let Some(funding_tx) = funding_tx.clone() {
8767+
debug_assert!(tx_signatures.is_some());
8768+
self.on_tx_signatures_exchange(funding_tx)
8769+
} else {
8770+
None
8771+
};
87338772

8734-
Ok((tx_signatures_opt, funding_tx_opt))
8773+
Ok(FundingTxSigned { tx_signatures, funding_tx, splice_negotiated })
87358774
}
87368775

87378776
pub fn tx_signatures(
87388777
&mut self, msg: &msgs::TxSignatures,
8739-
) -> Result<(Option<msgs::TxSignatures>, Option<Transaction>), ChannelError> {
8778+
) -> Result<FundingTxSigned, ChannelError> {
87408779
let signing_session = if let Some(signing_session) =
87418780
self.context.interactive_tx_signing_session.as_mut()
87428781
{
@@ -8779,14 +8818,16 @@ where
87798818
}
87808819
}
87818820

8782-
let (holder_tx_signatures_opt, funding_tx_opt) =
8821+
let (holder_tx_signatures, funding_tx) =
87838822
signing_session.received_tx_signatures(msg).map_err(|msg| ChannelError::Warn(msg))?;
87848823

8785-
if let Some(funding_tx) = funding_tx_opt.clone() {
8786-
self.on_tx_signatures_exchange(funding_tx);
8787-
}
8824+
let splice_negotiated = if let Some(funding_tx) = funding_tx.clone() {
8825+
self.on_tx_signatures_exchange(funding_tx)
8826+
} else {
8827+
None
8828+
};
87888829

8789-
Ok((holder_tx_signatures_opt, funding_tx_opt))
8830+
Ok(FundingTxSigned { tx_signatures: holder_tx_signatures, funding_tx, splice_negotiated })
87908831
}
87918832

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

lightning/src/ln/channelmanager.rs

Lines changed: 65 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,8 @@ use crate::ln::chan_utils::selected_commitment_sat_per_1000_weight;
6060
use crate::ln::channel::QuiescentAction;
6161
use crate::ln::channel::{
6262
self, hold_time_since, Channel, ChannelError, ChannelUpdateStatus, FundedChannel,
63-
InboundV1Channel, OutboundV1Channel, PendingV2Channel, ReconnectionMsg, ShutdownResult,
64-
StfuResponse, UpdateFulfillCommitFetch, WithChannelContext,
63+
FundingTxSigned, InboundV1Channel, OutboundV1Channel, PendingV2Channel, ReconnectionMsg,
64+
ShutdownResult, StfuResponse, UpdateFulfillCommitFetch, WithChannelContext,
6565
};
6666
use crate::ln::channel_state::ChannelDetails;
6767
use crate::ln::funding::SpliceContribution;
@@ -6298,10 +6298,26 @@ where
62986298
.filter(|witness| !witness.is_empty())
62996299
.collect();
63006300
match chan.funding_transaction_signed(txid, witnesses) {
6301-
Ok((Some(tx_signatures), funding_tx_opt)) => {
6302-
if let Some(funding_tx) = funding_tx_opt {
6301+
Ok(FundingTxSigned {
6302+
tx_signatures: Some(tx_signatures),
6303+
funding_tx,
6304+
splice_negotiated,
6305+
}) => {
6306+
if let Some(funding_tx) = funding_tx {
63036307
self.broadcast_interactive_funding(chan, &funding_tx);
63046308
}
6309+
if let Some(splice_negotiated) = splice_negotiated {
6310+
self.pending_events.lock().unwrap().push_back((
6311+
events::Event::SplicePending {
6312+
channel_id: *channel_id,
6313+
counterparty_node_id: *counterparty_node_id,
6314+
user_channel_id: chan.context.get_user_id(),
6315+
new_funding_txo: splice_negotiated.funding_txo,
6316+
channel_type: splice_negotiated.channel_type,
6317+
},
6318+
None,
6319+
));
6320+
}
63056321
peer_state.pending_msg_events.push(
63066322
MessageSendEvent::SendTxSignatures {
63076323
node_id: *counterparty_node_id,
@@ -6314,7 +6330,13 @@ where
63146330
result = Err(err);
63156331
return NotifyOption::SkipPersistNoEvents;
63166332
},
6317-
_ => {
6333+
Ok(FundingTxSigned {
6334+
tx_signatures: None,
6335+
funding_tx,
6336+
splice_negotiated,
6337+
}) => {
6338+
debug_assert!(funding_tx.is_none());
6339+
debug_assert!(splice_negotiated.is_none());
63186340
return NotifyOption::SkipPersistNoEvents;
63196341
},
63206342
}
@@ -9413,18 +9435,32 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
94139435
} else {
94149436
let txid = signing_session.unsigned_tx().compute_txid();
94159437
match channel.funding_transaction_signed(txid, vec![]) {
9416-
Ok((Some(tx_signatures), funding_tx_opt)) => {
9417-
if let Some(funding_tx) = funding_tx_opt {
9438+
Ok(FundingTxSigned { tx_signatures: Some(tx_signatures), funding_tx, splice_negotiated }) => {
9439+
if let Some(funding_tx) = funding_tx {
94189440
self.broadcast_interactive_funding(channel, &funding_tx);
94199441
}
9442+
9443+
if let Some(splice_negotiated) = splice_negotiated {
9444+
self.pending_events.lock().unwrap().push_back((
9445+
events::Event::SplicePending {
9446+
channel_id: channel.context.channel_id(),
9447+
counterparty_node_id,
9448+
user_channel_id: channel.context.get_user_id(),
9449+
new_funding_txo: splice_negotiated.funding_txo,
9450+
channel_type: splice_negotiated.channel_type,
9451+
},
9452+
None,
9453+
));
9454+
}
9455+
94209456
if channel.context.is_connected() {
94219457
pending_msg_events.push(MessageSendEvent::SendTxSignatures {
94229458
node_id: counterparty_node_id,
94239459
msg: tx_signatures,
94249460
});
94259461
}
94269462
},
9427-
Ok((None, _)) => {
9463+
Ok(FundingTxSigned { tx_signatures: None, .. }) => {
94289464
debug_assert!(false, "If our tx_signatures is empty, then we should send it first!");
94299465
},
94309466
Err(err) => {
@@ -10373,20 +10409,33 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1037310409
hash_map::Entry::Occupied(mut chan_entry) => {
1037410410
match chan_entry.get_mut().as_funded_mut() {
1037510411
Some(chan) => {
10376-
let (tx_signatures_opt, funding_tx_opt) = try_channel_entry!(self, peer_state, chan.tx_signatures(msg), chan_entry);
10377-
if let Some(tx_signatures) = tx_signatures_opt {
10412+
let FundingTxSigned { tx_signatures, funding_tx, splice_negotiated } =
10413+
try_channel_entry!(self, peer_state, chan.tx_signatures(msg), chan_entry);
10414+
if let Some(tx_signatures) = tx_signatures {
1037810415
peer_state.pending_msg_events.push(MessageSendEvent::SendTxSignatures {
1037910416
node_id: *counterparty_node_id,
1038010417
msg: tx_signatures,
1038110418
});
1038210419
}
10383-
if let Some(ref funding_tx) = funding_tx_opt {
10420+
if let Some(ref funding_tx) = funding_tx {
1038410421
self.tx_broadcaster.broadcast_transactions(&[funding_tx]);
1038510422
{
1038610423
let mut pending_events = self.pending_events.lock().unwrap();
1038710424
emit_channel_pending_event!(pending_events, chan);
1038810425
}
1038910426
}
10427+
if let Some(splice_negotiated) = splice_negotiated {
10428+
self.pending_events.lock().unwrap().push_back((
10429+
events::Event::SplicePending {
10430+
channel_id: msg.channel_id,
10431+
counterparty_node_id: *counterparty_node_id,
10432+
user_channel_id: chan.context.get_user_id(),
10433+
new_funding_txo: splice_negotiated.funding_txo,
10434+
channel_type: splice_negotiated.channel_type,
10435+
},
10436+
None,
10437+
));
10438+
}
1039010439
},
1039110440
None => {
1039210441
let msg = "Got an unexpected tx_signatures message";
@@ -11337,7 +11386,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1133711386
}
1133811387

1133911388
#[rustfmt::skip]
11340-
fn internal_channel_reestablish(&self, counterparty_node_id: &PublicKey, msg: &msgs::ChannelReestablish) -> Result<NotifyOption, MsgHandleErrInternal> {
11389+
fn internal_channel_reestablish(&self, counterparty_node_id: &PublicKey, msg: &msgs::ChannelReestablish) -> Result<(), MsgHandleErrInternal> {
1134111390
let (inferred_splice_locked, need_lnd_workaround) = {
1134211391
let per_peer_state = self.per_peer_state.read().unwrap();
1134311392

@@ -11448,10 +11497,9 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1144811497

1144911498
if let Some(splice_locked) = inferred_splice_locked {
1145011499
self.internal_splice_locked(counterparty_node_id, &splice_locked)?;
11451-
return Ok(NotifyOption::DoPersist);
1145211500
}
1145311501

11454-
Ok(NotifyOption::SkipPersistHandleEvents)
11502+
Ok(())
1145511503
}
1145611504

1145711505
/// Handle incoming splice request, transition channel to splice-pending (unless some check fails).
@@ -14563,16 +14611,9 @@ where
1456314611
fn handle_channel_reestablish(
1456414612
&self, counterparty_node_id: PublicKey, msg: &msgs::ChannelReestablish,
1456514613
) {
14566-
let _persistence_guard = PersistenceNotifierGuard::optionally_notify(self, || {
14567-
let res = self.internal_channel_reestablish(&counterparty_node_id, msg);
14568-
let persist = match &res {
14569-
Err(e) if e.closes_channel() => NotifyOption::DoPersist,
14570-
Err(_) => NotifyOption::SkipPersistHandleEvents,
14571-
Ok(persist) => *persist,
14572-
};
14573-
let _ = handle_error!(self, res, counterparty_node_id);
14574-
persist
14575-
});
14614+
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
14615+
let res = self.internal_channel_reestablish(&counterparty_node_id, msg);
14616+
let _ = handle_error!(self, res, counterparty_node_id);
1457614617
}
1457714618

1457814619
#[rustfmt::skip]

lightning/src/ln/functional_test_utils.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3067,6 +3067,21 @@ pub fn expect_channel_ready_event<'a, 'b, 'c, 'd>(
30673067
}
30683068
}
30693069

3070+
#[cfg(any(test, ldk_bench, feature = "_test_utils"))]
3071+
pub fn expect_splice_pending_event<'a, 'b, 'c, 'd>(
3072+
node: &'a Node<'b, 'c, 'd>, expected_counterparty_node_id: &PublicKey,
3073+
) -> ChannelId {
3074+
let events = node.node.get_and_clear_pending_events();
3075+
assert_eq!(events.len(), 1);
3076+
match &events[0] {
3077+
crate::events::Event::SplicePending { channel_id, counterparty_node_id, .. } => {
3078+
assert_eq!(*expected_counterparty_node_id, *counterparty_node_id);
3079+
*channel_id
3080+
},
3081+
_ => panic!("Unexpected event"),
3082+
}
3083+
}
3084+
30703085
pub fn expect_probe_successful_events(
30713086
node: &Node, mut probe_results: Vec<(PaymentHash, PaymentId)>,
30723087
) {

lightning/src/ln/splicing_tests.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,9 @@ fn splice_channel<'a, 'b, 'c, 'd>(
246246
initiator: &'a Node<'b, 'c, 'd>, acceptor: &'a Node<'b, 'c, 'd>, channel_id: ChannelId,
247247
initiator_contribution: SpliceContribution,
248248
) -> Transaction {
249+
let node_id_initiator = initiator.node.get_our_node_id();
250+
let node_id_acceptor = acceptor.node.get_our_node_id();
251+
249252
let initial_commit_sig_for_acceptor =
250253
negotiate_splice_tx(initiator, acceptor, channel_id, initiator_contribution);
251254
sign_interactive_funding_transaction(initiator, acceptor, initial_commit_sig_for_acceptor);
@@ -257,6 +260,10 @@ fn splice_channel<'a, 'b, 'c, 'd>(
257260
assert_eq!(initiator_txn, acceptor_txn);
258261
initiator_txn.remove(0)
259262
};
263+
264+
expect_splice_pending_event(initiator, &node_id_acceptor);
265+
expect_splice_pending_event(acceptor, &node_id_initiator);
266+
260267
splice_tx
261268
}
262269

@@ -939,11 +946,13 @@ fn do_test_splice_reestablish(reload: bool, async_monitor_update: bool) {
939946
nodes[0].node.funding_transaction_signed(&channel_id, &node_id_1, tx).unwrap();
940947
}
941948
let _ = get_event_msg!(nodes[0], MessageSendEvent::SendTxSignatures, node_id_1);
949+
expect_splice_pending_event(&nodes[0], &node_id_1);
942950

943951
// Reconnect to make sure node 0 retransmits its `tx_signatures` as it was never delivered.
944952
reconnect_nodes!(|reconnect_args: &mut ReconnectArgs| {
945953
reconnect_args.send_interactive_tx_sigs = (false, true);
946954
});
955+
expect_splice_pending_event(&nodes[1], &node_id_0);
947956

948957
// Reestablish the channel again to make sure node 0 doesn't retransmit `tx_signatures`
949958
// unnecessarily as it was delivered in the previous reestablishment.

0 commit comments

Comments
 (0)