+
+#[test]
+fn test_batch_channel_open() {
+ let chanmon_cfgs = create_chanmon_cfgs(3);
+ let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
+ let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
+ let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
+
+ // Initiate channel opening and create the batch channel funding transaction.
+ let (tx, funding_created_msgs) = create_batch_channel_funding(&nodes[0], &[
+ (&nodes[1], 100_000, 0, 42, None),
+ (&nodes[2], 200_000, 0, 43, None),
+ ]);
+
+ // Go through the funding_created and funding_signed flow with node 1.
+ nodes[1].node.handle_funding_created(&nodes[0].node.get_our_node_id(), &funding_created_msgs[0]);
+ check_added_monitors(&nodes[1], 1);
+ expect_channel_pending_event(&nodes[1], &nodes[0].node.get_our_node_id());
+
+ let funding_signed_msg = get_event_msg!(nodes[1], MessageSendEvent::SendFundingSigned, nodes[0].node.get_our_node_id());
+ nodes[0].node.handle_funding_signed(&nodes[1].node.get_our_node_id(), &funding_signed_msg);
+ check_added_monitors(&nodes[0], 1);
+
+ // The transaction should not have been broadcast before all channels are ready.
+ assert_eq!(nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().len(), 0);
+
+ // Go through the funding_created and funding_signed flow with node 2.
+ nodes[2].node.handle_funding_created(&nodes[0].node.get_our_node_id(), &funding_created_msgs[1]);
+ check_added_monitors(&nodes[2], 1);
+ expect_channel_pending_event(&nodes[2], &nodes[0].node.get_our_node_id());
+
+ let funding_signed_msg = get_event_msg!(nodes[2], MessageSendEvent::SendFundingSigned, nodes[0].node.get_our_node_id());
+ chanmon_cfgs[0].persister.set_update_ret(ChannelMonitorUpdateStatus::InProgress);
+ nodes[0].node.handle_funding_signed(&nodes[2].node.get_our_node_id(), &funding_signed_msg);
+ check_added_monitors(&nodes[0], 1);
+
+ // The transaction should not have been broadcast before persisting all monitors has been
+ // completed.
+ assert_eq!(nodes[0].tx_broadcaster.txn_broadcast().len(), 0);
+ assert_eq!(nodes[0].node.get_and_clear_pending_events().len(), 0);
+
+ // Complete the persistence of the monitor.
+ nodes[0].chain_monitor.complete_sole_pending_chan_update(
+ &OutPoint { txid: tx.txid(), index: 1 }.to_channel_id()
+ );
+ let events = nodes[0].node.get_and_clear_pending_events();
+
+ // The transaction should only have been broadcast now.
+ let broadcasted_txs = nodes[0].tx_broadcaster.txn_broadcast();
+ assert_eq!(broadcasted_txs.len(), 1);
+ assert_eq!(broadcasted_txs[0], tx);
+
+ assert_eq!(events.len(), 2);
+ assert!(events.iter().any(|e| matches!(
+ *e,
+ crate::events::Event::ChannelPending {
+ ref counterparty_node_id,
+ ..
+ } if counterparty_node_id == &nodes[1].node.get_our_node_id(),
+ )));
+ assert!(events.iter().any(|e| matches!(
+ *e,
+ crate::events::Event::ChannelPending {
+ ref counterparty_node_id,
+ ..
+ } if counterparty_node_id == &nodes[2].node.get_our_node_id(),
+ )));
+}
+
+#[test]
+fn test_disconnect_in_funding_batch() {
+ let chanmon_cfgs = create_chanmon_cfgs(3);
+ let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
+ let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
+ let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
+
+ // Initiate channel opening and create the batch channel funding transaction.
+ let (tx, funding_created_msgs) = create_batch_channel_funding(&nodes[0], &[
+ (&nodes[1], 100_000, 0, 42, None),
+ (&nodes[2], 200_000, 0, 43, None),
+ ]);
+
+ // Go through the funding_created and funding_signed flow with node 1.
+ nodes[1].node.handle_funding_created(&nodes[0].node.get_our_node_id(), &funding_created_msgs[0]);
+ check_added_monitors(&nodes[1], 1);
+ expect_channel_pending_event(&nodes[1], &nodes[0].node.get_our_node_id());
+
+ let funding_signed_msg = get_event_msg!(nodes[1], MessageSendEvent::SendFundingSigned, nodes[0].node.get_our_node_id());
+ nodes[0].node.handle_funding_signed(&nodes[1].node.get_our_node_id(), &funding_signed_msg);
+ check_added_monitors(&nodes[0], 1);
+
+ // The transaction should not have been broadcast before all channels are ready.
+ assert_eq!(nodes[0].tx_broadcaster.txn_broadcast().len(), 0);
+
+ // The remaining peer in the batch disconnects.
+ nodes[0].node.peer_disconnected(&nodes[2].node.get_our_node_id());
+
+ // The channels in the batch will close immediately.
+ let channel_id_1 = OutPoint { txid: tx.txid(), index: 0 }.to_channel_id();
+ let channel_id_2 = OutPoint { txid: tx.txid(), index: 1 }.to_channel_id();
+ let events = nodes[0].node.get_and_clear_pending_events();
+ assert_eq!(events.len(), 4);
+ assert!(events.iter().any(|e| matches!(
+ e,
+ Event::ChannelClosed {
+ channel_id,
+ ..
+ } if channel_id == &channel_id_1
+ )));
+ assert!(events.iter().any(|e| matches!(
+ e,
+ Event::ChannelClosed {
+ channel_id,
+ ..
+ } if channel_id == &channel_id_2
+ )));
+ assert_eq!(events.iter().filter(|e| matches!(
+ e,
+ Event::DiscardFunding { .. },
+ )).count(), 2);
+
+ // The monitor should become closed.
+ check_added_monitors(&nodes[0], 1);
+ {
+ let mut monitor_updates = nodes[0].chain_monitor.monitor_updates.lock().unwrap();
+ let monitor_updates_1 = monitor_updates.get(&channel_id_1).unwrap();
+ assert_eq!(monitor_updates_1.len(), 1);
+ assert_eq!(monitor_updates_1[0].update_id, CLOSED_CHANNEL_UPDATE_ID);
+ }
+
+ // The funding transaction should not have been broadcast, and therefore, we don't need
+ // to broadcast a force-close transaction for the closed monitor.
+ assert_eq!(nodes[0].tx_broadcaster.txn_broadcast().len(), 0);
+
+ // Ensure the channels don't exist anymore.
+ assert!(nodes[0].node.list_channels().is_empty());
+}
+
+#[test]
+fn test_batch_funding_close_after_funding_signed() {
+ let chanmon_cfgs = create_chanmon_cfgs(3);
+ let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
+ let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
+ let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
+
+ // Initiate channel opening and create the batch channel funding transaction.
+ let (tx, funding_created_msgs) = create_batch_channel_funding(&nodes[0], &[
+ (&nodes[1], 100_000, 0, 42, None),
+ (&nodes[2], 200_000, 0, 43, None),
+ ]);
+
+ // Go through the funding_created and funding_signed flow with node 1.
+ nodes[1].node.handle_funding_created(&nodes[0].node.get_our_node_id(), &funding_created_msgs[0]);
+ check_added_monitors(&nodes[1], 1);
+ expect_channel_pending_event(&nodes[1], &nodes[0].node.get_our_node_id());
+
+ let funding_signed_msg = get_event_msg!(nodes[1], MessageSendEvent::SendFundingSigned, nodes[0].node.get_our_node_id());
+ nodes[0].node.handle_funding_signed(&nodes[1].node.get_our_node_id(), &funding_signed_msg);
+ check_added_monitors(&nodes[0], 1);
+
+ // Go through the funding_created and funding_signed flow with node 2.
+ nodes[2].node.handle_funding_created(&nodes[0].node.get_our_node_id(), &funding_created_msgs[1]);
+ check_added_monitors(&nodes[2], 1);
+ expect_channel_pending_event(&nodes[2], &nodes[0].node.get_our_node_id());
+
+ let funding_signed_msg = get_event_msg!(nodes[2], MessageSendEvent::SendFundingSigned, nodes[0].node.get_our_node_id());
+ chanmon_cfgs[0].persister.set_update_ret(ChannelMonitorUpdateStatus::InProgress);
+ nodes[0].node.handle_funding_signed(&nodes[2].node.get_our_node_id(), &funding_signed_msg);
+ check_added_monitors(&nodes[0], 1);
+
+ // The transaction should not have been broadcast before all channels are ready.
+ assert_eq!(nodes[0].tx_broadcaster.txn_broadcast().len(), 0);
+
+ // Force-close the channel for which we've completed the initial monitor.
+ let channel_id_1 = OutPoint { txid: tx.txid(), index: 0 }.to_channel_id();
+ let channel_id_2 = OutPoint { txid: tx.txid(), index: 1 }.to_channel_id();
+ nodes[0].node.force_close_broadcasting_latest_txn(&channel_id_1, &nodes[1].node.get_our_node_id()).unwrap();
+ check_added_monitors(&nodes[0], 2);
+ {
+ let mut monitor_updates = nodes[0].chain_monitor.monitor_updates.lock().unwrap();
+ let monitor_updates_1 = monitor_updates.get(&channel_id_1).unwrap();
+ assert_eq!(monitor_updates_1.len(), 1);
+ assert_eq!(monitor_updates_1[0].update_id, CLOSED_CHANNEL_UPDATE_ID);
+ let monitor_updates_2 = monitor_updates.get(&channel_id_2).unwrap();
+ assert_eq!(monitor_updates_2.len(), 1);
+ assert_eq!(monitor_updates_2[0].update_id, CLOSED_CHANNEL_UPDATE_ID);
+ }
+ let msg_events = nodes[0].node.get_and_clear_pending_msg_events();
+ match msg_events[0] {
+ MessageSendEvent::HandleError { .. } => (),
+ _ => panic!("Unexpected message."),
+ }
+
+ // We broadcast the commitment transaction as part of the force-close.
+ {
+ let broadcasted_txs = nodes[0].tx_broadcaster.txn_broadcast();
+ assert_eq!(broadcasted_txs.len(), 1);
+ assert!(broadcasted_txs[0].txid() != tx.txid());
+ assert_eq!(broadcasted_txs[0].input.len(), 1);
+ assert_eq!(broadcasted_txs[0].input[0].previous_output.txid, tx.txid());
+ }
+
+ // All channels in the batch should close immediately.
+ let events = nodes[0].node.get_and_clear_pending_events();
+ assert_eq!(events.len(), 4);
+ assert!(events.iter().any(|e| matches!(
+ e,
+ Event::ChannelClosed {
+ channel_id,
+ ..
+ } if channel_id == &channel_id_1
+ )));
+ assert!(events.iter().any(|e| matches!(
+ e,
+ Event::ChannelClosed {
+ channel_id,
+ ..
+ } if channel_id == &channel_id_2
+ )));
+ assert_eq!(events.iter().filter(|e| matches!(
+ e,
+ Event::DiscardFunding { .. },
+ )).count(), 2);
+
+ // Ensure the channels don't exist anymore.
+ assert!(nodes[0].node.list_channels().is_empty());
+}
+
+fn do_test_funding_and_commitment_tx_confirm_same_block(confirm_remote_commitment: bool) {
+ // Tests that a node will forget the channel (when it only requires 1 confirmation) if the
+ // funding and commitment transaction confirm in the same block.
+ let chanmon_cfgs = create_chanmon_cfgs(2);
+ let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
+ let mut min_depth_1_block_cfg = test_default_channel_config();
+ min_depth_1_block_cfg.channel_handshake_config.minimum_depth = 1;
+ let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[Some(min_depth_1_block_cfg), Some(min_depth_1_block_cfg)]);
+ let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
+
+ let funding_tx = create_chan_between_nodes_with_value_init(&nodes[0], &nodes[1], 1_000_000, 0);
+ let chan_id = chain::transaction::OutPoint { txid: funding_tx.txid(), index: 0 }.to_channel_id();
+
+ assert_eq!(nodes[0].node.list_channels().len(), 1);
+ assert_eq!(nodes[1].node.list_channels().len(), 1);
+
+ let (closing_node, other_node) = if confirm_remote_commitment {
+ (&nodes[1], &nodes[0])
+ } else {
+ (&nodes[0], &nodes[1])
+ };
+
+ closing_node.node.force_close_broadcasting_latest_txn(&chan_id, &other_node.node.get_our_node_id()).unwrap();
+ let mut msg_events = closing_node.node.get_and_clear_pending_msg_events();
+ assert_eq!(msg_events.len(), 1);
+ match msg_events.pop().unwrap() {
+ MessageSendEvent::HandleError { action: msgs::ErrorAction::DisconnectPeer { .. }, .. } => {},
+ _ => panic!("Unexpected event"),
+ }
+ check_added_monitors(closing_node, 1);
+ check_closed_event(closing_node, 1, ClosureReason::HolderForceClosed, false, &[other_node.node.get_our_node_id()], 1_000_000);
+
+ let commitment_tx = {
+ let mut txn = closing_node.tx_broadcaster.txn_broadcast();
+ assert_eq!(txn.len(), 1);
+ let commitment_tx = txn.pop().unwrap();
+ check_spends!(commitment_tx, funding_tx);
+ commitment_tx
+ };
+
+ mine_transactions(&nodes[0], &[&funding_tx, &commitment_tx]);
+ mine_transactions(&nodes[1], &[&funding_tx, &commitment_tx]);
+
+ check_closed_broadcast(other_node, 1, true);
+ check_added_monitors(other_node, 1);
+ check_closed_event(other_node, 1, ClosureReason::CommitmentTxConfirmed, false, &[closing_node.node.get_our_node_id()], 1_000_000);
+
+ assert!(nodes[0].node.list_channels().is_empty());
+ assert!(nodes[1].node.list_channels().is_empty());
+}
+
+#[test]
+fn test_funding_and_commitment_tx_confirm_same_block() {
+ do_test_funding_and_commitment_tx_confirm_same_block(false);
+ do_test_funding_and_commitment_tx_confirm_same_block(true);
+}