@@ -2587,6 +2587,131 @@ fn held_htlc_timeout() {
2587
2587
) ;
2588
2588
}
2589
2589
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
+
2590
2715
#[ test]
2591
2716
fn intercepted_hold_htlc ( ) {
2592
2717
// Test a payment `sender --> LSP --> recipient` such that the HTLC is both a hold htlc and an
0 commit comments