@@ -3031,6 +3031,92 @@ fn held_htlc_timeout() {
30313031 ) ;
30323032}
30333033
3034+ #[ test]
3035+ fn fail_held_htlc_on_reconnect ( ) {
3036+ // Test that if a held HTLC by the sender LSP fails but the async sender is offline, the HTLC
3037+ // is failed on reconnect instead of FC the channel.
3038+ let chanmon_cfgs = create_chanmon_cfgs ( 4 ) ;
3039+ let node_cfgs = create_node_cfgs ( 4 , & chanmon_cfgs) ;
3040+
3041+ let ( sender_cfg, recipient_cfg) = ( often_offline_node_cfg ( ) , often_offline_node_cfg ( ) ) ;
3042+ let mut sender_lsp_cfg = test_default_channel_config ( ) ;
3043+ sender_lsp_cfg. enable_htlc_hold = true ;
3044+ let mut invoice_server_cfg = test_default_channel_config ( ) ;
3045+ invoice_server_cfg. accept_forwards_to_priv_channels = true ;
3046+
3047+ let node_chanmgrs = create_node_chanmgrs (
3048+ 4 ,
3049+ & node_cfgs,
3050+ & [ Some ( sender_cfg) , Some ( sender_lsp_cfg) , Some ( invoice_server_cfg) , Some ( recipient_cfg) ] ,
3051+ ) ;
3052+ let nodes = create_network ( 4 , & node_cfgs, & node_chanmgrs) ;
3053+ let chan = create_unannounced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 1_000_000 , 0 ) ;
3054+ create_announced_chan_between_nodes_with_value ( & nodes, 1 , 2 , 1_000_000 , 0 ) ;
3055+ create_unannounced_chan_between_nodes_with_value ( & nodes, 2 , 3 , 1_000_000 , 0 ) ;
3056+ unify_blockheight_across_nodes ( & nodes) ;
3057+ let sender = & nodes[ 0 ] ;
3058+ let sender_lsp = & nodes[ 1 ] ;
3059+ let invoice_server = & nodes[ 2 ] ;
3060+ let recipient = & nodes[ 3 ] ;
3061+
3062+ let amt_msat = 5000 ;
3063+ let ( _, peer_node_id, static_invoice_om) = build_async_offer_and_init_payment ( amt_msat, & nodes) ;
3064+ let payment_hash =
3065+ lock_in_htlc_for_static_invoice ( & static_invoice_om, peer_node_id, sender, sender_lsp) ;
3066+
3067+ sender_lsp. node . process_pending_htlc_forwards ( ) ;
3068+ let ( peer_id, held_htlc_om) =
3069+ extract_held_htlc_available_oms ( sender, & [ sender_lsp, invoice_server, recipient] )
3070+ . pop ( )
3071+ . unwrap ( ) ;
3072+ recipient. onion_messenger . handle_onion_message ( peer_id, & held_htlc_om) ;
3073+
3074+ let _ = extract_release_htlc_oms ( recipient, & [ sender, sender_lsp, invoice_server] ) ;
3075+
3076+ // Disconnect async sender <-> sender LSP
3077+ sender. node . peer_disconnected ( sender_lsp. node . get_our_node_id ( ) ) ;
3078+ sender_lsp. node . peer_disconnected ( sender. node . get_our_node_id ( ) ) ;
3079+
3080+ // Connect blocks such that they cause the HTLC to timeout
3081+ let chan_id = chan. 0 . channel_id ;
3082+ let channel =
3083+ sender. node . list_channels ( ) . iter ( ) . find ( |c| c. channel_id == chan_id) . unwrap ( ) . clone ( ) ;
3084+ let htlc_expiry = channel
3085+ . pending_outbound_htlcs
3086+ . iter ( )
3087+ . find ( |htlc| htlc. payment_hash == payment_hash)
3088+ . unwrap ( )
3089+ . cltv_expiry ;
3090+ let blocks_to_connect = htlc_expiry - sender. best_block_info ( ) . 1 + 100 ;
3091+ connect_blocks ( sender, blocks_to_connect) ;
3092+ connect_blocks ( sender_lsp, blocks_to_connect) ;
3093+
3094+ sender_lsp. node . process_pending_htlc_forwards ( ) ;
3095+ let mut evs = sender_lsp. node . get_and_clear_pending_events ( ) ;
3096+ assert_eq ! ( evs. len( ) , 1 ) ;
3097+ match evs. pop ( ) . unwrap ( ) {
3098+ Event :: HTLCHandlingFailed { failure_type, failure_reason, .. } => {
3099+ assert ! ( matches!( failure_type, HTLCHandlingFailureType :: InvalidForward { .. } ) ) ;
3100+ assert ! ( matches!(
3101+ failure_reason,
3102+ Some ( HTLCHandlingFailureReason :: Local {
3103+ reason: LocalHTLCFailureReason :: ForwardExpiryBuffer
3104+ } )
3105+ ) ) ;
3106+ } ,
3107+ _ => panic ! ( ) ,
3108+ }
3109+
3110+ // After reconnecting, check that HTLC was failed and channel is open.
3111+ let mut reconnect_args = ReconnectArgs :: new ( & sender, & sender_lsp) ;
3112+ reconnect_args. pending_cell_htlc_fails . 0 = 1 ;
3113+ reconnect_nodes ( reconnect_args) ;
3114+
3115+ expect_payment_failed ! ( sender, payment_hash, false ) ;
3116+ assert_eq ! ( sender. node. list_channels( ) . len( ) , 1 ) ;
3117+ assert_eq ! ( sender_lsp. node. list_channels( ) . len( ) , 2 ) ;
3118+ }
3119+
30343120#[ test]
30353121fn intercepted_hold_htlc ( ) {
30363122 // Test a payment `sender --> LSP --> recipient` such that the HTLC is both a hold htlc and an
0 commit comments