@@ -727,6 +727,81 @@ fn creates_and_pays_for_offer_using_one_hop_blinded_path() {
727727 expect_recent_payment ! ( bob, RecentPaymentDetails :: Fulfilled , payment_id) ;
728728}
729729
730+ /// Verifies that the invoice request message can be retried if it fails to reach the
731+ /// payee on the first attempt.
732+ #[ test]
733+ fn creates_and_pays_for_offer_with_retry ( ) {
734+ let chanmon_cfgs = create_chanmon_cfgs ( 2 ) ;
735+ let node_cfgs = create_node_cfgs ( 2 , & chanmon_cfgs) ;
736+ let node_chanmgrs = create_node_chanmgrs ( 2 , & node_cfgs, & [ None , None ] ) ;
737+ let nodes = create_network ( 2 , & node_cfgs, & node_chanmgrs) ;
738+
739+ create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 10_000_000 , 1_000_000_000 ) ;
740+
741+ let alice = & nodes[ 0 ] ;
742+ let alice_id = alice. node . get_our_node_id ( ) ;
743+ let bob = & nodes[ 1 ] ;
744+ let bob_id = bob. node . get_our_node_id ( ) ;
745+
746+ let offer = alice. node
747+ . create_offer_builder ( None ) . unwrap ( )
748+ . amount_msats ( 10_000_000 )
749+ . build ( ) . unwrap ( ) ;
750+ assert_ne ! ( offer. signing_pubkey( ) , Some ( alice_id) ) ;
751+ assert ! ( !offer. paths( ) . is_empty( ) ) ;
752+ for path in offer. paths ( ) {
753+ assert_eq ! ( path. introduction_node, IntroductionNode :: NodeId ( alice_id) ) ;
754+ }
755+ let payment_id = PaymentId ( [ 1 ; 32 ] ) ;
756+ bob. node . pay_for_offer ( & offer, None , None , None , payment_id, Retry :: Attempts ( 0 ) , None ) . unwrap ( ) ;
757+ expect_recent_payment ! ( bob, RecentPaymentDetails :: AwaitingInvoice , payment_id) ;
758+
759+ let _lost_onion_message = bob. onion_messenger . next_onion_message_for_peer ( alice_id) . unwrap ( ) ;
760+
761+ // Simulate a scenario where the original onion_message is lost before reaching Alice.
762+ // Use handle_message_received to regenerate the message.
763+ bob. node . handle_message_received ( ) ;
764+ let onion_message = bob. onion_messenger . next_onion_message_for_peer ( alice_id) . unwrap ( ) ;
765+
766+ alice. onion_messenger . handle_onion_message ( & bob_id, & onion_message) ;
767+
768+ let ( invoice_request, reply_path) = extract_invoice_request ( alice, & onion_message) ;
769+ let payment_context = PaymentContext :: Bolt12Offer ( Bolt12OfferContext {
770+ offer_id : offer. id ( ) ,
771+ invoice_request : InvoiceRequestFields {
772+ payer_id : invoice_request. payer_id ( ) ,
773+ quantity : None ,
774+ payer_note_truncated : None ,
775+ } ,
776+ } ) ;
777+ assert_eq ! ( invoice_request. amount_msats( ) , None ) ;
778+ assert_ne ! ( invoice_request. payer_id( ) , bob_id) ;
779+ assert_eq ! ( reply_path. introduction_node, IntroductionNode :: NodeId ( bob_id) ) ;
780+ let onion_message = alice. onion_messenger . next_onion_message_for_peer ( bob_id) . unwrap ( ) ;
781+ bob. onion_messenger . handle_onion_message ( & alice_id, & onion_message) ;
782+
783+ // Expect no more OffersMessage to be enqueued by this point, even after calling
784+ // handle_message_received.
785+ bob. node . handle_message_received ( ) ;
786+
787+ match bob. onion_messenger . next_onion_message_for_peer ( alice_id) {
788+ Some ( _) => panic ! ( "Unexpected message enqueued after retry tick." ) ,
789+ None => { } ,
790+ } ;
791+
792+ let ( invoice, _) = extract_invoice ( bob, & onion_message) ;
793+ assert_eq ! ( invoice. amount_msats( ) , 10_000_000 ) ;
794+ assert_ne ! ( invoice. signing_pubkey( ) , alice_id) ;
795+ assert ! ( !invoice. payment_paths( ) . is_empty( ) ) ;
796+ for ( _, path) in invoice. payment_paths ( ) {
797+ assert_eq ! ( path. introduction_node, IntroductionNode :: NodeId ( alice_id) ) ;
798+ }
799+ route_bolt12_payment ( bob, & [ alice] , & invoice) ;
800+ expect_recent_payment ! ( bob, RecentPaymentDetails :: Pending , payment_id) ;
801+ claim_bolt12_payment ( bob, & [ alice] , payment_context) ;
802+ expect_recent_payment ! ( bob, RecentPaymentDetails :: Fulfilled , payment_id) ;
803+ }
804+
730805/// Checks that a refund can be paid through a one-hop blinded path and that ephemeral pubkeys are
731806/// used rather than exposing a node's pubkey. However, the node's pubkey is still used as the
732807/// introduction node of the blinded path.
0 commit comments