@@ -8977,6 +8977,61 @@ fn test_duplicate_temporary_channel_id_from_different_peers() {
8977
8977
}
8978
8978
}
8979
8979
8980
+ #[test]
8981
+ fn test_peer_funding_sidechannel() {
8982
+ // Test that if a peer somehow learns which txid we'll use for our channel funding before we
8983
+ // receive `funding_transaction_generated` the peer cannot cause us to crash. We'd previously
8984
+ // assumed that LDK would receive `funding_transaction_generated` prior to our peer learning
8985
+ // the txid and panicked if the peer tried to open a redundant channel to us with the same
8986
+ // funding outpoint.
8987
+ //
8988
+ // While this assumption is generally safe, some users may have out-of-band protocols where
8989
+ // they notify their LSP about a funding outpoint first, or this may be violated in the future
8990
+ // with collaborative transaction construction protocols, i.e. dual-funding.
8991
+ let chanmon_cfgs = create_chanmon_cfgs(3);
8992
+ let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
8993
+ let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
8994
+ let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
8995
+
8996
+ let temp_chan_id_ab = exchange_open_accept_chan(&nodes[0], &nodes[1], 1_000_000, 0);
8997
+ let temp_chan_id_ca = exchange_open_accept_chan(&nodes[2], &nodes[0], 1_000_000, 0);
8998
+
8999
+ let (_, tx, funding_output) =
9000
+ create_funding_transaction(&nodes[0], &nodes[1].node.get_our_node_id(), 1_000_000, 42);
9001
+
9002
+ let cs_funding_events = nodes[2].node.get_and_clear_pending_events();
9003
+ assert_eq!(cs_funding_events.len(), 1);
9004
+ match cs_funding_events[0] {
9005
+ Event::FundingGenerationReady { .. } => {}
9006
+ _ => panic!("Unexpected event {:?}", cs_funding_events),
9007
+ }
9008
+
9009
+ nodes[2].node.funding_transaction_generated_unchecked(&temp_chan_id_ca, &nodes[0].node.get_our_node_id(), tx.clone(), funding_output.index).unwrap();
9010
+ let funding_created_msg = get_event_msg!(nodes[2], MessageSendEvent::SendFundingCreated, nodes[0].node.get_our_node_id());
9011
+ nodes[0].node.handle_funding_created(&nodes[2].node.get_our_node_id(), &funding_created_msg);
9012
+ get_event_msg!(nodes[0], MessageSendEvent::SendFundingSigned, nodes[2].node.get_our_node_id());
9013
+ expect_channel_pending_event(&nodes[0], &nodes[2].node.get_our_node_id());
9014
+ check_added_monitors!(nodes[0], 1);
9015
+
9016
+ let res = nodes[0].node.funding_transaction_generated(&temp_chan_id_ab, &nodes[1].node.get_our_node_id(), tx.clone());
9017
+ let err_msg = format!("{:?}", res.unwrap_err());
9018
+ assert!(err_msg.contains("An existing channel using outpoint "));
9019
+ assert!(err_msg.contains(" is open with peer"));
9020
+ // Even though the last funding_transaction_generated errored, it still generated a
9021
+ // SendFundingCreated. However, when the peer responds with a funding_signed it will send the
9022
+ // appropriate error message.
9023
+ let as_funding_created = get_event_msg!(nodes[0], MessageSendEvent::SendFundingCreated, nodes[1].node.get_our_node_id());
9024
+ nodes[1].node.handle_funding_created(&nodes[0].node.get_our_node_id(), &as_funding_created);
9025
+ check_added_monitors!(nodes[1], 1);
9026
+ expect_channel_pending_event(&nodes[1], &nodes[0].node.get_our_node_id());
9027
+ let reason = ClosureReason::ProcessingError { err: format!("An existing channel using outpoint {} is open with peer {}", funding_output, nodes[2].node.get_our_node_id()), };
9028
+ check_closed_events(&nodes[0], &[ExpectedCloseEvent::from_id_reason(funding_output.to_channel_id(), true, reason)]);
9029
+
9030
+ let funding_signed = get_event_msg!(nodes[1], MessageSendEvent::SendFundingSigned, nodes[0].node.get_our_node_id());
9031
+ nodes[0].node.handle_funding_signed(&nodes[1].node.get_our_node_id(), &funding_signed);
9032
+ get_err_msg(&nodes[0], &nodes[1].node.get_our_node_id());
9033
+ }
9034
+
8980
9035
#[test]
8981
9036
fn test_duplicate_funding_err_in_funding() {
8982
9037
// Test that if we have a live channel with one peer, then another peer comes along and tries
0 commit comments