@@ -198,6 +198,55 @@ fn expect_channel_shutdown_state_with_htlc() {
198
198
assert ! ( nodes[ 0 ] . node. list_channels( ) . is_empty( ) ) ;
199
199
}
200
200
201
+ #[ test]
202
+ fn test_lnd_bug_6039 ( ) {
203
+ // LND sends a nonsense error message any time it gets a shutdown if there are still HTLCs
204
+ // pending. We currently swallow that error to work around LND's bug #6039. This test emulates
205
+ // the LND nonsense and ensures we at least kinda handle it.
206
+ let chanmon_cfgs = create_chanmon_cfgs ( 2 ) ;
207
+ let node_cfgs = create_node_cfgs ( 2 , & chanmon_cfgs) ;
208
+ let node_chanmgrs = create_node_chanmgrs ( 2 , & node_cfgs, & [ None , None ] ) ;
209
+ let mut nodes = create_network ( 2 , & node_cfgs, & node_chanmgrs) ;
210
+ let chan = create_announced_chan_between_nodes ( & nodes, 0 , 1 ) ;
211
+
212
+ let ( payment_preimage, payment_hash, _) = route_payment ( & nodes[ 0 ] , & [ & nodes[ 1 ] ] , 100_000 ) ;
213
+
214
+ nodes[ 0 ] . node . close_channel ( & chan. 2 , & nodes[ 1 ] . node . get_our_node_id ( ) ) . unwrap ( ) ;
215
+ let node_0_shutdown = get_event_msg ! ( nodes[ 0 ] , MessageSendEvent :: SendShutdown , nodes[ 1 ] . node. get_our_node_id( ) ) ;
216
+ nodes[ 1 ] . node . handle_shutdown ( & nodes[ 0 ] . node . get_our_node_id ( ) , & node_0_shutdown) ;
217
+
218
+ // Generate an lnd-like error message and check that we respond by simply screaming louder to
219
+ // see if LND will accept our protocol compliance.
220
+ let err_msg = msgs:: ErrorMessage { channel_id : chan. 2 , data : "link failed to shutdown" . to_string ( ) } ;
221
+ nodes[ 0 ] . node . handle_error ( & nodes[ 1 ] . node . get_our_node_id ( ) , & err_msg) ;
222
+ let _node_0_repeated_shutdown = get_event_msg ! ( nodes[ 0 ] , MessageSendEvent :: SendShutdown , nodes[ 1 ] . node. get_our_node_id( ) ) ;
223
+
224
+ let node_1_shutdown = get_event_msg ! ( nodes[ 1 ] , MessageSendEvent :: SendShutdown , nodes[ 0 ] . node. get_our_node_id( ) ) ;
225
+
226
+ assert ! ( nodes[ 0 ] . node. get_and_clear_pending_msg_events( ) . is_empty( ) ) ;
227
+ assert ! ( nodes[ 1 ] . node. get_and_clear_pending_msg_events( ) . is_empty( ) ) ;
228
+
229
+ claim_payment ( & nodes[ 0 ] , & [ & nodes[ 1 ] ] , payment_preimage) ;
230
+
231
+ // Assume that LND will eventually respond to our Shutdown if we clear all the remaining HTLCs
232
+ nodes[ 0 ] . node . handle_shutdown ( & nodes[ 1 ] . node . get_our_node_id ( ) , & node_1_shutdown) ;
233
+
234
+ // ClosingSignNegotion process
235
+ let node_0_closing_signed = get_event_msg ! ( nodes[ 0 ] , MessageSendEvent :: SendClosingSigned , nodes[ 1 ] . node. get_our_node_id( ) ) ;
236
+ nodes[ 1 ] . node . handle_closing_signed ( & nodes[ 0 ] . node . get_our_node_id ( ) , & node_0_closing_signed) ;
237
+ let node_1_closing_signed = get_event_msg ! ( nodes[ 1 ] , MessageSendEvent :: SendClosingSigned , nodes[ 0 ] . node. get_our_node_id( ) ) ;
238
+ nodes[ 0 ] . node . handle_closing_signed ( & nodes[ 1 ] . node . get_our_node_id ( ) , & node_1_closing_signed) ;
239
+ let ( _, node_0_2nd_closing_signed) = get_closing_signed_broadcast ! ( nodes[ 0 ] . node, nodes[ 1 ] . node. get_our_node_id( ) ) ;
240
+ nodes[ 1 ] . node . handle_closing_signed ( & nodes[ 0 ] . node . get_our_node_id ( ) , & node_0_2nd_closing_signed. unwrap ( ) ) ;
241
+ let ( _, node_1_none) = get_closing_signed_broadcast ! ( nodes[ 1 ] . node, nodes[ 0 ] . node. get_our_node_id( ) ) ;
242
+ assert ! ( node_1_none. is_none( ) ) ;
243
+ check_closed_event ! ( nodes[ 0 ] , 1 , ClosureReason :: CooperativeClosure , [ nodes[ 1 ] . node. get_our_node_id( ) ] , 100000 ) ;
244
+ check_closed_event ! ( nodes[ 1 ] , 1 , ClosureReason :: CooperativeClosure , [ nodes[ 0 ] . node. get_our_node_id( ) ] , 100000 ) ;
245
+
246
+ // Shutdown basically removes the channelDetails, testing of shutdowncomplete state unnecessary
247
+ assert ! ( nodes[ 0 ] . node. list_channels( ) . is_empty( ) ) ;
248
+ }
249
+
201
250
#[ test]
202
251
fn expect_channel_shutdown_state_with_force_closure ( ) {
203
252
// Test sending a shutdown prior to channel_ready after funding generation
0 commit comments