@@ -2587,6 +2587,131 @@ fn held_htlc_timeout() {
25872587 ) ;
25882588}
25892589
2590+ #[ test]
2591+ fn fallback_to_one_hop_release_htlc_path ( ) {
2592+ // Check that if the sender's LSP's message router fails to find a blinded path when creating a
2593+ // path for the release_held_htlc message, they will fall back to manually creating a 1-hop
2594+ // blinded path.
2595+ let chanmon_cfgs = create_chanmon_cfgs ( 4 ) ;
2596+ let node_cfgs = create_node_cfgs ( 4 , & chanmon_cfgs) ;
2597+
2598+ let ( sender_cfg, recipient_cfg) = ( often_offline_node_cfg ( ) , often_offline_node_cfg ( ) ) ;
2599+ let mut sender_lsp_cfg = test_default_channel_config ( ) ;
2600+ sender_lsp_cfg. enable_htlc_hold = true ;
2601+ let mut invoice_server_cfg = test_default_channel_config ( ) ;
2602+ invoice_server_cfg. accept_forwards_to_priv_channels = true ;
2603+
2604+ let node_chanmgrs = create_node_chanmgrs (
2605+ 4 ,
2606+ & node_cfgs,
2607+ & [ Some ( sender_cfg) , Some ( sender_lsp_cfg) , Some ( invoice_server_cfg) , Some ( recipient_cfg) ] ,
2608+ ) ;
2609+ let nodes = create_network ( 4 , & node_cfgs, & node_chanmgrs) ;
2610+ create_unannounced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 1_000_000 , 0 ) ;
2611+ create_announced_chan_between_nodes_with_value ( & nodes, 1 , 2 , 1_000_000 , 0 ) ;
2612+ create_unannounced_chan_between_nodes_with_value ( & nodes, 2 , 3 , 1_000_000 , 0 ) ;
2613+ // Make sure all nodes are at the same block height
2614+ let node_max_height =
2615+ nodes. iter ( ) . map ( |node| node. blocks . lock ( ) . unwrap ( ) . len ( ) ) . max ( ) . unwrap ( ) as u32 ;
2616+ connect_blocks ( & nodes[ 0 ] , node_max_height - nodes[ 0 ] . best_block_info ( ) . 1 ) ;
2617+ connect_blocks ( & nodes[ 1 ] , node_max_height - nodes[ 1 ] . best_block_info ( ) . 1 ) ;
2618+ connect_blocks ( & nodes[ 2 ] , node_max_height - nodes[ 2 ] . best_block_info ( ) . 1 ) ;
2619+ connect_blocks ( & nodes[ 3 ] , node_max_height - nodes[ 3 ] . best_block_info ( ) . 1 ) ;
2620+ let sender = & nodes[ 0 ] ;
2621+ let sender_lsp = & nodes[ 1 ] ;
2622+ let invoice_server = & nodes[ 2 ] ;
2623+ let recipient = & nodes[ 3 ] ;
2624+
2625+ let recipient_id = vec ! [ 42 ; 32 ] ;
2626+ let inv_server_paths =
2627+ invoice_server. node . blinded_paths_for_async_recipient ( recipient_id. clone ( ) , None ) . unwrap ( ) ;
2628+ recipient. node . set_paths_to_static_invoice_server ( inv_server_paths) . unwrap ( ) ;
2629+ expect_offer_paths_requests ( recipient, & [ sender, sender_lsp, invoice_server] ) ;
2630+ let invoice =
2631+ pass_static_invoice_server_messages ( invoice_server, recipient, recipient_id. clone ( ) )
2632+ . invoice ;
2633+
2634+ let offer = recipient. node . get_async_receive_offer ( ) . unwrap ( ) ;
2635+ let amt_msat = 5000 ;
2636+ let payment_id = PaymentId ( [ 1 ; 32 ] ) ;
2637+ let params = RouteParametersConfig :: default ( ) ;
2638+ sender
2639+ . node
2640+ . pay_for_offer ( & offer, None , Some ( amt_msat) , None , payment_id, Retry :: Attempts ( 1 ) , params)
2641+ . unwrap ( ) ;
2642+
2643+ // Forward invreq to server, pass static invoice back, check that htlc was locked in/monitor was
2644+ // added
2645+ let ( peer_id, invreq_om) = extract_invoice_request_om ( sender, & [ sender_lsp, invoice_server] ) ;
2646+ invoice_server. onion_messenger . handle_onion_message ( peer_id, & invreq_om) ;
2647+
2648+ let mut events = invoice_server. node . get_and_clear_pending_events ( ) ;
2649+ assert_eq ! ( events. len( ) , 1 ) ;
2650+ let reply_path = match events. pop ( ) . unwrap ( ) {
2651+ Event :: StaticInvoiceRequested { recipient_id : ev_id, invoice_slot : _, reply_path } => {
2652+ assert_eq ! ( recipient_id, ev_id) ;
2653+ reply_path
2654+ } ,
2655+ _ => panic ! ( ) ,
2656+ } ;
2657+
2658+ invoice_server. node . send_static_invoice ( invoice. clone ( ) , reply_path) . unwrap ( ) ;
2659+ let ( peer_node_id, static_invoice_om, _) =
2660+ extract_static_invoice_om ( invoice_server, & [ sender_lsp, sender, recipient] ) ;
2661+
2662+ // The sender should lock in the held HTLC with their LSP right after receiving the static invoice.
2663+ sender. onion_messenger . handle_onion_message ( peer_node_id, & static_invoice_om) ;
2664+ check_added_monitors ( sender, 1 ) ;
2665+ let commitment_update = get_htlc_update_msgs ! ( sender, sender_lsp. node. get_our_node_id( ) ) ;
2666+ let update_add = commitment_update. update_add_htlcs [ 0 ] . clone ( ) ;
2667+ let payment_hash = update_add. payment_hash ;
2668+ assert ! ( update_add. hold_htlc. is_some( ) ) ;
2669+
2670+ // Force the sender_lsp's call to MessageRouter::create_blinded_paths to fail so it has to fall
2671+ // back to a 1-hop blinded path when creating the paths for its revoke_and_ack message.
2672+ sender_lsp. message_router . create_blinded_paths_res_override . lock ( ) . unwrap ( ) . 1 = Some ( Err ( ( ) ) ) ;
2673+
2674+ sender_lsp. node . handle_update_add_htlc ( sender. node . get_our_node_id ( ) , & update_add) ;
2675+ commitment_signed_dance ! ( sender_lsp, sender, & commitment_update. commitment_signed, false , true ) ;
2676+
2677+ // Check that we actually had to fall back to a 1-hop path.
2678+ assert ! ( sender_lsp. message_router. create_blinded_paths_res_override. lock( ) . unwrap( ) . 0 > 0 ) ;
2679+ sender_lsp. message_router . create_blinded_paths_res_override . lock ( ) . unwrap ( ) . 1 = None ;
2680+
2681+ sender_lsp. node . process_pending_htlc_forwards ( ) ;
2682+ let ( peer_id, held_htlc_om) =
2683+ extract_held_htlc_available_oms ( sender, & [ sender_lsp, invoice_server, recipient] )
2684+ . pop ( )
2685+ . unwrap ( ) ;
2686+ recipient. onion_messenger . handle_onion_message ( peer_id, & held_htlc_om) ;
2687+
2688+ // The release_htlc OM should go straight to the sender's LSP since they created a 1-hop blinded
2689+ // path to themselves for receiving it.
2690+ let release_htlc_om = recipient
2691+ . onion_messenger
2692+ . next_onion_message_for_peer ( sender_lsp. node . get_our_node_id ( ) )
2693+ . unwrap ( ) ;
2694+ sender_lsp
2695+ . onion_messenger
2696+ . handle_onion_message ( recipient. node . get_our_node_id ( ) , & release_htlc_om) ;
2697+
2698+ sender_lsp. node . process_pending_htlc_forwards ( ) ;
2699+ let mut events = sender_lsp. node . get_and_clear_pending_msg_events ( ) ;
2700+ assert_eq ! ( events. len( ) , 1 ) ;
2701+ let ev = remove_first_msg_event_to_node ( & invoice_server. node . get_our_node_id ( ) , & mut events) ;
2702+ check_added_monitors ! ( sender_lsp, 1 ) ;
2703+
2704+ let path: & [ & Node ] = & [ invoice_server, recipient] ;
2705+ let args = PassAlongPathArgs :: new ( sender_lsp, path, amt_msat, payment_hash, ev) ;
2706+ let claimable_ev = do_pass_along_path ( args) . unwrap ( ) ;
2707+
2708+ let route: & [ & [ & Node ] ] = & [ & [ sender_lsp, invoice_server, recipient] ] ;
2709+ let keysend_preimage = extract_payment_preimage ( & claimable_ev) ;
2710+ let ( res, _) =
2711+ claim_payment_along_route ( ClaimAlongRouteArgs :: new ( sender, route, keysend_preimage) ) ;
2712+ assert_eq ! ( res, Some ( PaidBolt12Invoice :: StaticInvoice ( invoice) ) ) ;
2713+ }
2714+
25902715#[ test]
25912716fn intercepted_hold_htlc ( ) {
25922717 // Test a payment `sender --> LSP --> recipient` such that the HTLC is both a hold htlc and an
0 commit comments