@@ -1178,6 +1178,319 @@ fn do_test_splice_reestablish(reload: bool, async_monitor_update: bool) {
11781178 . remove_watched_txn_and_outputs ( prev_funding_outpoint, prev_funding_script) ;
11791179}
11801180
1181+ #[ test]
1182+ fn test_propose_splice_while_disconnected ( ) {
1183+ do_test_propose_splice_while_disconnected ( false , false ) ;
1184+ do_test_propose_splice_while_disconnected ( false , true ) ;
1185+ do_test_propose_splice_while_disconnected ( true , false ) ;
1186+ do_test_propose_splice_while_disconnected ( true , true ) ;
1187+ }
1188+
1189+ fn do_test_propose_splice_while_disconnected ( reload : bool , use_0conf : bool ) {
1190+ // Test that both nodes are able to propose a splice while the counterparty is disconnected, and
1191+ // whoever doesn't go first due to the quiescence tie-breaker, will retry their splice after the
1192+ // first one becomes locked.
1193+ let chanmon_cfgs = create_chanmon_cfgs ( 2 ) ;
1194+ let node_cfgs = create_node_cfgs ( 2 , & chanmon_cfgs) ;
1195+ let ( persister_0a, persister_0b, persister_1a, persister_1b) ;
1196+ let ( chain_monitor_0a, chain_monitor_0b, chain_monitor_1a, chain_monitor_1b) ;
1197+ let mut config = test_default_channel_config ( ) ;
1198+ if use_0conf {
1199+ config. manually_accept_inbound_channels = true ;
1200+ config. channel_handshake_limits . trust_own_funding_0conf = true ;
1201+ }
1202+ let node_chanmgrs = create_node_chanmgrs ( 2 , & node_cfgs, & [ Some ( config. clone ( ) ) , Some ( config) ] ) ;
1203+ let ( node_0a, node_0b, node_1a, node_1b) ;
1204+ let mut nodes = create_network ( 2 , & node_cfgs, & node_chanmgrs) ;
1205+
1206+ let node_id_0 = nodes[ 0 ] . node . get_our_node_id ( ) ;
1207+ let node_id_1 = nodes[ 1 ] . node . get_our_node_id ( ) ;
1208+
1209+ let initial_channel_value_sat = 1_000_000 ;
1210+ let push_msat = initial_channel_value_sat / 2 * 1000 ;
1211+ let channel_id = if use_0conf {
1212+ let ( funding_tx, channel_id) = open_zero_conf_channel_with_value (
1213+ & nodes[ 0 ] ,
1214+ & nodes[ 1 ] ,
1215+ None ,
1216+ initial_channel_value_sat,
1217+ push_msat,
1218+ ) ;
1219+ mine_transaction ( & nodes[ 0 ] , & funding_tx) ;
1220+ mine_transaction ( & nodes[ 1 ] , & funding_tx) ;
1221+ channel_id
1222+ } else {
1223+ let ( _, _, channel_id, _) = create_announced_chan_between_nodes_with_value (
1224+ & nodes,
1225+ 0 ,
1226+ 1 ,
1227+ initial_channel_value_sat,
1228+ push_msat,
1229+ ) ;
1230+ channel_id
1231+ } ;
1232+
1233+ // Start with the nodes disconnected, and have each one attempt a splice.
1234+ nodes[ 0 ] . node . peer_disconnected ( node_id_1) ;
1235+ nodes[ 1 ] . node . peer_disconnected ( node_id_0) ;
1236+
1237+ let splice_out_sat = initial_channel_value_sat / 4 ;
1238+ let node_0_contribution = SpliceContribution :: SpliceOut {
1239+ outputs : vec ! [ TxOut {
1240+ value: Amount :: from_sat( splice_out_sat) ,
1241+ script_pubkey: nodes[ 0 ] . wallet_source. get_change_script( ) . unwrap( ) ,
1242+ } ] ,
1243+ } ;
1244+ nodes[ 0 ]
1245+ . node
1246+ . splice_channel (
1247+ & channel_id,
1248+ & node_id_1,
1249+ node_0_contribution. clone ( ) ,
1250+ FEERATE_FLOOR_SATS_PER_KW ,
1251+ None ,
1252+ )
1253+ . unwrap ( ) ;
1254+ assert ! ( nodes[ 0 ] . node. get_and_clear_pending_msg_events( ) . is_empty( ) ) ;
1255+
1256+ let node_1_contribution = SpliceContribution :: SpliceOut {
1257+ outputs : vec ! [ TxOut {
1258+ value: Amount :: from_sat( splice_out_sat) ,
1259+ script_pubkey: nodes[ 1 ] . wallet_source. get_change_script( ) . unwrap( ) ,
1260+ } ] ,
1261+ } ;
1262+ nodes[ 1 ]
1263+ . node
1264+ . splice_channel (
1265+ & channel_id,
1266+ & node_id_0,
1267+ node_1_contribution. clone ( ) ,
1268+ FEERATE_FLOOR_SATS_PER_KW ,
1269+ None ,
1270+ )
1271+ . unwrap ( ) ;
1272+ assert ! ( nodes[ 1 ] . node. get_and_clear_pending_msg_events( ) . is_empty( ) ) ;
1273+
1274+ if reload {
1275+ let encoded_monitor_0 = get_monitor ! ( nodes[ 0 ] , channel_id) . encode ( ) ;
1276+ reload_node ! (
1277+ nodes[ 0 ] ,
1278+ nodes[ 0 ] . node. encode( ) ,
1279+ & [ & encoded_monitor_0] ,
1280+ persister_0a,
1281+ chain_monitor_0a,
1282+ node_0a
1283+ ) ;
1284+ let encoded_monitor_1 = get_monitor ! ( nodes[ 1 ] , channel_id) . encode ( ) ;
1285+ reload_node ! (
1286+ nodes[ 1 ] ,
1287+ nodes[ 1 ] . node. encode( ) ,
1288+ & [ & encoded_monitor_1] ,
1289+ persister_1a,
1290+ chain_monitor_1a,
1291+ node_1a
1292+ ) ;
1293+ }
1294+
1295+ // Reconnect the nodes. Both nodes should attempt quiescence as the initiator, but only one will
1296+ // be it via the tie-breaker.
1297+ let mut reconnect_args = ReconnectArgs :: new ( & nodes[ 0 ] , & nodes[ 1 ] ) ;
1298+ reconnect_args. send_channel_ready = ( true , true ) ;
1299+ if !use_0conf {
1300+ reconnect_args. send_announcement_sigs = ( true , true ) ;
1301+ }
1302+ reconnect_args. send_stfu = ( true , true ) ;
1303+ reconnect_nodes ( reconnect_args) ;
1304+ let splice_init = get_event_msg ! ( nodes[ 0 ] , MessageSendEvent :: SendSpliceInit , node_id_1) ;
1305+ assert ! ( nodes[ 1 ] . node. get_and_clear_pending_msg_events( ) . is_empty( ) ) ;
1306+
1307+ let ( prev_funding_outpoint, prev_funding_script) = nodes[ 0 ]
1308+ . chain_monitor
1309+ . chain_monitor
1310+ . get_monitor ( channel_id)
1311+ . map ( |monitor| ( monitor. get_funding_txo ( ) , monitor. get_funding_script ( ) ) )
1312+ . unwrap ( ) ;
1313+
1314+ // Negotiate the first splice to completion.
1315+ let initial_commit_sig = {
1316+ nodes[ 1 ] . node . handle_splice_init ( node_id_0, & splice_init) ;
1317+ let splice_ack = get_event_msg ! ( nodes[ 1 ] , MessageSendEvent :: SendSpliceAck , node_id_0) ;
1318+ nodes[ 0 ] . node . handle_splice_ack ( node_id_1, & splice_ack) ;
1319+ let new_funding_script = chan_utils:: make_funding_redeemscript (
1320+ & splice_init. funding_pubkey ,
1321+ & splice_ack. funding_pubkey ,
1322+ )
1323+ . to_p2wsh ( ) ;
1324+ complete_interactive_funding_negotiation (
1325+ & nodes[ 0 ] ,
1326+ & nodes[ 1 ] ,
1327+ channel_id,
1328+ node_0_contribution,
1329+ new_funding_script,
1330+ )
1331+ } ;
1332+ let ( splice_tx, splice_locked) =
1333+ sign_interactive_funding_tx ( & nodes[ 0 ] , & nodes[ 1 ] , initial_commit_sig, use_0conf) ;
1334+ expect_splice_pending_event ( & nodes[ 0 ] , & node_id_1) ;
1335+ expect_splice_pending_event ( & nodes[ 1 ] , & node_id_0) ;
1336+
1337+ let splice_locked = if use_0conf {
1338+ let ( splice_locked, for_node_id) = splice_locked. unwrap ( ) ;
1339+ assert_eq ! ( for_node_id, node_id_1) ;
1340+ splice_locked
1341+ } else {
1342+ assert ! ( splice_locked. is_none( ) ) ;
1343+
1344+ mine_transaction ( & nodes[ 0 ] , & splice_tx) ;
1345+ mine_transaction ( & nodes[ 1 ] , & splice_tx) ;
1346+
1347+ // Mine enough blocks for the first splice to become locked.
1348+ connect_blocks ( & nodes[ 0 ] , ANTI_REORG_DELAY - 1 ) ;
1349+ connect_blocks ( & nodes[ 1 ] , ANTI_REORG_DELAY - 1 ) ;
1350+
1351+ get_event_msg ! ( nodes[ 0 ] , MessageSendEvent :: SendSpliceLocked , node_id_1)
1352+ } ;
1353+ nodes[ 1 ] . node . handle_splice_locked ( node_id_0, & splice_locked) ;
1354+
1355+ // We should see the node which lost the tie-breaker attempt their splice now by first
1356+ // negotiating quiescence, but their `stfu` won't be sent until after another reconnection.
1357+ let msg_events = nodes[ 1 ] . node . get_and_clear_pending_msg_events ( ) ;
1358+ assert_eq ! ( msg_events. len( ) , if use_0conf { 2 } else { 3 } , "{msg_events:?}" ) ;
1359+ if let MessageSendEvent :: SendSpliceLocked { ref msg, .. } = & msg_events[ 0 ] {
1360+ nodes[ 0 ] . node . handle_splice_locked ( node_id_1, msg) ;
1361+ if use_0conf {
1362+ // TODO(splicing): Revisit splice transaction rebroadcasts.
1363+ let txn_0 = nodes[ 0 ] . tx_broadcaster . txn_broadcast ( ) ;
1364+ assert_eq ! ( txn_0. len( ) , 1 ) ;
1365+ assert_eq ! ( & txn_0[ 0 ] , & splice_tx) ;
1366+ mine_transaction ( & nodes[ 0 ] , & splice_tx) ;
1367+ mine_transaction ( & nodes[ 1 ] , & splice_tx) ;
1368+ }
1369+ } else {
1370+ panic ! ( "Unexpected event {:?}" , & msg_events[ 0 ] ) ;
1371+ }
1372+ if !use_0conf {
1373+ if let MessageSendEvent :: SendAnnouncementSignatures { ref msg, .. } = & msg_events[ 1 ] {
1374+ nodes[ 0 ] . node . handle_announcement_signatures ( node_id_1, msg) ;
1375+ } else {
1376+ panic ! ( "Unexpected event {:?}" , & msg_events[ 1 ] ) ;
1377+ }
1378+ }
1379+ assert ! ( matches!(
1380+ & msg_events[ if use_0conf { 1 } else { 2 } ] ,
1381+ MessageSendEvent :: SendStfu { .. }
1382+ ) ) ;
1383+
1384+ let msg_events = nodes[ 0 ] . node . get_and_clear_pending_msg_events ( ) ;
1385+ assert_eq ! ( msg_events. len( ) , if use_0conf { 0 } else { 2 } , "{msg_events:?}" ) ;
1386+ if !use_0conf {
1387+ if let MessageSendEvent :: SendAnnouncementSignatures { ref msg, .. } = & msg_events[ 0 ] {
1388+ nodes[ 1 ] . node . handle_announcement_signatures ( node_id_0, msg) ;
1389+ } else {
1390+ panic ! ( "Unexpected event {:?}" , & msg_events[ 1 ] ) ;
1391+ }
1392+ assert ! ( matches!( & msg_events[ 1 ] , MessageSendEvent :: BroadcastChannelAnnouncement { .. } ) ) ;
1393+ }
1394+
1395+ let msg_events = nodes[ 1 ] . node . get_and_clear_pending_msg_events ( ) ;
1396+ assert_eq ! ( msg_events. len( ) , if use_0conf { 0 } else { 1 } , "{msg_events:?}" ) ;
1397+ if !use_0conf {
1398+ assert ! ( matches!( & msg_events[ 0 ] , MessageSendEvent :: BroadcastChannelAnnouncement { .. } ) ) ;
1399+ }
1400+
1401+ expect_channel_ready_event ( & nodes[ 0 ] , & node_id_1) ;
1402+ check_added_monitors ( & nodes[ 0 ] , 1 ) ;
1403+ expect_channel_ready_event ( & nodes[ 1 ] , & node_id_0) ;
1404+ check_added_monitors ( & nodes[ 1 ] , 1 ) ;
1405+
1406+ // Remove the corresponding outputs and transactions the chain source is watching for the
1407+ // old funding as it is no longer being tracked.
1408+ nodes[ 0 ]
1409+ . chain_source
1410+ . remove_watched_txn_and_outputs ( prev_funding_outpoint, prev_funding_script. clone ( ) ) ;
1411+ nodes[ 1 ]
1412+ . chain_source
1413+ . remove_watched_txn_and_outputs ( prev_funding_outpoint, prev_funding_script) ;
1414+
1415+ // Reconnect the nodes. This should trigger the node which lost the tie-breaker to resend `stfu`
1416+ // for their splice attempt.
1417+ if reload {
1418+ let encoded_monitor_0 = get_monitor ! ( nodes[ 0 ] , channel_id) . encode ( ) ;
1419+ reload_node ! (
1420+ nodes[ 0 ] ,
1421+ nodes[ 0 ] . node. encode( ) ,
1422+ & [ & encoded_monitor_0] ,
1423+ persister_0b,
1424+ chain_monitor_0b,
1425+ node_0b
1426+ ) ;
1427+ let encoded_monitor_1 = get_monitor ! ( nodes[ 1 ] , channel_id) . encode ( ) ;
1428+ reload_node ! (
1429+ nodes[ 1 ] ,
1430+ nodes[ 1 ] . node. encode( ) ,
1431+ & [ & encoded_monitor_1] ,
1432+ persister_1b,
1433+ chain_monitor_1b,
1434+ node_1b
1435+ ) ;
1436+ } else {
1437+ nodes[ 0 ] . node . peer_disconnected ( node_id_1) ;
1438+ nodes[ 1 ] . node . peer_disconnected ( node_id_0) ;
1439+ }
1440+ let mut reconnect_args = ReconnectArgs :: new ( & nodes[ 0 ] , & nodes[ 1 ] ) ;
1441+ if !use_0conf {
1442+ reconnect_args. send_announcement_sigs = ( true , true ) ;
1443+ }
1444+ reconnect_args. send_stfu = ( true , false ) ;
1445+ reconnect_nodes ( reconnect_args) ;
1446+
1447+ // Drive the second splice to completion.
1448+ let msg_events = nodes[ 0 ] . node . get_and_clear_pending_msg_events ( ) ;
1449+ assert_eq ! ( msg_events. len( ) , 1 , "{msg_events:?}" ) ;
1450+ if let MessageSendEvent :: SendStfu { ref msg, .. } = msg_events[ 0 ] {
1451+ nodes[ 1 ] . node . handle_stfu ( node_id_0, msg) ;
1452+ } else {
1453+ panic ! ( "Unexpected event {:?}" , & msg_events[ 0 ] ) ;
1454+ }
1455+
1456+ let splice_init = get_event_msg ! ( nodes[ 1 ] , MessageSendEvent :: SendSpliceInit , node_id_0) ;
1457+ let initial_commit_sig = {
1458+ nodes[ 0 ] . node . handle_splice_init ( node_id_1, & splice_init) ;
1459+ let splice_ack = get_event_msg ! ( nodes[ 0 ] , MessageSendEvent :: SendSpliceAck , node_id_1) ;
1460+ nodes[ 1 ] . node . handle_splice_ack ( node_id_0, & splice_ack) ;
1461+ let new_funding_script = chan_utils:: make_funding_redeemscript (
1462+ & splice_init. funding_pubkey ,
1463+ & splice_ack. funding_pubkey ,
1464+ )
1465+ . to_p2wsh ( ) ;
1466+ complete_interactive_funding_negotiation (
1467+ & nodes[ 1 ] ,
1468+ & nodes[ 0 ] ,
1469+ channel_id,
1470+ node_1_contribution,
1471+ new_funding_script,
1472+ )
1473+ } ;
1474+ let ( splice_tx, splice_locked) =
1475+ sign_interactive_funding_tx ( & nodes[ 1 ] , & nodes[ 0 ] , initial_commit_sig, use_0conf) ;
1476+ expect_splice_pending_event ( & nodes[ 0 ] , & node_id_1) ;
1477+ expect_splice_pending_event ( & nodes[ 1 ] , & node_id_0) ;
1478+
1479+ if use_0conf {
1480+ let ( splice_locked, for_node_id) = splice_locked. unwrap ( ) ;
1481+ assert_eq ! ( for_node_id, node_id_0) ;
1482+ lock_splice ( & nodes[ 1 ] , & nodes[ 0 ] , & splice_locked, true ) ;
1483+ } else {
1484+ assert ! ( splice_locked. is_none( ) ) ;
1485+ mine_transaction ( & nodes[ 0 ] , & splice_tx) ;
1486+ mine_transaction ( & nodes[ 1 ] , & splice_tx) ;
1487+ lock_splice_after_blocks ( & nodes[ 1 ] , & nodes[ 0 ] , ANTI_REORG_DELAY - 1 ) ;
1488+ }
1489+
1490+ // Sanity check that we can still make a test payment.
1491+ send_payment ( & nodes[ 0 ] , & [ & nodes[ 1 ] ] , 1_000_000 ) ;
1492+ }
1493+
11811494#[ test]
11821495fn disconnect_on_unexpected_interactive_tx_message ( ) {
11831496 let chanmon_cfgs = create_chanmon_cfgs ( 2 ) ;
0 commit comments