@@ -51,6 +51,7 @@ use crate::blinded_path::payment::{Bolt12OfferContext, Bolt12RefundContext, Paym
51
51
use crate :: blinded_path:: message:: OffersContext ;
52
52
use crate :: events:: { ClosureReason , Event , HTLCHandlingFailureType , PaidBolt12Invoice , PaymentFailureReason , PaymentPurpose } ;
53
53
use crate :: ln:: channelmanager:: { Bolt12PaymentError , PaymentId , RecentPaymentDetails , RecipientOnionFields , Retry , self } ;
54
+ use crate :: offers:: flow:: FlowEvents ;
54
55
use crate :: types:: features:: Bolt12InvoiceFeatures ;
55
56
use crate :: ln:: functional_test_utils:: * ;
56
57
use crate :: ln:: msgs:: { BaseMessageHandler , ChannelMessageHandler , Init , NodeAnnouncement , OnionMessage , OnionMessageHandler , RoutingMessageHandler , SocketAddress , UnsignedGossipMessage , UnsignedNodeAnnouncement } ;
@@ -797,6 +798,122 @@ fn creates_and_pays_for_offer_using_one_hop_blinded_path() {
797
798
expect_recent_payment ! ( bob, RecentPaymentDetails :: Fulfilled , payment_id) ;
798
799
}
799
800
801
+ /// Checks that an offer can be paid through a one-hop blinded path and that ephemeral pubkeys are
802
+ /// used rather than exposing a node's pubkey. However, the node's pubkey is still used as the
803
+ /// introduction node of the blinded path.
804
+ #[ test]
805
+ fn creates_and_manually_respond_to_ir_then_pays_for_offer_using_one_hop_blinded_path ( ) {
806
+ let chanmon_cfgs = create_chanmon_cfgs ( 2 ) ;
807
+ let node_cfgs = create_node_cfgs ( 2 , & chanmon_cfgs) ;
808
+ let mut node_chanmgrs = create_node_chanmgrs ( 2 , & node_cfgs, & [ None , None ] ) ;
809
+ node_chanmgrs[ 0 ] . flow . enable_events ( ) ;
810
+ let nodes = create_network ( 2 , & node_cfgs, & node_chanmgrs) ;
811
+
812
+ create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 10_000_000 , 1_000_000_000 ) ;
813
+
814
+ let alice = & nodes[ 0 ] ;
815
+ let alice_id = alice. node . get_our_node_id ( ) ;
816
+ let bob = & nodes[ 1 ] ;
817
+ let bob_id = bob. node . get_our_node_id ( ) ;
818
+
819
+ let offer = alice. node
820
+ . create_offer_builder ( ) . unwrap ( )
821
+ . amount_msats ( 10_000_000 )
822
+ . build ( ) . unwrap ( ) ;
823
+ assert_ne ! ( offer. issuer_signing_pubkey( ) , Some ( alice_id) ) ;
824
+ assert ! ( !offer. paths( ) . is_empty( ) ) ;
825
+ for path in offer. paths ( ) {
826
+ assert ! ( check_compact_path_introduction_node( & path, bob, alice_id) ) ;
827
+ }
828
+
829
+ let payment_id = PaymentId ( [ 1 ; 32 ] ) ;
830
+ bob. node . pay_for_offer ( & offer, None , None , None , payment_id, Retry :: Attempts ( 0 ) , RouteParametersConfig :: default ( ) ) . unwrap ( ) ;
831
+ expect_recent_payment ! ( bob, RecentPaymentDetails :: AwaitingInvoice , payment_id) ;
832
+
833
+ let onion_message = bob. onion_messenger . next_onion_message_for_peer ( alice_id) . unwrap ( ) ;
834
+ alice. onion_messenger . handle_onion_message ( bob_id, & onion_message) ;
835
+
836
+ let flow_events = alice. node . flow . release_pending_flow_events ( ) ;
837
+ assert_eq ! ( flow_events. len( ) , 1 , "expected exactly one flow event" ) ;
838
+
839
+ let ( invoice_request, reply_path) = match flow_events. into_iter ( ) . next ( ) . unwrap ( ) {
840
+ FlowEvents :: InvoiceRequestReceived {
841
+ invoice_request : InvoiceRequestVerifiedFromOffer :: DerivedKeys ( req) ,
842
+ reply_path
843
+ } => ( req, reply_path) ,
844
+ _ => panic ! ( "Unexpected flow event" ) ,
845
+ } ;
846
+
847
+ let payment_context = PaymentContext :: Bolt12Offer ( Bolt12OfferContext {
848
+ offer_id : offer. id ( ) ,
849
+ invoice_request : InvoiceRequestFields {
850
+ payer_signing_pubkey : invoice_request. payer_signing_pubkey ( ) ,
851
+ quantity : None ,
852
+ payer_note_truncated : None ,
853
+ human_readable_name : None ,
854
+ } ,
855
+ } ) ;
856
+ assert_eq ! ( invoice_request. amount_msats( ) , Some ( 10_000_000 ) ) ;
857
+ assert_ne ! ( invoice_request. payer_signing_pubkey( ) , bob_id) ;
858
+ assert ! ( check_compact_path_introduction_node( & reply_path, alice, bob_id) ) ;
859
+
860
+ // Create response for invoice request manually.
861
+ let get_payment_info = |amount_msats, relative_expiry| {
862
+ alice
863
+ . node
864
+ . create_inbound_payment ( Some ( amount_msats) , relative_expiry, None )
865
+ . map_err ( |_| Bolt12SemanticError :: InvalidAmount )
866
+ } ;
867
+
868
+ let router = & alice. node . router ;
869
+ let entropy = & * alice. node . entropy_source ;
870
+
871
+ let ( builder, _) = alice
872
+ . node
873
+ . flow
874
+ . create_invoice_builder_from_invoice_request_with_keys (
875
+ router,
876
+ entropy,
877
+ & DefaultCurrencyConversion { } ,
878
+ & invoice_request,
879
+ alice. node . list_usable_channels ( ) ,
880
+ get_payment_info,
881
+ )
882
+ . expect ( "failed to create builder with derived keys" ) ;
883
+
884
+ let invoice = builder
885
+ . build_and_sign ( & alice. node . secp_ctx )
886
+ . expect ( "failed to build and sign invoice" ) ;
887
+
888
+ alice
889
+ . node
890
+ . flow
891
+ . enqueue_invoice_using_reply_paths (
892
+ invoice,
893
+ & [ reply_path] ,
894
+ alice. node . get_peers_for_blinded_path ( ) ,
895
+ )
896
+ . expect ( "failed to enqueue invoice" ) ;
897
+
898
+ let onion_message = alice. onion_messenger . next_onion_message_for_peer ( bob_id) . unwrap ( ) ;
899
+ bob. onion_messenger . handle_onion_message ( alice_id, & onion_message) ;
900
+
901
+ let ( invoice, reply_path) = extract_invoice ( bob, & onion_message) ;
902
+ assert_eq ! ( invoice. amount_msats( ) , 10_000_000 ) ;
903
+ assert_ne ! ( invoice. signing_pubkey( ) , alice_id) ;
904
+ assert ! ( !invoice. payment_paths( ) . is_empty( ) ) ;
905
+ for path in invoice. payment_paths ( ) {
906
+ assert_eq ! ( path. introduction_node( ) , & IntroductionNode :: NodeId ( alice_id) ) ;
907
+ }
908
+ assert ! ( check_compact_path_introduction_node( & reply_path, bob, alice_id) ) ;
909
+
910
+ route_bolt12_payment ( bob, & [ alice] , & invoice) ;
911
+ expect_recent_payment ! ( bob, RecentPaymentDetails :: Pending , payment_id) ;
912
+
913
+ claim_bolt12_payment ( bob, & [ alice] , payment_context, & invoice) ;
914
+ expect_recent_payment ! ( bob, RecentPaymentDetails :: Fulfilled , payment_id) ;
915
+ }
916
+
800
917
/// Checks that a refund can be paid through a one-hop blinded path and that ephemeral pubkeys are
801
918
/// used rather than exposing a node's pubkey. However, the node's pubkey is still used as the
802
919
/// introduction node of the blinded path.
0 commit comments