@@ -65,6 +65,32 @@ fn test_v1_splice_in_negative_insufficient_inputs() {
65
65
}
66
66
}
67
67
68
+ fn negotiate_splice_tx_with_init < ' a , ' b , ' c , ' d > (
69
+ initiator : & ' a Node < ' b , ' c , ' d > , acceptor : & ' a Node < ' b , ' c , ' d > , channel_id : ChannelId ,
70
+ initiator_contribution : SpliceContribution , splice_init : & msgs:: SpliceInit ,
71
+ ) -> msgs:: CommitmentSigned {
72
+ let node_id_initiator = initiator. node . get_our_node_id ( ) ;
73
+ let node_id_acceptor = acceptor. node . get_our_node_id ( ) ;
74
+
75
+ acceptor. node . handle_splice_init ( node_id_initiator, & splice_init) ;
76
+ let splice_ack = get_event_msg ! ( acceptor, MessageSendEvent :: SendSpliceAck , node_id_initiator) ;
77
+ initiator. node . handle_splice_ack ( node_id_acceptor, & splice_ack) ;
78
+
79
+ let new_funding_script = chan_utils:: make_funding_redeemscript (
80
+ & splice_init. funding_pubkey ,
81
+ & splice_ack. funding_pubkey ,
82
+ )
83
+ . to_p2wsh ( ) ;
84
+
85
+ complete_interactive_funding_negotiation (
86
+ initiator,
87
+ acceptor,
88
+ channel_id,
89
+ initiator_contribution,
90
+ new_funding_script,
91
+ )
92
+ }
93
+
68
94
fn negotiate_splice_tx < ' a , ' b , ' c , ' d > (
69
95
initiator : & ' a Node < ' b , ' c , ' d > , acceptor : & ' a Node < ' b , ' c , ' d > , channel_id : ChannelId ,
70
96
initiator_contribution : SpliceContribution ,
@@ -89,22 +115,12 @@ fn negotiate_splice_tx<'a, 'b, 'c, 'd>(
89
115
initiator. node . handle_stfu ( node_id_acceptor, & stfu_ack) ;
90
116
91
117
let splice_init = get_event_msg ! ( initiator, MessageSendEvent :: SendSpliceInit , node_id_acceptor) ;
92
- acceptor. node . handle_splice_init ( node_id_initiator, & splice_init) ;
93
- let splice_ack = get_event_msg ! ( acceptor, MessageSendEvent :: SendSpliceAck , node_id_initiator) ;
94
- initiator. node . handle_splice_ack ( node_id_acceptor, & splice_ack) ;
95
-
96
- let new_funding_script = chan_utils:: make_funding_redeemscript (
97
- & splice_init. funding_pubkey ,
98
- & splice_ack. funding_pubkey ,
99
- )
100
- . to_p2wsh ( ) ;
101
-
102
- complete_interactive_funding_negotiation (
118
+ negotiate_splice_tx_with_init (
103
119
initiator,
104
120
acceptor,
105
121
channel_id,
106
122
initiator_contribution,
107
- new_funding_script ,
123
+ & splice_init ,
108
124
)
109
125
}
110
126
@@ -1083,3 +1099,292 @@ fn do_test_splice_reestablish(reload: bool, async_monitor_update: bool) {
1083
1099
. chain_source
1084
1100
. remove_watched_txn_and_outputs ( prev_funding_outpoint, prev_funding_script) ;
1085
1101
}
1102
+
1103
+ #[ test]
1104
+ fn test_propose_splice_while_disconnected ( ) {
1105
+ do_test_propose_splice_while_disconnected ( false , false ) ;
1106
+ do_test_propose_splice_while_disconnected ( false , true ) ;
1107
+ do_test_propose_splice_while_disconnected ( true , false ) ;
1108
+ do_test_propose_splice_while_disconnected ( true , true ) ;
1109
+ }
1110
+
1111
+ fn do_test_propose_splice_while_disconnected ( reload : bool , use_0conf : bool ) {
1112
+ // Test that both nodes are able to propose a splice while the counterparty is disconnected, and
1113
+ // whoever doesn't go first due to the quiescence tie-breaker, will retry their splice after the
1114
+ // first one becomes locked.
1115
+ let chanmon_cfgs = create_chanmon_cfgs ( 2 ) ;
1116
+ let node_cfgs = create_node_cfgs ( 2 , & chanmon_cfgs) ;
1117
+ let ( persister_0a, persister_0b, persister_1a, persister_1b) ;
1118
+ let ( chain_monitor_0a, chain_monitor_0b, chain_monitor_1a, chain_monitor_1b) ;
1119
+ let mut config = test_default_channel_config ( ) ;
1120
+ if use_0conf {
1121
+ config. manually_accept_inbound_channels = true ;
1122
+ config. channel_handshake_limits . trust_own_funding_0conf = true ;
1123
+ }
1124
+ let node_chanmgrs = create_node_chanmgrs ( 2 , & node_cfgs, & [ Some ( config. clone ( ) ) , Some ( config) ] ) ;
1125
+ let ( node_0a, node_0b, node_1a, node_1b) ;
1126
+ let mut nodes = create_network ( 2 , & node_cfgs, & node_chanmgrs) ;
1127
+
1128
+ let node_id_0 = nodes[ 0 ] . node . get_our_node_id ( ) ;
1129
+ let node_id_1 = nodes[ 1 ] . node . get_our_node_id ( ) ;
1130
+
1131
+ let initial_channel_value_sat = 1_000_000 ;
1132
+ let push_msat = initial_channel_value_sat / 2 * 1000 ;
1133
+ let channel_id = if use_0conf {
1134
+ let ( funding_tx, channel_id) = open_zero_conf_channel_with_value (
1135
+ & nodes[ 0 ] ,
1136
+ & nodes[ 1 ] ,
1137
+ None ,
1138
+ initial_channel_value_sat,
1139
+ push_msat,
1140
+ ) ;
1141
+ mine_transaction ( & nodes[ 0 ] , & funding_tx) ;
1142
+ mine_transaction ( & nodes[ 1 ] , & funding_tx) ;
1143
+ channel_id
1144
+ } else {
1145
+ let ( _, _, channel_id, _) = create_announced_chan_between_nodes_with_value (
1146
+ & nodes,
1147
+ 0 ,
1148
+ 1 ,
1149
+ initial_channel_value_sat,
1150
+ push_msat,
1151
+ ) ;
1152
+ channel_id
1153
+ } ;
1154
+
1155
+ // Start with the nodes disconnected, and have each one attempt a splice.
1156
+ nodes[ 0 ] . node . peer_disconnected ( node_id_1) ;
1157
+ nodes[ 1 ] . node . peer_disconnected ( node_id_0) ;
1158
+
1159
+ let splice_out_sat = initial_channel_value_sat / 4 ;
1160
+ let node_0_contribution = SpliceContribution :: SpliceOut {
1161
+ outputs : vec ! [ TxOut {
1162
+ value: Amount :: from_sat( splice_out_sat) ,
1163
+ script_pubkey: nodes[ 0 ] . wallet_source. get_change_script( ) . unwrap( ) ,
1164
+ } ] ,
1165
+ } ;
1166
+ nodes[ 0 ]
1167
+ . node
1168
+ . splice_channel (
1169
+ & channel_id,
1170
+ & node_id_1,
1171
+ node_0_contribution. clone ( ) ,
1172
+ FEERATE_FLOOR_SATS_PER_KW ,
1173
+ None ,
1174
+ )
1175
+ . unwrap ( ) ;
1176
+ assert ! ( nodes[ 0 ] . node. get_and_clear_pending_msg_events( ) . is_empty( ) ) ;
1177
+
1178
+ let node_1_contribution = SpliceContribution :: SpliceOut {
1179
+ outputs : vec ! [ TxOut {
1180
+ value: Amount :: from_sat( splice_out_sat) ,
1181
+ script_pubkey: nodes[ 1 ] . wallet_source. get_change_script( ) . unwrap( ) ,
1182
+ } ] ,
1183
+ } ;
1184
+ nodes[ 1 ]
1185
+ . node
1186
+ . splice_channel (
1187
+ & channel_id,
1188
+ & node_id_0,
1189
+ node_1_contribution. clone ( ) ,
1190
+ FEERATE_FLOOR_SATS_PER_KW ,
1191
+ None ,
1192
+ )
1193
+ . unwrap ( ) ;
1194
+ assert ! ( nodes[ 1 ] . node. get_and_clear_pending_msg_events( ) . is_empty( ) ) ;
1195
+
1196
+ if reload {
1197
+ let encoded_monitor_0 = get_monitor ! ( nodes[ 0 ] , channel_id) . encode ( ) ;
1198
+ reload_node ! (
1199
+ nodes[ 0 ] ,
1200
+ nodes[ 0 ] . node. encode( ) ,
1201
+ & [ & encoded_monitor_0] ,
1202
+ persister_0a,
1203
+ chain_monitor_0a,
1204
+ node_0a
1205
+ ) ;
1206
+ let encoded_monitor_1 = get_monitor ! ( nodes[ 1 ] , channel_id) . encode ( ) ;
1207
+ reload_node ! (
1208
+ nodes[ 1 ] ,
1209
+ nodes[ 1 ] . node. encode( ) ,
1210
+ & [ & encoded_monitor_1] ,
1211
+ persister_1a,
1212
+ chain_monitor_1a,
1213
+ node_1a
1214
+ ) ;
1215
+ }
1216
+
1217
+ // Reconnect the nodes. Both nodes should attempt quiescence as the initiator, but only one will
1218
+ // be it via the tie-breaker.
1219
+ let mut reconnect_args = ReconnectArgs :: new ( & nodes[ 0 ] , & nodes[ 1 ] ) ;
1220
+ reconnect_args. send_channel_ready = ( true , true ) ;
1221
+ if !use_0conf {
1222
+ reconnect_args. send_announcement_sigs = ( true , true ) ;
1223
+ }
1224
+ reconnect_args. send_stfu = ( true , true ) ;
1225
+ reconnect_nodes ( reconnect_args) ;
1226
+ let splice_init = get_event_msg ! ( nodes[ 0 ] , MessageSendEvent :: SendSpliceInit , node_id_1) ;
1227
+ assert ! ( nodes[ 1 ] . node. get_and_clear_pending_msg_events( ) . is_empty( ) ) ;
1228
+
1229
+ let ( prev_funding_outpoint, prev_funding_script) = nodes[ 0 ]
1230
+ . chain_monitor
1231
+ . chain_monitor
1232
+ . get_monitor ( channel_id)
1233
+ . map ( |monitor| ( monitor. get_funding_txo ( ) , monitor. get_funding_script ( ) ) )
1234
+ . unwrap ( ) ;
1235
+
1236
+ // Negotiate the first splice to completion.
1237
+ let initial_commit_sig = negotiate_splice_tx_with_init (
1238
+ & nodes[ 0 ] ,
1239
+ & nodes[ 1 ] ,
1240
+ channel_id,
1241
+ node_0_contribution,
1242
+ & splice_init,
1243
+ ) ;
1244
+ let ( splice_tx, splice_locked) =
1245
+ sign_interactive_funding_tx ( & nodes[ 0 ] , & nodes[ 1 ] , initial_commit_sig, use_0conf) ;
1246
+
1247
+ let splice_locked = if use_0conf {
1248
+ let ( splice_locked, for_node_id) = splice_locked. unwrap ( ) ;
1249
+ assert_eq ! ( for_node_id, node_id_1) ;
1250
+ splice_locked
1251
+ } else {
1252
+ assert ! ( splice_locked. is_none( ) ) ;
1253
+
1254
+ mine_transaction ( & nodes[ 0 ] , & splice_tx) ;
1255
+ mine_transaction ( & nodes[ 1 ] , & splice_tx) ;
1256
+
1257
+ // Mine enough blocks for the first splice to become locked.
1258
+ connect_blocks ( & nodes[ 0 ] , ANTI_REORG_DELAY - 1 ) ;
1259
+ connect_blocks ( & nodes[ 1 ] , ANTI_REORG_DELAY - 1 ) ;
1260
+
1261
+ get_event_msg ! ( nodes[ 0 ] , MessageSendEvent :: SendSpliceLocked , node_id_1)
1262
+ } ;
1263
+ nodes[ 1 ] . node . handle_splice_locked ( node_id_0, & splice_locked) ;
1264
+
1265
+ // We should see the node which lost the tie-breaker attempt their splice now by first
1266
+ // negotiating quiescence, but their `stfu` won't be sent until after another reconnection.
1267
+ let msg_events = nodes[ 1 ] . node . get_and_clear_pending_msg_events ( ) ;
1268
+ assert_eq ! ( msg_events. len( ) , if use_0conf { 2 } else { 3 } , "{msg_events:?}" ) ;
1269
+ if let MessageSendEvent :: SendSpliceLocked { ref msg, .. } = & msg_events[ 0 ] {
1270
+ nodes[ 0 ] . node . handle_splice_locked ( node_id_1, msg) ;
1271
+ if use_0conf {
1272
+ // TODO(splicing): Revisit splice transaction rebroadcasts.
1273
+ let txn_0 = nodes[ 0 ] . tx_broadcaster . txn_broadcast ( ) ;
1274
+ assert_eq ! ( txn_0. len( ) , 1 ) ;
1275
+ assert_eq ! ( & txn_0[ 0 ] , & splice_tx) ;
1276
+ mine_transaction ( & nodes[ 0 ] , & splice_tx) ;
1277
+ mine_transaction ( & nodes[ 1 ] , & splice_tx) ;
1278
+ }
1279
+ } else {
1280
+ panic ! ( "Unexpected event {:?}" , & msg_events[ 0 ] ) ;
1281
+ }
1282
+ if !use_0conf {
1283
+ if let MessageSendEvent :: SendAnnouncementSignatures { ref msg, .. } = & msg_events[ 1 ] {
1284
+ nodes[ 0 ] . node . handle_announcement_signatures ( node_id_1, msg) ;
1285
+ } else {
1286
+ panic ! ( "Unexpected event {:?}" , & msg_events[ 1 ] ) ;
1287
+ }
1288
+ }
1289
+ assert ! ( matches!(
1290
+ & msg_events[ if use_0conf { 1 } else { 2 } ] ,
1291
+ MessageSendEvent :: SendStfu { .. }
1292
+ ) ) ;
1293
+
1294
+ let msg_events = nodes[ 0 ] . node . get_and_clear_pending_msg_events ( ) ;
1295
+ assert_eq ! ( msg_events. len( ) , if use_0conf { 0 } else { 2 } , "{msg_events:?}" ) ;
1296
+ if !use_0conf {
1297
+ if let MessageSendEvent :: SendAnnouncementSignatures { ref msg, .. } = & msg_events[ 0 ] {
1298
+ nodes[ 1 ] . node . handle_announcement_signatures ( node_id_0, msg) ;
1299
+ } else {
1300
+ panic ! ( "Unexpected event {:?}" , & msg_events[ 1 ] ) ;
1301
+ }
1302
+ assert ! ( matches!( & msg_events[ 1 ] , MessageSendEvent :: BroadcastChannelAnnouncement { .. } ) ) ;
1303
+ }
1304
+
1305
+ let msg_events = nodes[ 1 ] . node . get_and_clear_pending_msg_events ( ) ;
1306
+ assert_eq ! ( msg_events. len( ) , if use_0conf { 0 } else { 1 } , "{msg_events:?}" ) ;
1307
+ if !use_0conf {
1308
+ assert ! ( matches!( & msg_events[ 0 ] , MessageSendEvent :: BroadcastChannelAnnouncement { .. } ) ) ;
1309
+ }
1310
+
1311
+ expect_channel_ready_event ( & nodes[ 0 ] , & node_id_1) ;
1312
+ check_added_monitors ( & nodes[ 0 ] , 1 ) ;
1313
+ expect_channel_ready_event ( & nodes[ 1 ] , & node_id_0) ;
1314
+ check_added_monitors ( & nodes[ 1 ] , 1 ) ;
1315
+
1316
+ // Remove the corresponding outputs and transactions the chain source is watching for the
1317
+ // old funding as it is no longer being tracked.
1318
+ nodes[ 0 ]
1319
+ . chain_source
1320
+ . remove_watched_txn_and_outputs ( prev_funding_outpoint, prev_funding_script. clone ( ) ) ;
1321
+ nodes[ 1 ]
1322
+ . chain_source
1323
+ . remove_watched_txn_and_outputs ( prev_funding_outpoint, prev_funding_script) ;
1324
+
1325
+ // Reconnect the nodes. This should trigger the node which lost the tie-breaker to resend `stfu`
1326
+ // for their splice attempt.
1327
+ if reload {
1328
+ let encoded_monitor_0 = get_monitor ! ( nodes[ 0 ] , channel_id) . encode ( ) ;
1329
+ reload_node ! (
1330
+ nodes[ 0 ] ,
1331
+ nodes[ 0 ] . node. encode( ) ,
1332
+ & [ & encoded_monitor_0] ,
1333
+ persister_0b,
1334
+ chain_monitor_0b,
1335
+ node_0b
1336
+ ) ;
1337
+ let encoded_monitor_1 = get_monitor ! ( nodes[ 1 ] , channel_id) . encode ( ) ;
1338
+ reload_node ! (
1339
+ nodes[ 1 ] ,
1340
+ nodes[ 1 ] . node. encode( ) ,
1341
+ & [ & encoded_monitor_1] ,
1342
+ persister_1b,
1343
+ chain_monitor_1b,
1344
+ node_1b
1345
+ ) ;
1346
+ } else {
1347
+ nodes[ 0 ] . node . peer_disconnected ( node_id_1) ;
1348
+ nodes[ 1 ] . node . peer_disconnected ( node_id_0) ;
1349
+ }
1350
+ let mut reconnect_args = ReconnectArgs :: new ( & nodes[ 0 ] , & nodes[ 1 ] ) ;
1351
+ if !use_0conf {
1352
+ reconnect_args. send_announcement_sigs = ( true , true ) ;
1353
+ }
1354
+ reconnect_args. send_stfu = ( true , false ) ;
1355
+ reconnect_nodes ( reconnect_args) ;
1356
+
1357
+ // Drive the second splice to completion.
1358
+ let msg_events = nodes[ 0 ] . node . get_and_clear_pending_msg_events ( ) ;
1359
+ assert_eq ! ( msg_events. len( ) , 1 , "{msg_events:?}" ) ;
1360
+ if let MessageSendEvent :: SendStfu { ref msg, .. } = msg_events[ 0 ] {
1361
+ nodes[ 1 ] . node . handle_stfu ( node_id_0, msg) ;
1362
+ } else {
1363
+ panic ! ( "Unexpected event {:?}" , & msg_events[ 0 ] ) ;
1364
+ }
1365
+
1366
+ let splice_init = get_event_msg ! ( nodes[ 1 ] , MessageSendEvent :: SendSpliceInit , node_id_0) ;
1367
+ let initial_commit_sig = negotiate_splice_tx_with_init (
1368
+ & nodes[ 1 ] ,
1369
+ & nodes[ 0 ] ,
1370
+ channel_id,
1371
+ node_1_contribution,
1372
+ & splice_init,
1373
+ ) ;
1374
+ let ( splice_tx, splice_locked) =
1375
+ sign_interactive_funding_tx ( & nodes[ 1 ] , & nodes[ 0 ] , initial_commit_sig, use_0conf) ;
1376
+
1377
+ if use_0conf {
1378
+ let ( splice_locked, for_node_id) = splice_locked. unwrap ( ) ;
1379
+ assert_eq ! ( for_node_id, node_id_0) ;
1380
+ lock_splice ( & nodes[ 1 ] , & nodes[ 0 ] , & splice_locked, true ) ;
1381
+ } else {
1382
+ assert ! ( splice_locked. is_none( ) ) ;
1383
+ mine_transaction ( & nodes[ 0 ] , & splice_tx) ;
1384
+ mine_transaction ( & nodes[ 1 ] , & splice_tx) ;
1385
+ lock_splice_after_blocks ( & nodes[ 1 ] , & nodes[ 0 ] , ANTI_REORG_DELAY - 1 ) ;
1386
+ }
1387
+
1388
+ // Sanity check that we can still make a test payment.
1389
+ send_payment ( & nodes[ 0 ] , & [ & nodes[ 1 ] ] , 1_000_000 ) ;
1390
+ }
0 commit comments