Skip to content

Commit f0a3029

Browse files
Merge pull request lightningdevkit#3034 from TheBlueMatt/2024-04-2982-123-fix
[0.0.123] Don't attempt to resume channels if we already exchanged funding
2 parents 8701b1b + 21ab2dc commit f0a3029

File tree

3 files changed

+50
-9
lines changed

3 files changed

+50
-9
lines changed

lightning/src/ln/channel.rs

+6
Original file line numberDiff line numberDiff line change
@@ -7456,6 +7456,12 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
74567456
Ok(self.get_open_channel(chain_hash))
74577457
}
74587458

7459+
/// Returns true if we can resume the channel by sending the [`msgs::OpenChannel`] again.
7460+
pub fn is_resumable(&self) -> bool {
7461+
!self.context.have_received_message() &&
7462+
self.context.cur_holder_commitment_transaction_number == INITIAL_COMMITMENT_NUMBER
7463+
}
7464+
74597465
pub fn get_open_channel(&self, chain_hash: ChainHash) -> msgs::OpenChannel {
74607466
if !self.context.is_outbound() {
74617467
panic!("Tried to open a channel for an inbound channel?");

lightning/src/ln/channelmanager.rs

+8-5
Original file line numberDiff line numberDiff line change
@@ -9943,11 +9943,14 @@ where
99439943
}
99449944
&mut chan.context
99459945
},
9946-
// We retain UnfundedOutboundV1 channel for some time in case
9947-
// peer unexpectedly disconnects, and intends to reconnect again.
9948-
ChannelPhase::UnfundedOutboundV1(_) => {
9949-
return true;
9950-
},
9946+
// If we get disconnected and haven't yet committed to a funding
9947+
// transaction, we can replay the `open_channel` on reconnection, so don't
9948+
// bother dropping the channel here. However, if we already committed to
9949+
// the funding transaction we don't yet support replaying the funding
9950+
// handshake (and bailing if the peer rejects it), so we force-close in
9951+
// that case.
9952+
ChannelPhase::UnfundedOutboundV1(chan) if chan.is_resumable() => return true,
9953+
ChannelPhase::UnfundedOutboundV1(chan) => &mut chan.context,
99519954
// Unfunded inbound channels will always be removed.
99529955
ChannelPhase::UnfundedInboundV1(chan) => {
99539956
&mut chan.context

lightning/src/ln/functional_tests.rs

+36-4
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,38 @@ use crate::ln::chan_utils::CommitmentTransaction;
6161

6262
use super::channel::UNFUNDED_CHANNEL_AGE_LIMIT_TICKS;
6363

64+
#[test]
65+
fn test_channel_resumption_fail_post_funding() {
66+
// If we fail to exchange funding with a peer prior to it disconnecting we'll resume the
67+
// channel open on reconnect, however if we do exchange funding we do not currently support
68+
// replaying it and here test that the channel closes.
69+
let chanmon_cfgs = create_chanmon_cfgs(2);
70+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
71+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
72+
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
73+
74+
nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 1_000_000, 0, 42, None, None).unwrap();
75+
let open_chan = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
76+
nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), &open_chan);
77+
let accept_chan = get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id());
78+
nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), &accept_chan);
79+
80+
let (temp_chan_id, tx, funding_output) =
81+
create_funding_transaction(&nodes[0], &nodes[1].node.get_our_node_id(), 1_000_000, 42);
82+
let new_chan_id = ChannelId::v1_from_funding_outpoint(funding_output);
83+
nodes[0].node.funding_transaction_generated(&temp_chan_id, &nodes[1].node.get_our_node_id(), tx).unwrap();
84+
85+
nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id());
86+
check_closed_events(&nodes[0], &[ExpectedCloseEvent::from_id_reason(new_chan_id, true, ClosureReason::DisconnectedPeer)]);
87+
88+
// After ddf75afd16 we'd panic on reconnection if we exchanged funding info, so test that
89+
// explicitly here.
90+
nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init {
91+
features: nodes[1].node.init_features(), networks: None, remote_network_address: None
92+
}, true).unwrap();
93+
assert_eq!(nodes[0].node.get_and_clear_pending_msg_events(), Vec::new());
94+
}
95+
6496
#[test]
6597
fn test_insane_channel_opens() {
6698
// Stand up a network of 2 nodes
@@ -3734,10 +3766,10 @@ fn test_peer_disconnected_before_funding_broadcasted() {
37343766
nodes[0].node.timer_tick_occurred();
37353767
}
37363768

3737-
// Ensure that the channel is closed with `ClosureReason::HolderForceClosed`
3738-
// when the peers are disconnected and do not reconnect before the funding
3739-
// transaction is broadcasted.
3740-
check_closed_event!(&nodes[0], 2, ClosureReason::HolderForceClosed, true
3769+
// Ensure that the channel is closed with `ClosureReason::DisconnectedPeer` and a
3770+
// `DiscardFunding` event when the peers are disconnected and do not reconnect before the
3771+
// funding transaction is broadcasted.
3772+
check_closed_event!(&nodes[0], 2, ClosureReason::DisconnectedPeer, true
37413773
, [nodes[1].node.get_our_node_id()], 1000000);
37423774
check_closed_event!(&nodes[1], 1, ClosureReason::DisconnectedPeer, false
37433775
, [nodes[0].node.get_our_node_id()], 1000000);

0 commit comments

Comments
 (0)