@@ -3431,3 +3431,72 @@ fn test_reload_mon_update_completion_actions() {
34313431 do_test_reload_mon_update_completion_actions ( true ) ;
34323432 do_test_reload_mon_update_completion_actions ( false ) ;
34333433}
3434+
3435+ fn do_test_glacial_peer_cant_hang ( hold_chan_a : bool ) {
3436+ // Test that if a peer manages to send an `update_fulfill_htlc` message without a
3437+ // `commitment_signed`, disconnects, then replays the `update_fulfill_htlc` message it doesn't
3438+ // result in a channel hang. This was previously broken as the `DuplicateClaim` case wasn't
3439+ // handled when claiming an HTLC and handling wasn't added when completion actions were added
3440+ // (which must always complete at some point).
3441+ let chanmon_cfgs = create_chanmon_cfgs ( 3 ) ;
3442+ let node_cfgs = create_node_cfgs ( 3 , & chanmon_cfgs) ;
3443+
3444+ let node_chanmgrs = create_node_chanmgrs ( 3 , & node_cfgs, & [ None , None , None ] ) ;
3445+ let mut nodes = create_network ( 3 , & node_cfgs, & node_chanmgrs) ;
3446+
3447+ create_announced_chan_between_nodes ( & nodes, 0 , 1 ) ;
3448+ create_announced_chan_between_nodes ( & nodes, 1 , 2 ) ;
3449+
3450+ // Route a payment from A, through B, to C, then claim it on C. Replay the
3451+ // `update_fulfill_htlc` twice on B to check that B doesn't hang.
3452+ let ( payment_preimage, payment_hash, ..) = route_payment ( & nodes[ 0 ] , & [ & nodes[ 1 ] , & nodes[ 2 ] ] , 1_000_000 ) ;
3453+
3454+ nodes[ 2 ] . node . claim_funds ( payment_preimage) ;
3455+ check_added_monitors ( & nodes[ 2 ] , 1 ) ;
3456+ expect_payment_claimed ! ( nodes[ 2 ] , payment_hash, 1_000_000 ) ;
3457+
3458+ let cs_updates = get_htlc_update_msgs ( & nodes[ 2 ] , & nodes[ 1 ] . node . get_our_node_id ( ) ) ;
3459+ if hold_chan_a {
3460+ // The first update will be on the A <-> B channel, which we allow to complete.
3461+ chanmon_cfgs[ 1 ] . persister . set_update_ret ( ChannelMonitorUpdateStatus :: InProgress ) ;
3462+ }
3463+ nodes[ 1 ] . node . handle_update_fulfill_htlc ( & nodes[ 2 ] . node . get_our_node_id ( ) , & cs_updates. update_fulfill_htlcs [ 0 ] ) ;
3464+ check_added_monitors ( & nodes[ 1 ] , 1 ) ;
3465+
3466+ if !hold_chan_a {
3467+ let bs_updates = get_htlc_update_msgs ( & nodes[ 1 ] , & nodes[ 0 ] . node . get_our_node_id ( ) ) ;
3468+ nodes[ 0 ] . node . handle_update_fulfill_htlc ( & nodes[ 1 ] . node . get_our_node_id ( ) , & bs_updates. update_fulfill_htlcs [ 0 ] ) ;
3469+ commitment_signed_dance ! ( nodes[ 0 ] , nodes[ 1 ] , bs_updates. commitment_signed, false ) ;
3470+ expect_payment_sent ! ( & nodes[ 0 ] , payment_preimage) ;
3471+ }
3472+
3473+ nodes[ 1 ] . node . peer_disconnected ( & nodes[ 2 ] . node . get_our_node_id ( ) ) ;
3474+ nodes[ 2 ] . node . peer_disconnected ( & nodes[ 1 ] . node . get_our_node_id ( ) ) ;
3475+
3476+ let mut reconnect = ReconnectArgs :: new ( & nodes[ 1 ] , & nodes[ 2 ] ) ;
3477+ reconnect. pending_htlc_claims = ( 1 , 0 ) ;
3478+ reconnect_nodes ( reconnect) ;
3479+
3480+ if !hold_chan_a {
3481+ expect_payment_forwarded ! ( nodes[ 1 ] , nodes[ 0 ] , nodes[ 2 ] , Some ( 1000 ) , false , false ) ;
3482+ send_payment ( & nodes[ 0 ] , & [ & nodes[ 1 ] , & nodes[ 2 ] ] , 100_000 ) ;
3483+ } else {
3484+ assert ! ( nodes[ 1 ] . node. get_and_clear_pending_events( ) . is_empty( ) ) ;
3485+ assert ! ( nodes[ 1 ] . node. get_and_clear_pending_msg_events( ) . is_empty( ) ) ;
3486+
3487+ let ( route, payment_hash_2, _, payment_secret_2) = get_route_and_payment_hash ! ( & nodes[ 1 ] , nodes[ 2 ] , 1_000_000 ) ;
3488+
3489+ nodes[ 1 ] . node . send_payment_with_route ( & route, payment_hash_2,
3490+ RecipientOnionFields :: secret_only ( payment_secret_2) , PaymentId ( payment_hash_2. 0 ) ) . unwrap ( ) ;
3491+ check_added_monitors ( & nodes[ 1 ] , 0 ) ;
3492+
3493+ assert ! ( nodes[ 1 ] . node. get_and_clear_pending_events( ) . is_empty( ) ) ;
3494+ assert ! ( nodes[ 1 ] . node. get_and_clear_pending_msg_events( ) . is_empty( ) ) ;
3495+ }
3496+ }
3497+
3498+ #[ test]
3499+ fn test_glacial_peer_cant_hang ( ) {
3500+ do_test_glacial_peer_cant_hang ( false ) ;
3501+ do_test_glacial_peer_cant_hang ( true ) ;
3502+ }
0 commit comments