@@ -198,6 +198,61 @@ 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_a_responses = nodes[ 0 ] . node . get_and_clear_pending_msg_events ( ) ;
223
+ assert_eq ! ( node_a_responses[ 0 ] , MessageSendEvent :: SendShutdown {
224
+ node_id: nodes[ 1 ] . node. get_our_node_id( ) ,
225
+ msg: node_0_shutdown,
226
+ } ) ;
227
+ if let MessageSendEvent :: HandleError { action : msgs:: ErrorAction :: SendWarningMessage { .. } , .. }
228
+ = node_a_responses[ 1 ] { } else { panic ! ( ) ; }
229
+
230
+ let node_1_shutdown = get_event_msg ! ( nodes[ 1 ] , MessageSendEvent :: SendShutdown , nodes[ 0 ] . node. get_our_node_id( ) ) ;
231
+
232
+ assert ! ( nodes[ 0 ] . node. get_and_clear_pending_msg_events( ) . is_empty( ) ) ;
233
+ assert ! ( nodes[ 1 ] . node. get_and_clear_pending_msg_events( ) . is_empty( ) ) ;
234
+
235
+ claim_payment ( & nodes[ 0 ] , & [ & nodes[ 1 ] ] , payment_preimage) ;
236
+
237
+ // Assume that LND will eventually respond to our Shutdown if we clear all the remaining HTLCs
238
+ nodes[ 0 ] . node . handle_shutdown ( & nodes[ 1 ] . node . get_our_node_id ( ) , & node_1_shutdown) ;
239
+
240
+ // ClosingSignNegotion process
241
+ let node_0_closing_signed = get_event_msg ! ( nodes[ 0 ] , MessageSendEvent :: SendClosingSigned , nodes[ 1 ] . node. get_our_node_id( ) ) ;
242
+ nodes[ 1 ] . node . handle_closing_signed ( & nodes[ 0 ] . node . get_our_node_id ( ) , & node_0_closing_signed) ;
243
+ let node_1_closing_signed = get_event_msg ! ( nodes[ 1 ] , MessageSendEvent :: SendClosingSigned , nodes[ 0 ] . node. get_our_node_id( ) ) ;
244
+ nodes[ 0 ] . node . handle_closing_signed ( & nodes[ 1 ] . node . get_our_node_id ( ) , & node_1_closing_signed) ;
245
+ let ( _, node_0_2nd_closing_signed) = get_closing_signed_broadcast ! ( nodes[ 0 ] . node, nodes[ 1 ] . node. get_our_node_id( ) ) ;
246
+ nodes[ 1 ] . node . handle_closing_signed ( & nodes[ 0 ] . node . get_our_node_id ( ) , & node_0_2nd_closing_signed. unwrap ( ) ) ;
247
+ let ( _, node_1_none) = get_closing_signed_broadcast ! ( nodes[ 1 ] . node, nodes[ 0 ] . node. get_our_node_id( ) ) ;
248
+ assert ! ( node_1_none. is_none( ) ) ;
249
+ check_closed_event ! ( nodes[ 0 ] , 1 , ClosureReason :: CooperativeClosure , [ nodes[ 1 ] . node. get_our_node_id( ) ] , 100000 ) ;
250
+ check_closed_event ! ( nodes[ 1 ] , 1 , ClosureReason :: CooperativeClosure , [ nodes[ 0 ] . node. get_our_node_id( ) ] , 100000 ) ;
251
+
252
+ // Shutdown basically removes the channelDetails, testing of shutdowncomplete state unnecessary
253
+ assert ! ( nodes[ 0 ] . node. list_channels( ) . is_empty( ) ) ;
254
+ }
255
+
201
256
#[ test]
202
257
fn expect_channel_shutdown_state_with_force_closure ( ) {
203
258
// Test sending a shutdown prior to channel_ready after funding generation
0 commit comments