@@ -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
@@ -901,3 +917,293 @@ fn do_test_splice_reestablish(reload: bool, async_monitor_update: bool) {
901
917
. chain_source
902
918
. remove_watched_txn_and_outputs ( prev_funding_outpoint, prev_funding_script) ;
903
919
}
920
+
921
+ #[ test]
922
+ fn test_propose_splice_while_disconnected ( ) {
923
+ do_test_propose_splice_while_disconnected ( false , false ) ;
924
+ do_test_propose_splice_while_disconnected ( false , true ) ;
925
+ do_test_propose_splice_while_disconnected ( true , false ) ;
926
+ do_test_propose_splice_while_disconnected ( true , true ) ;
927
+ }
928
+
929
+ fn do_test_propose_splice_while_disconnected ( reload : bool , use_0conf : bool ) {
930
+ // Test that both nodes are able to propose a splice while the counterparty is disconnected, and
931
+ // whoever doesn't go first due to the quiescence tie-breaker, will retry their splice after the
932
+ // first one becomes locked.
933
+ let chanmon_cfgs = create_chanmon_cfgs ( 2 ) ;
934
+ let node_cfgs = create_node_cfgs ( 2 , & chanmon_cfgs) ;
935
+ let ( persister_0a, persister_0b, persister_1a, persister_1b) ;
936
+ let ( chain_monitor_0a, chain_monitor_0b, chain_monitor_1a, chain_monitor_1b) ;
937
+ let mut config = test_default_channel_config ( ) ;
938
+ if use_0conf {
939
+ config. manually_accept_inbound_channels = true ;
940
+ config. channel_handshake_limits . trust_own_funding_0conf = true ;
941
+ }
942
+ let node_chanmgrs = create_node_chanmgrs ( 2 , & node_cfgs, & [ Some ( config. clone ( ) ) , Some ( config) ] ) ;
943
+ let ( node_0a, node_0b, node_1a, node_1b) ;
944
+ let mut nodes = create_network ( 2 , & node_cfgs, & node_chanmgrs) ;
945
+
946
+ let node_id_0 = nodes[ 0 ] . node . get_our_node_id ( ) ;
947
+ let node_id_1 = nodes[ 1 ] . node . get_our_node_id ( ) ;
948
+
949
+ let initial_channel_value_sat = 1_000_000 ;
950
+ let push_msat = initial_channel_value_sat / 2 * 1000 ;
951
+ let channel_id = if use_0conf {
952
+ let ( funding_tx, channel_id) = open_zero_conf_channel_with_value (
953
+ & nodes[ 0 ] ,
954
+ & nodes[ 1 ] ,
955
+ None ,
956
+ initial_channel_value_sat,
957
+ push_msat,
958
+ ) ;
959
+ mine_transaction ( & nodes[ 0 ] , & funding_tx) ;
960
+ mine_transaction ( & nodes[ 1 ] , & funding_tx) ;
961
+ channel_id
962
+ } else {
963
+ let ( _, _, channel_id, _) = create_announced_chan_between_nodes_with_value (
964
+ & nodes,
965
+ 0 ,
966
+ 1 ,
967
+ initial_channel_value_sat,
968
+ push_msat,
969
+ ) ;
970
+ channel_id
971
+ } ;
972
+
973
+ // Start with the nodes disconnected, and have each one attempt a splice.
974
+ nodes[ 0 ] . node . peer_disconnected ( node_id_1) ;
975
+ nodes[ 1 ] . node . peer_disconnected ( node_id_0) ;
976
+
977
+ let splice_out_sat = initial_channel_value_sat / 4 ;
978
+ let node_0_contribution = SpliceContribution :: SpliceOut {
979
+ outputs : vec ! [ TxOut {
980
+ value: Amount :: from_sat( splice_out_sat) ,
981
+ script_pubkey: nodes[ 0 ] . wallet_source. get_change_script( ) . unwrap( ) ,
982
+ } ] ,
983
+ } ;
984
+ nodes[ 0 ]
985
+ . node
986
+ . splice_channel (
987
+ & channel_id,
988
+ & node_id_1,
989
+ node_0_contribution. clone ( ) ,
990
+ FEERATE_FLOOR_SATS_PER_KW ,
991
+ None ,
992
+ )
993
+ . unwrap ( ) ;
994
+ assert ! ( nodes[ 0 ] . node. get_and_clear_pending_msg_events( ) . is_empty( ) ) ;
995
+
996
+ let node_1_contribution = SpliceContribution :: SpliceOut {
997
+ outputs : vec ! [ TxOut {
998
+ value: Amount :: from_sat( splice_out_sat) ,
999
+ script_pubkey: nodes[ 1 ] . wallet_source. get_change_script( ) . unwrap( ) ,
1000
+ } ] ,
1001
+ } ;
1002
+ nodes[ 1 ]
1003
+ . node
1004
+ . splice_channel (
1005
+ & channel_id,
1006
+ & node_id_0,
1007
+ node_1_contribution. clone ( ) ,
1008
+ FEERATE_FLOOR_SATS_PER_KW ,
1009
+ None ,
1010
+ )
1011
+ . unwrap ( ) ;
1012
+ assert ! ( nodes[ 1 ] . node. get_and_clear_pending_msg_events( ) . is_empty( ) ) ;
1013
+
1014
+ if reload {
1015
+ let encoded_monitor_0 = get_monitor ! ( nodes[ 0 ] , channel_id) . encode ( ) ;
1016
+ reload_node ! (
1017
+ nodes[ 0 ] ,
1018
+ nodes[ 0 ] . node. encode( ) ,
1019
+ & [ & encoded_monitor_0] ,
1020
+ persister_0a,
1021
+ chain_monitor_0a,
1022
+ node_0a
1023
+ ) ;
1024
+ let encoded_monitor_1 = get_monitor ! ( nodes[ 1 ] , channel_id) . encode ( ) ;
1025
+ reload_node ! (
1026
+ nodes[ 1 ] ,
1027
+ nodes[ 1 ] . node. encode( ) ,
1028
+ & [ & encoded_monitor_1] ,
1029
+ persister_1a,
1030
+ chain_monitor_1a,
1031
+ node_1a
1032
+ ) ;
1033
+ }
1034
+
1035
+ // Reconnect the nodes. Both nodes should attempt quiescence as the initiator, but only one will
1036
+ // be it via the tie-breaker.
1037
+ let mut reconnect_args = ReconnectArgs :: new ( & nodes[ 0 ] , & nodes[ 1 ] ) ;
1038
+ reconnect_args. send_channel_ready = ( true , true ) ;
1039
+ if !use_0conf {
1040
+ reconnect_args. send_announcement_sigs = ( true , true ) ;
1041
+ }
1042
+ reconnect_args. send_stfu = ( true , true ) ;
1043
+ reconnect_nodes ( reconnect_args) ;
1044
+ let splice_init = get_event_msg ! ( nodes[ 0 ] , MessageSendEvent :: SendSpliceInit , node_id_1) ;
1045
+ assert ! ( nodes[ 1 ] . node. get_and_clear_pending_msg_events( ) . is_empty( ) ) ;
1046
+
1047
+ let ( prev_funding_outpoint, prev_funding_script) = nodes[ 0 ]
1048
+ . chain_monitor
1049
+ . chain_monitor
1050
+ . get_monitor ( channel_id)
1051
+ . map ( |monitor| ( monitor. get_funding_txo ( ) , monitor. get_funding_script ( ) ) )
1052
+ . unwrap ( ) ;
1053
+
1054
+ // Negotiate the first splice to completion.
1055
+ let initial_commit_sig = negotiate_splice_tx_with_init (
1056
+ & nodes[ 0 ] ,
1057
+ & nodes[ 1 ] ,
1058
+ channel_id,
1059
+ node_0_contribution,
1060
+ & splice_init,
1061
+ ) ;
1062
+ let ( splice_tx, splice_locked) =
1063
+ sign_interactive_funding_tx ( & nodes[ 0 ] , & nodes[ 1 ] , initial_commit_sig, use_0conf) ;
1064
+
1065
+ let splice_locked = if use_0conf {
1066
+ let ( splice_locked, for_node_id) = splice_locked. unwrap ( ) ;
1067
+ assert_eq ! ( for_node_id, node_id_1) ;
1068
+ splice_locked
1069
+ } else {
1070
+ assert ! ( splice_locked. is_none( ) ) ;
1071
+
1072
+ mine_transaction ( & nodes[ 0 ] , & splice_tx) ;
1073
+ mine_transaction ( & nodes[ 1 ] , & splice_tx) ;
1074
+
1075
+ // Mine enough blocks for the first splice to become locked.
1076
+ connect_blocks ( & nodes[ 0 ] , ANTI_REORG_DELAY - 1 ) ;
1077
+ connect_blocks ( & nodes[ 1 ] , ANTI_REORG_DELAY - 1 ) ;
1078
+
1079
+ get_event_msg ! ( nodes[ 0 ] , MessageSendEvent :: SendSpliceLocked , node_id_1)
1080
+ } ;
1081
+ nodes[ 1 ] . node . handle_splice_locked ( node_id_0, & splice_locked) ;
1082
+
1083
+ // We should see the node which lost the tie-breaker attempt their splice now by first
1084
+ // negotiating quiescence, but their `stfu` won't be sent until after another reconnection.
1085
+ let msg_events = nodes[ 1 ] . node . get_and_clear_pending_msg_events ( ) ;
1086
+ assert_eq ! ( msg_events. len( ) , if use_0conf { 2 } else { 3 } , "{msg_events:?}" ) ;
1087
+ if let MessageSendEvent :: SendSpliceLocked { ref msg, .. } = & msg_events[ 0 ] {
1088
+ nodes[ 0 ] . node . handle_splice_locked ( node_id_1, msg) ;
1089
+ if use_0conf {
1090
+ // TODO(splicing): Revisit splice transaction rebroadcasts.
1091
+ let txn_0 = nodes[ 0 ] . tx_broadcaster . txn_broadcast ( ) ;
1092
+ assert_eq ! ( txn_0. len( ) , 1 ) ;
1093
+ assert_eq ! ( & txn_0[ 0 ] , & splice_tx) ;
1094
+ mine_transaction ( & nodes[ 0 ] , & splice_tx) ;
1095
+ mine_transaction ( & nodes[ 1 ] , & splice_tx) ;
1096
+ }
1097
+ } else {
1098
+ panic ! ( "Unexpected event {:?}" , & msg_events[ 0 ] ) ;
1099
+ }
1100
+ if !use_0conf {
1101
+ if let MessageSendEvent :: SendAnnouncementSignatures { ref msg, .. } = & msg_events[ 1 ] {
1102
+ nodes[ 0 ] . node . handle_announcement_signatures ( node_id_1, msg) ;
1103
+ } else {
1104
+ panic ! ( "Unexpected event {:?}" , & msg_events[ 1 ] ) ;
1105
+ }
1106
+ }
1107
+ assert ! ( matches!(
1108
+ & msg_events[ if use_0conf { 1 } else { 2 } ] ,
1109
+ MessageSendEvent :: SendStfu { .. }
1110
+ ) ) ;
1111
+
1112
+ let msg_events = nodes[ 0 ] . node . get_and_clear_pending_msg_events ( ) ;
1113
+ assert_eq ! ( msg_events. len( ) , if use_0conf { 0 } else { 2 } , "{msg_events:?}" ) ;
1114
+ if !use_0conf {
1115
+ if let MessageSendEvent :: SendAnnouncementSignatures { ref msg, .. } = & msg_events[ 0 ] {
1116
+ nodes[ 1 ] . node . handle_announcement_signatures ( node_id_0, msg) ;
1117
+ } else {
1118
+ panic ! ( "Unexpected event {:?}" , & msg_events[ 1 ] ) ;
1119
+ }
1120
+ assert ! ( matches!( & msg_events[ 1 ] , MessageSendEvent :: BroadcastChannelAnnouncement { .. } ) ) ;
1121
+ }
1122
+
1123
+ let msg_events = nodes[ 1 ] . node . get_and_clear_pending_msg_events ( ) ;
1124
+ assert_eq ! ( msg_events. len( ) , if use_0conf { 0 } else { 1 } , "{msg_events:?}" ) ;
1125
+ if !use_0conf {
1126
+ assert ! ( matches!( & msg_events[ 0 ] , MessageSendEvent :: BroadcastChannelAnnouncement { .. } ) ) ;
1127
+ }
1128
+
1129
+ expect_channel_ready_event ( & nodes[ 0 ] , & node_id_1) ;
1130
+ check_added_monitors ( & nodes[ 0 ] , 1 ) ;
1131
+ expect_channel_ready_event ( & nodes[ 1 ] , & node_id_0) ;
1132
+ check_added_monitors ( & nodes[ 1 ] , 1 ) ;
1133
+
1134
+ // Remove the corresponding outputs and transactions the chain source is watching for the
1135
+ // old funding as it is no longer being tracked.
1136
+ nodes[ 0 ]
1137
+ . chain_source
1138
+ . remove_watched_txn_and_outputs ( prev_funding_outpoint, prev_funding_script. clone ( ) ) ;
1139
+ nodes[ 1 ]
1140
+ . chain_source
1141
+ . remove_watched_txn_and_outputs ( prev_funding_outpoint, prev_funding_script) ;
1142
+
1143
+ // Reconnect the nodes. This should trigger the node which lost the tie-breaker to resend `stfu`
1144
+ // for their splice attempt.
1145
+ if reload {
1146
+ let encoded_monitor_0 = get_monitor ! ( nodes[ 0 ] , channel_id) . encode ( ) ;
1147
+ reload_node ! (
1148
+ nodes[ 0 ] ,
1149
+ nodes[ 0 ] . node. encode( ) ,
1150
+ & [ & encoded_monitor_0] ,
1151
+ persister_0b,
1152
+ chain_monitor_0b,
1153
+ node_0b
1154
+ ) ;
1155
+ let encoded_monitor_1 = get_monitor ! ( nodes[ 1 ] , channel_id) . encode ( ) ;
1156
+ reload_node ! (
1157
+ nodes[ 1 ] ,
1158
+ nodes[ 1 ] . node. encode( ) ,
1159
+ & [ & encoded_monitor_1] ,
1160
+ persister_1b,
1161
+ chain_monitor_1b,
1162
+ node_1b
1163
+ ) ;
1164
+ } else {
1165
+ nodes[ 0 ] . node . peer_disconnected ( node_id_1) ;
1166
+ nodes[ 1 ] . node . peer_disconnected ( node_id_0) ;
1167
+ }
1168
+ let mut reconnect_args = ReconnectArgs :: new ( & nodes[ 0 ] , & nodes[ 1 ] ) ;
1169
+ reconnect_args. send_channel_ready = ( true , true ) ;
1170
+ if !use_0conf {
1171
+ reconnect_args. send_announcement_sigs = ( true , true ) ;
1172
+ }
1173
+ reconnect_args. send_stfu = ( true , false ) ;
1174
+ reconnect_nodes ( reconnect_args) ;
1175
+
1176
+ // Drive the second splice to completion.
1177
+ let msg_events = nodes[ 0 ] . node . get_and_clear_pending_msg_events ( ) ;
1178
+ assert_eq ! ( msg_events. len( ) , 1 , "{msg_events:?}" ) ;
1179
+ if let MessageSendEvent :: SendStfu { ref msg, .. } = msg_events[ 0 ] {
1180
+ nodes[ 1 ] . node . handle_stfu ( node_id_0, msg) ;
1181
+ } else {
1182
+ panic ! ( "Unexpected event {:?}" , & msg_events[ 0 ] ) ;
1183
+ }
1184
+
1185
+ let splice_init = get_event_msg ! ( nodes[ 1 ] , MessageSendEvent :: SendSpliceInit , node_id_0) ;
1186
+ let initial_commit_sig = negotiate_splice_tx_with_init (
1187
+ & nodes[ 1 ] ,
1188
+ & nodes[ 0 ] ,
1189
+ channel_id,
1190
+ node_1_contribution,
1191
+ & splice_init,
1192
+ ) ;
1193
+ let ( splice_tx, splice_locked) =
1194
+ sign_interactive_funding_tx ( & nodes[ 1 ] , & nodes[ 0 ] , initial_commit_sig, use_0conf) ;
1195
+
1196
+ if use_0conf {
1197
+ let ( splice_locked, for_node_id) = splice_locked. unwrap ( ) ;
1198
+ assert_eq ! ( for_node_id, node_id_0) ;
1199
+ lock_splice ( & nodes[ 1 ] , & nodes[ 0 ] , & splice_locked, true ) ;
1200
+ } else {
1201
+ assert ! ( splice_locked. is_none( ) ) ;
1202
+ mine_transaction ( & nodes[ 0 ] , & splice_tx) ;
1203
+ mine_transaction ( & nodes[ 1 ] , & splice_tx) ;
1204
+ lock_splice_after_blocks ( & nodes[ 1 ] , & nodes[ 0 ] , ANTI_REORG_DELAY - 1 ) ;
1205
+ }
1206
+
1207
+ // Sanity check that we can still make a test payment.
1208
+ send_payment ( & nodes[ 0 ] , & [ & nodes[ 1 ] ] , 1_000_000 ) ;
1209
+ }
0 commit comments