Skip to content

Commit 92fcdd3

Browse files
committed
Avoid early return upon confirmation of channel funding
This early return is only possible if the channel requires a single confirmation, allowing a `channel_ready` message to go out. This can be problematic though if a commitment transaction (specifically from the counterparty, as the channel would be immediately closed if a local commitment is broadcast) also confirms within the same block. The `ChannelMonitor` will detect both, but it won't inform the `ChannelManager` at all. Luckily, while the channel still is considered open to the `ChannelManager`, the `ChannelMonitor` will reject any further updates to the channel state.
1 parent 6016101 commit 92fcdd3

File tree

2 files changed

+60
-2
lines changed

2 files changed

+60
-2
lines changed

lightning/src/ln/channel.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4808,6 +4808,7 @@ impl<SP: Deref> Channel<SP> where
48084808
NS::Target: NodeSigner,
48094809
L::Target: Logger
48104810
{
4811+
let mut msgs = (None, None);
48114812
if let Some(funding_txo) = self.context.get_funding_txo() {
48124813
for &(index_in_block, tx) in txdata.iter() {
48134814
// Check if the transaction is the expected funding transaction, and if it is,
@@ -4863,7 +4864,7 @@ impl<SP: Deref> Channel<SP> where
48634864
if let Some(channel_ready) = self.check_get_channel_ready(height) {
48644865
log_info!(logger, "Sending a channel_ready to our peer for channel {}", &self.context.channel_id);
48654866
let announcement_sigs = self.get_announcement_sigs(node_signer, genesis_block_hash, user_config, height, logger);
4866-
return Ok((Some(channel_ready), announcement_sigs));
4867+
msgs = (Some(channel_ready), announcement_sigs);
48674868
}
48684869
}
48694870
for inp in tx.input.iter() {
@@ -4874,7 +4875,7 @@ impl<SP: Deref> Channel<SP> where
48744875
}
48754876
}
48764877
}
4877-
Ok((None, None))
4878+
Ok(msgs)
48784879
}
48794880

48804881
/// When a new block is connected, we check the height of the block against outbound holding

lightning/src/ln/functional_tests.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10625,3 +10625,60 @@ fn test_batch_funding_close_after_funding_signed() {
1062510625
// Ensure the channels don't exist anymore.
1062610626
assert!(nodes[0].node.list_channels().is_empty());
1062710627
}
10628+
10629+
fn do_test_funding_and_commitment_tx_confirm_same_block(confirm_remote_commitment: bool) {
10630+
// Tests that a node will forget the channel (when it only requires 1 confirmation) if the
10631+
// funding and commitment transaction confirm in the same block.
10632+
let chanmon_cfgs = create_chanmon_cfgs(2);
10633+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
10634+
let mut min_depth_1_block_cfg = test_default_channel_config();
10635+
min_depth_1_block_cfg.channel_handshake_config.minimum_depth = 1;
10636+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[Some(min_depth_1_block_cfg), Some(min_depth_1_block_cfg)]);
10637+
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
10638+
10639+
let funding_tx = create_chan_between_nodes_with_value_init(&nodes[0], &nodes[1], 1_000_000, 0);
10640+
let chan_id = chain::transaction::OutPoint { txid: funding_tx.txid(), index: 0 }.to_channel_id();
10641+
10642+
assert_eq!(nodes[0].node.list_channels().len(), 1);
10643+
assert_eq!(nodes[1].node.list_channels().len(), 1);
10644+
10645+
let (closing_node, other_node) = if confirm_remote_commitment {
10646+
(&nodes[1], &nodes[0])
10647+
} else {
10648+
(&nodes[0], &nodes[1])
10649+
};
10650+
10651+
closing_node.node.force_close_broadcasting_latest_txn(&chan_id, &other_node.node.get_our_node_id()).unwrap();
10652+
let mut msg_events = closing_node.node.get_and_clear_pending_msg_events();
10653+
assert_eq!(msg_events.len(), 1);
10654+
match msg_events.pop().unwrap() {
10655+
MessageSendEvent::HandleError { action: msgs::ErrorAction::SendErrorMessage { .. }, .. } => {},
10656+
_ => panic!("Unexpected event"),
10657+
}
10658+
check_added_monitors(closing_node, 1);
10659+
check_closed_event(closing_node, 1, ClosureReason::HolderForceClosed, false, &[other_node.node.get_our_node_id()], 1_000_000);
10660+
10661+
let commitment_tx = {
10662+
let mut txn = closing_node.tx_broadcaster.txn_broadcast();
10663+
assert_eq!(txn.len(), 1);
10664+
let commitment_tx = txn.pop().unwrap();
10665+
check_spends!(commitment_tx, funding_tx);
10666+
commitment_tx
10667+
};
10668+
10669+
mine_transactions(&nodes[0], &[&funding_tx, &commitment_tx]);
10670+
mine_transactions(&nodes[1], &[&funding_tx, &commitment_tx]);
10671+
10672+
check_closed_broadcast(other_node, 1, true);
10673+
check_added_monitors(other_node, 1);
10674+
check_closed_event(other_node, 1, ClosureReason::CommitmentTxConfirmed, false, &[closing_node.node.get_our_node_id()], 1_000_000);
10675+
10676+
assert!(nodes[0].node.list_channels().is_empty());
10677+
assert!(nodes[1].node.list_channels().is_empty());
10678+
}
10679+
10680+
#[test]
10681+
fn test_funding_and_commitment_tx_confirm_same_block() {
10682+
do_test_funding_and_commitment_tx_confirm_same_block(false);
10683+
do_test_funding_and_commitment_tx_confirm_same_block(true);
10684+
}

0 commit comments

Comments
 (0)