Skip to content

Commit 294fbba

Browse files
committed
Send splice_locked for promoted splice on reconnect
When a splice confirms after our `channel_reestablish` was generated and sent, but prior to processing the counterparty's, we may promote the splice and clear `pending_splice`. In such cases, we're still required to send an explicit `splice_locked` as the `channel_reestablish` we sent did not consider the splice confirmation.
1 parent bb597dd commit 294fbba

2 files changed

Lines changed: 107 additions & 0 deletions

File tree

lightning/src/ln/channel.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10784,6 +10784,19 @@ where
1078410784
channel_id: self.context.channel_id,
1078510785
splice_txid,
1078610786
})
10787+
}).or_else(|| {
10788+
// If a splice confirms after we've sent `channel_reestablish` but before we've received
10789+
// theirs, we may promote the splice and clear `pending_splice`. We still need to send
10790+
// `splice_locked` after reestablishing as it was not included in our
10791+
// `channel_reestablish`.
10792+
let current_funding_txid = self.funding.get_funding_txid()?;
10793+
(self.pending_splice.is_none()
10794+
&& self.funding.channel_transaction_parameters.splice_parent_funding_txid.is_some()
10795+
&& Some(current_funding_txid) != funding_locked_txid_sent_in_reestablish)
10796+
.then(|| msgs::SpliceLocked {
10797+
channel_id: self.context.channel_id,
10798+
splice_txid: current_funding_txid,
10799+
})
1078710800
});
1078810801

1078910802
if msg.next_local_commitment_number == next_counterparty_commitment_number {

lightning/src/ln/splicing_tests.rs

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2676,6 +2676,100 @@ fn test_splice_locked_waits_for_channel_reestablish() {
26762676
send_payment(&nodes[0], &[&nodes[1]], 1_000_000);
26772677
}
26782678

2679+
#[test]
2680+
fn test_promoted_splice_locked_sent_after_channel_reestablish() {
2681+
// Test that a splice gets promoted for both nodes if one of the nodes sees the splice lock
2682+
// before reestablishment and the other after.
2683+
let chanmon_cfgs = create_chanmon_cfgs(2);
2684+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
2685+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
2686+
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
2687+
2688+
let node_id_0 = nodes[0].node.get_our_node_id();
2689+
let node_id_1 = nodes[1].node.get_our_node_id();
2690+
2691+
let initial_channel_value_sat = 100_000;
2692+
let (_, _, channel_id, _) =
2693+
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, initial_channel_value_sat, 0);
2694+
let prev_funding_txo = get_monitor!(nodes[0], channel_id).get_funding_txo();
2695+
2696+
send_payment(&nodes[0], &[&nodes[1]], 1_000_000);
2697+
2698+
let outputs = vec![
2699+
TxOut {
2700+
value: Amount::from_sat(initial_channel_value_sat / 4),
2701+
script_pubkey: nodes[0].wallet_source.get_change_script().unwrap(),
2702+
},
2703+
TxOut {
2704+
value: Amount::from_sat(initial_channel_value_sat / 4),
2705+
script_pubkey: nodes[1].wallet_source.get_change_script().unwrap(),
2706+
},
2707+
];
2708+
let funding_contribution =
2709+
initiate_splice_out(&nodes[0], &nodes[1], channel_id, outputs).unwrap();
2710+
let (splice_tx, _) = splice_channel(&nodes[0], &nodes[1], channel_id, funding_contribution);
2711+
2712+
// Confirm the splice for node 0 first. This should result in them sending `splice_locked`, but
2713+
// node 1 should not send it back yet as it hasn't seen the confirmation.
2714+
confirm_transaction(&nodes[0], &splice_tx);
2715+
let splice_locked_0 = get_event_msg!(nodes[0], MessageSendEvent::SendSpliceLocked, node_id_1);
2716+
nodes[1].node.handle_splice_locked(node_id_0, &splice_locked_0);
2717+
assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
2718+
2719+
// Reconnect the peers.
2720+
nodes[0].node.peer_disconnected(node_id_1);
2721+
nodes[1].node.peer_disconnected(node_id_0);
2722+
connect_nodes(&nodes[0], &nodes[1]);
2723+
let reestablish_0 =
2724+
get_event_msg!(nodes[0], MessageSendEvent::SendChannelReestablish, node_id_1);
2725+
let reestablish_1 =
2726+
get_event_msg!(nodes[1], MessageSendEvent::SendChannelReestablish, node_id_0);
2727+
2728+
// Before delivering the reestablish message to each other, confirm the splice for node 1. We
2729+
// should see a `ChannelReady` event for node 1 as the pending splice should have been promoted,
2730+
// but `splice_locked` should not be sent until it receives node 0's reestablish.
2731+
confirm_transaction(&nodes[1], &splice_tx);
2732+
check_added_monitors(&nodes[1], 1);
2733+
let new_funding_txo =
2734+
get_monitor!(nodes[1], channel_id).get_funding_txo().into_bitcoin_outpoint();
2735+
let channel_ready_1 = get_event!(&nodes[1], Event::ChannelReady);
2736+
assert!(matches!(
2737+
channel_ready_1, Event::ChannelReady { funding_txo, .. }
2738+
if funding_txo == Some(new_funding_txo)
2739+
));
2740+
2741+
nodes[1].node.handle_channel_reestablish(node_id_0, &reestablish_0);
2742+
let msg_events = nodes[1].node.get_and_clear_pending_msg_events();
2743+
assert_eq!(msg_events.len(), 3, "{msg_events:?}");
2744+
assert!(matches!(&msg_events[0], MessageSendEvent::SendAnnouncementSignatures { .. }));
2745+
let splice_locked_1 = if let MessageSendEvent::SendSpliceLocked { msg, .. } = &msg_events[1] {
2746+
msg
2747+
} else {
2748+
panic!("Unexpected event {:?}", msg_events[0]);
2749+
};
2750+
assert!(matches!(&msg_events[2], MessageSendEvent::SendChannelUpdate { .. }));
2751+
2752+
// Deliver node 1's reestablish to node 0. Since it was generated prior to the splice
2753+
// confirmation, it should not promote the splice for node 0 yet.
2754+
nodes[0].node.handle_channel_reestablish(node_id_1, &reestablish_1);
2755+
let _ = get_event_msg!(nodes[0], MessageSendEvent::SendChannelUpdate, node_id_1);
2756+
2757+
// Deliver node 1's splice locked to node 0, allowing the splice to be promoted on node 0's side
2758+
// as well.
2759+
nodes[0].node.handle_splice_locked(node_id_1, splice_locked_1);
2760+
check_added_monitors(&nodes[0], 1);
2761+
let _ = get_event_msg!(nodes[0], MessageSendEvent::SendAnnouncementSignatures, node_id_1);
2762+
let channel_ready_0 = get_event!(&nodes[0], Event::ChannelReady);
2763+
assert!(matches!(
2764+
channel_ready_0, Event::ChannelReady { funding_txo, .. }
2765+
if funding_txo == Some(new_funding_txo)
2766+
));
2767+
2768+
for node in [&nodes[0], &nodes[1]] {
2769+
node.chain_source.remove_watched_by_txid(prev_funding_txo.txid);
2770+
}
2771+
}
2772+
26792773
#[test]
26802774
fn test_splice_reestablish_waits_for_holder_tx_signatures_before_commitment_signed() {
26812775
let chanmon_cfgs = create_chanmon_cfgs(2);

0 commit comments

Comments
 (0)