@@ -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 } ;
@@ -66,13 +67,15 @@ use crate::onion_message::offers::OffersMessage;
6667use crate :: routing:: gossip:: { NodeAlias , NodeId } ;
6768use crate :: routing:: router:: { DEFAULT_PAYMENT_DUMMY_HOPS , PaymentParameters , RouteParameters , RouteParametersConfig } ;
6869use crate :: sign:: { NodeSigner , Recipient } ;
70+ use crate :: types:: payment:: PaymentHash ;
6971use crate :: util:: ser:: Writeable ;
7072
7173/// This used to determine whether we built a compact path or not, but now its just a random
7274/// constant we apply to blinded path expiry in these tests.
7375const MAX_SHORT_LIVED_RELATIVE_EXPIRY : Duration = Duration :: from_secs ( 60 * 60 * 24 ) ;
7476
7577use crate :: prelude:: * ;
78+ use crate :: offers:: test_utils:: { payment_hash, payment_paths} ;
7679use crate :: util:: test_utils:: TestCurrencyConversion ;
7780
7881macro_rules! expect_recent_payment {
@@ -916,6 +919,78 @@ fn creates_and_pays_for_offer_using_one_hop_blinded_path() {
916919 expect_recent_payment ! ( bob, RecentPaymentDetails :: Fulfilled , payment_id) ;
917920}
918921
922+ /// Checks that an offer can be paid through a one-hop blinded path and that ephemeral pubkeys are
923+ /// used rather than exposing a node's pubkey. However, the node's pubkey is still used as the
924+ /// introduction node of the blinded path.
925+ #[ test]
926+ fn creates_and_pays_for_offer_with_fiat_amount_using_one_hop_blinded_path ( ) {
927+ let chanmon_cfgs = create_chanmon_cfgs ( 2 ) ;
928+ let node_cfgs = create_node_cfgs ( 2 , & chanmon_cfgs) ;
929+ let node_chanmgrs = create_node_chanmgrs ( 2 , & node_cfgs, & [ None , None ] ) ;
930+ let nodes = create_network ( 2 , & node_cfgs, & node_chanmgrs) ;
931+
932+ create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 10_000_000 , 1_000_000_000 ) ;
933+
934+ let alice = & nodes[ 0 ] ;
935+ let alice_id = alice. node . get_our_node_id ( ) ;
936+ let bob = & nodes[ 1 ] ;
937+ let bob_id = bob. node . get_our_node_id ( ) ;
938+
939+ let amount = Amount :: Currency {
940+ iso4217_code : CurrencyCode :: new ( * b"USD" ) . unwrap ( ) ,
941+ amount : 1000 ,
942+ } ;
943+
944+ let offer = alice. node
945+ . create_offer_builder ( ) . unwrap ( )
946+ . amount ( amount, alice. node . currency_conversion ) . unwrap ( )
947+ . build ( ) ;
948+ assert_ne ! ( offer. issuer_signing_pubkey( ) , Some ( alice_id) ) ;
949+ assert ! ( !offer. paths( ) . is_empty( ) ) ;
950+ for path in offer. paths ( ) {
951+ assert ! ( check_compact_path_introduction_node( & path, bob, alice_id) ) ;
952+ }
953+
954+ let payment_id = PaymentId ( [ 1 ; 32 ] ) ;
955+ bob. node . pay_for_offer ( & offer, None , payment_id, Default :: default ( ) ) . unwrap ( ) ;
956+ expect_recent_payment ! ( bob, RecentPaymentDetails :: AwaitingInvoice , payment_id) ;
957+
958+ let onion_message = bob. onion_messenger . next_onion_message_for_peer ( alice_id) . unwrap ( ) ;
959+ alice. onion_messenger . handle_onion_message ( bob_id, & onion_message) ;
960+
961+ let ( invoice_request, reply_path) = extract_invoice_request ( alice, & onion_message) ;
962+ let payment_context = PaymentContext :: Bolt12Offer ( Bolt12OfferContext {
963+ offer_id : offer. id ( ) ,
964+ invoice_request : InvoiceRequestFields {
965+ payer_signing_pubkey : invoice_request. payer_signing_pubkey ( ) ,
966+ quantity : None ,
967+ payer_note_truncated : None ,
968+ human_readable_name : None ,
969+ } ,
970+ } ) ;
971+ assert_eq ! ( invoice_request. amount_msats( alice. node. currency_conversion) , Ok ( 1_000_000 ) ) ;
972+ assert_ne ! ( invoice_request. payer_signing_pubkey( ) , bob_id) ;
973+ assert ! ( check_dummy_hopped_path_length( & reply_path, alice, bob_id, DUMMY_HOPS_PATH_LENGTH ) ) ;
974+
975+ let onion_message = alice. onion_messenger . next_onion_message_for_peer ( bob_id) . unwrap ( ) ;
976+ bob. onion_messenger . handle_onion_message ( alice_id, & onion_message) ;
977+
978+ let ( invoice, reply_path) = extract_invoice ( bob, & onion_message) ;
979+ assert_eq ! ( invoice. amount_msats( ) , 1_000_000 ) ;
980+ assert_ne ! ( invoice. signing_pubkey( ) , alice_id) ;
981+ assert ! ( !invoice. payment_paths( ) . is_empty( ) ) ;
982+ for path in invoice. payment_paths ( ) {
983+ assert_eq ! ( path. introduction_node( ) , & IntroductionNode :: NodeId ( alice_id) ) ;
984+ }
985+ assert ! ( check_dummy_hopped_path_length( & reply_path, bob, alice_id, DUMMY_HOPS_PATH_LENGTH ) ) ;
986+
987+ route_bolt12_payment ( bob, & [ alice] , & invoice) ;
988+ expect_recent_payment ! ( bob, RecentPaymentDetails :: Pending , payment_id) ;
989+
990+ claim_bolt12_payment ( bob, & [ alice] , payment_context, & invoice) ;
991+ expect_recent_payment ! ( bob, RecentPaymentDetails :: Fulfilled , payment_id) ;
992+ }
993+
919994/// Checks that a refund can be paid through a one-hop blinded path and that ephemeral pubkeys are
920995/// used rather than exposing a node's pubkey. However, the node's pubkey is still used as the
921996/// introduction node of the blinded path.
@@ -1400,6 +1475,165 @@ fn pays_bolt12_invoice_asynchronously() {
14001475 ) ;
14011476}
14021477
1478+ /// Checks that a deferred fiat-denominated invoice is rejected if its quoted msat amount does not
1479+ /// match the payer's local conversion result.
1480+ #[ test]
1481+ fn rejects_unexpected_fiat_bolt12_invoice_amount_asynchronously ( ) {
1482+ let mut manually_pay_cfg = test_default_channel_config ( ) ;
1483+ manually_pay_cfg. manually_handle_bolt12_invoices = true ;
1484+
1485+ let chanmon_cfgs = create_chanmon_cfgs ( 2 ) ;
1486+ let node_cfgs = create_node_cfgs ( 2 , & chanmon_cfgs) ;
1487+ let node_chanmgrs = create_node_chanmgrs ( 2 , & node_cfgs, & [ None , Some ( manually_pay_cfg) ] ) ;
1488+ let nodes = create_network ( 2 , & node_cfgs, & node_chanmgrs) ;
1489+
1490+ create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 10_000_000 , 1_000_000_000 ) ;
1491+
1492+ let alice = & nodes[ 0 ] ;
1493+ let alice_id = alice. node . get_our_node_id ( ) ;
1494+ let bob = & nodes[ 1 ] ;
1495+ let bob_id = bob. node . get_our_node_id ( ) ;
1496+ let conversion = TestCurrencyConversion ;
1497+
1498+ let offer = alice. node
1499+ . create_offer_builder ( ) . unwrap ( )
1500+ . amount (
1501+ Amount :: Currency {
1502+ iso4217_code : CurrencyCode :: new ( * b"USD" ) . unwrap ( ) ,
1503+ amount : 1000 ,
1504+ } ,
1505+ & conversion,
1506+ )
1507+ . unwrap ( )
1508+ . build ( ) ;
1509+
1510+ let payment_id = PaymentId ( [ 1 ; 32 ] ) ;
1511+ bob. node . pay_for_offer ( & offer, None , payment_id, Default :: default ( ) ) . unwrap ( ) ;
1512+ expect_recent_payment ! ( bob, RecentPaymentDetails :: AwaitingInvoice , payment_id) ;
1513+
1514+ let onion_message = bob. onion_messenger . next_onion_message_for_peer ( alice_id) . unwrap ( ) ;
1515+ alice. onion_messenger . handle_onion_message ( bob_id, & onion_message) ;
1516+
1517+ let ( invoice_request, _) = extract_invoice_request ( alice, & onion_message) ;
1518+ let nonce = extract_offer_nonce ( alice, & onion_message) ;
1519+
1520+ let onion_message = alice. onion_messenger . next_onion_message_for_peer ( bob_id) . unwrap ( ) ;
1521+ bob. onion_messenger . handle_onion_message ( alice_id, & onion_message) ;
1522+
1523+ let mut events = bob. node . get_and_clear_pending_events ( ) ;
1524+ assert_eq ! ( events. len( ) , 1 ) ;
1525+
1526+ let ( invoice, context) = match events. pop ( ) . unwrap ( ) {
1527+ Event :: InvoiceReceived { payment_id : actual_payment_id, invoice, context, .. } => {
1528+ assert_eq ! ( actual_payment_id, payment_id) ;
1529+ ( invoice, context)
1530+ } ,
1531+ _ => panic ! ( "No Event::InvoiceReceived" ) ,
1532+ } ;
1533+
1534+ let expanded_key = alice. keys_manager . get_expanded_key ( ) ;
1535+ let secp_ctx = Secp256k1 :: new ( ) ;
1536+ let verified_invoice_request =
1537+ invoice_request. verify_using_recipient_data ( nonce, & expanded_key, & secp_ctx) . unwrap ( ) ;
1538+
1539+ let bad_invoice = match verified_invoice_request {
1540+ InvoiceRequestVerifiedFromOffer :: DerivedKeys ( request) => request
1541+ . respond_using_derived_keys_no_std (
1542+ & conversion,
1543+ payment_paths ( ) ,
1544+ payment_hash ( ) ,
1545+ Duration :: from_secs ( 1000 ) ,
1546+ )
1547+ . unwrap ( )
1548+ . amount_msats_unchecked ( invoice. amount_msats ( ) + 1 )
1549+ . build_and_sign ( & secp_ctx)
1550+ . unwrap ( ) ,
1551+ InvoiceRequestVerifiedFromOffer :: ExplicitKeys ( _) => {
1552+ panic ! ( "Expected invoice request with derived keys" ) ;
1553+ } ,
1554+ } ;
1555+
1556+ assert_eq ! (
1557+ bob. node. send_payment_for_bolt12_invoice( & bad_invoice, context. as_ref( ) ) ,
1558+ Err ( Bolt12PaymentError :: UnexpectedInvoice ) ,
1559+ ) ;
1560+ }
1561+
1562+ /// Checks that deferred manual invoice handling rejects a different invoice replayed for the same
1563+ /// payment id after the first invoice has already been recorded.
1564+ #[ test]
1565+ fn rejects_different_bolt12_invoice_replayed_asynchronously ( ) {
1566+ let mut manually_pay_cfg = test_default_channel_config ( ) ;
1567+ manually_pay_cfg. manually_handle_bolt12_invoices = true ;
1568+
1569+ let chanmon_cfgs = create_chanmon_cfgs ( 2 ) ;
1570+ let node_cfgs = create_node_cfgs ( 2 , & chanmon_cfgs) ;
1571+ let node_chanmgrs = create_node_chanmgrs ( 2 , & node_cfgs, & [ None , Some ( manually_pay_cfg) ] ) ;
1572+ let nodes = create_network ( 2 , & node_cfgs, & node_chanmgrs) ;
1573+
1574+ create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 10_000_000 , 1_000_000_000 ) ;
1575+
1576+ let alice = & nodes[ 0 ] ;
1577+ let alice_id = alice. node . get_our_node_id ( ) ;
1578+ let bob = & nodes[ 1 ] ;
1579+ let bob_id = bob. node . get_our_node_id ( ) ;
1580+
1581+ let offer = alice. node
1582+ . create_offer_builder ( ) . unwrap ( )
1583+ . amount_msats ( 10_000_000 ) . unwrap ( )
1584+ . build ( ) ;
1585+
1586+ let payment_id = PaymentId ( [ 1 ; 32 ] ) ;
1587+ bob. node . pay_for_offer ( & offer, None , payment_id, Default :: default ( ) ) . unwrap ( ) ;
1588+ expect_recent_payment ! ( bob, RecentPaymentDetails :: AwaitingInvoice , payment_id) ;
1589+
1590+ let onion_message = bob. onion_messenger . next_onion_message_for_peer ( alice_id) . unwrap ( ) ;
1591+ alice. onion_messenger . handle_onion_message ( bob_id, & onion_message) ;
1592+
1593+ let ( invoice_request, _) = extract_invoice_request ( alice, & onion_message) ;
1594+ let nonce = extract_offer_nonce ( alice, & onion_message) ;
1595+
1596+ let onion_message = alice. onion_messenger . next_onion_message_for_peer ( bob_id) . unwrap ( ) ;
1597+ bob. onion_messenger . handle_onion_message ( alice_id, & onion_message) ;
1598+
1599+ let mut events = bob. node . get_and_clear_pending_events ( ) ;
1600+ assert_eq ! ( events. len( ) , 1 ) ;
1601+
1602+ let ( invoice, context) = match events. pop ( ) . unwrap ( ) {
1603+ Event :: InvoiceReceived { payment_id : actual_payment_id, invoice, context, .. } => {
1604+ assert_eq ! ( actual_payment_id, payment_id) ;
1605+ ( invoice, context)
1606+ } ,
1607+ _ => panic ! ( "No Event::InvoiceReceived" ) ,
1608+ } ;
1609+
1610+ let expanded_key = alice. keys_manager . get_expanded_key ( ) ;
1611+ let secp_ctx = Secp256k1 :: new ( ) ;
1612+ let verified_invoice_request =
1613+ invoice_request. verify_using_recipient_data ( nonce, & expanded_key, & secp_ctx) . unwrap ( ) ;
1614+
1615+ let replayed_invoice = match verified_invoice_request {
1616+ InvoiceRequestVerifiedFromOffer :: DerivedKeys ( request) => request
1617+ . respond_using_derived_keys_no_std (
1618+ alice. node . currency_conversion ,
1619+ payment_paths ( ) ,
1620+ PaymentHash ( [ 43 ; 32 ] ) ,
1621+ Duration :: from_secs ( 1000 ) ,
1622+ )
1623+ . unwrap ( )
1624+ . build_and_sign ( & secp_ctx)
1625+ . unwrap ( ) ,
1626+ InvoiceRequestVerifiedFromOffer :: ExplicitKeys ( _) => {
1627+ panic ! ( "Expected invoice request with derived keys" ) ;
1628+ } ,
1629+ } ;
1630+
1631+ assert_ne ! ( replayed_invoice. payment_hash( ) , invoice. payment_hash( ) ) ;
1632+ assert_eq ! (
1633+ bob. node. send_payment_for_bolt12_invoice( & replayed_invoice, context. as_ref( ) ) ,
1634+ Err ( Bolt12PaymentError :: DuplicateInvoice ) ,
1635+ ) ;
1636+ }
14031637/// Checks that an offer can be created using an unannounced node as a blinded path's introduction
14041638/// node. This is only preferred if there are no other options which may indicated either the offer
14051639/// is intended for the unannounced node or that the node is actually announced (e.g., an LSP) but
0 commit comments