@@ -52,6 +52,7 @@ use crate::blinded_path::message::OffersContext;
5252use crate :: events:: { ClosureReason , Event , HTLCHandlingFailureType , PaidBolt12Invoice , PaymentFailureReason , PaymentPurpose } ;
5353use crate :: ln:: channelmanager:: { PaymentId , RecentPaymentDetails , self } ;
5454use crate :: ln:: outbound_payment:: { Bolt12PaymentError , RecipientOnionFields , Retry } ;
55+ use crate :: offers:: offer:: { Amount , CurrencyCode } ;
5556use crate :: types:: features:: Bolt12InvoiceFeatures ;
5657use crate :: ln:: functional_test_utils:: * ;
5758use crate :: ln:: msgs:: { BaseMessageHandler , ChannelMessageHandler , Init , NodeAnnouncement , OnionMessage , OnionMessageHandler , RoutingMessageHandler , SocketAddress , UnsignedGossipMessage , UnsignedNodeAnnouncement } ;
@@ -916,6 +917,78 @@ fn creates_and_pays_for_offer_using_one_hop_blinded_path() {
916917 expect_recent_payment ! ( bob, RecentPaymentDetails :: Fulfilled , payment_id) ;
917918}
918919
920+ /// Checks that an offer can be paid through a one-hop blinded path and that ephemeral pubkeys are
921+ /// used rather than exposing a node's pubkey. However, the node's pubkey is still used as the
922+ /// introduction node of the blinded path.
923+ #[ test]
924+ fn creates_and_pays_for_offer_with_fiat_amount_using_one_hop_blinded_path ( ) {
925+ let chanmon_cfgs = create_chanmon_cfgs ( 2 ) ;
926+ let node_cfgs = create_node_cfgs ( 2 , & chanmon_cfgs) ;
927+ let node_chanmgrs = create_node_chanmgrs ( 2 , & node_cfgs, & [ None , None ] ) ;
928+ let nodes = create_network ( 2 , & node_cfgs, & node_chanmgrs) ;
929+
930+ create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 10_000_000 , 1_000_000_000 ) ;
931+
932+ let alice = & nodes[ 0 ] ;
933+ let alice_id = alice. node . get_our_node_id ( ) ;
934+ let bob = & nodes[ 1 ] ;
935+ let bob_id = bob. node . get_our_node_id ( ) ;
936+
937+ let amount = Amount :: Currency {
938+ iso4217_code : CurrencyCode :: new ( * b"USD" ) . unwrap ( ) ,
939+ amount : 1000 ,
940+ } ;
941+
942+ let offer = alice. node
943+ . create_offer_builder ( ) . unwrap ( )
944+ . amount ( amount, & alice. node . flow . currency_conversion ) . unwrap ( )
945+ . build ( ) ;
946+ assert_ne ! ( offer. issuer_signing_pubkey( ) , Some ( alice_id) ) ;
947+ assert ! ( !offer. paths( ) . is_empty( ) ) ;
948+ for path in offer. paths ( ) {
949+ assert ! ( check_compact_path_introduction_node( & path, bob, alice_id) ) ;
950+ }
951+
952+ let payment_id = PaymentId ( [ 1 ; 32 ] ) ;
953+ bob. node . pay_for_offer ( & offer, None , payment_id, Default :: default ( ) ) . unwrap ( ) ;
954+ expect_recent_payment ! ( bob, RecentPaymentDetails :: AwaitingInvoice , payment_id) ;
955+
956+ let onion_message = bob. onion_messenger . next_onion_message_for_peer ( alice_id) . unwrap ( ) ;
957+ alice. onion_messenger . handle_onion_message ( bob_id, & onion_message) ;
958+
959+ let ( invoice_request, reply_path) = extract_invoice_request ( alice, & onion_message) ;
960+ let payment_context = PaymentContext :: Bolt12Offer ( Bolt12OfferContext {
961+ offer_id : offer. id ( ) ,
962+ invoice_request : InvoiceRequestFields {
963+ payer_signing_pubkey : invoice_request. payer_signing_pubkey ( ) ,
964+ quantity : None ,
965+ payer_note_truncated : None ,
966+ human_readable_name : None ,
967+ } ,
968+ } ) ;
969+ assert_eq ! ( invoice_request. amount_msats( & alice. node. flow. currency_conversion) , Ok ( 1_000_000 ) ) ;
970+ assert_ne ! ( invoice_request. payer_signing_pubkey( ) , bob_id) ;
971+ assert ! ( check_dummy_hopped_path_length( & reply_path, alice, bob_id, DUMMY_HOPS_PATH_LENGTH ) ) ;
972+
973+ let onion_message = alice. onion_messenger . next_onion_message_for_peer ( bob_id) . unwrap ( ) ;
974+ bob. onion_messenger . handle_onion_message ( alice_id, & onion_message) ;
975+
976+ let ( invoice, reply_path) = extract_invoice ( bob, & onion_message) ;
977+ assert_eq ! ( invoice. amount_msats( ) , 1_000_000 ) ;
978+ assert_ne ! ( invoice. signing_pubkey( ) , alice_id) ;
979+ assert ! ( !invoice. payment_paths( ) . is_empty( ) ) ;
980+ for path in invoice. payment_paths ( ) {
981+ assert_eq ! ( path. introduction_node( ) , & IntroductionNode :: NodeId ( alice_id) ) ;
982+ }
983+ assert ! ( check_dummy_hopped_path_length( & reply_path, bob, alice_id, DUMMY_HOPS_PATH_LENGTH ) ) ;
984+
985+ route_bolt12_payment ( bob, & [ alice] , & invoice) ;
986+ expect_recent_payment ! ( bob, RecentPaymentDetails :: Pending , payment_id) ;
987+
988+ claim_bolt12_payment ( bob, & [ alice] , payment_context, & invoice) ;
989+ expect_recent_payment ! ( bob, RecentPaymentDetails :: Fulfilled , payment_id) ;
990+ }
991+
919992/// Checks that a refund can be paid through a one-hop blinded path and that ephemeral pubkeys are
920993/// used rather than exposing a node's pubkey. However, the node's pubkey is still used as the
921994/// introduction node of the blinded path.
0 commit comments