@@ -75,15 +75,21 @@ const MAX_SHORT_LIVED_RELATIVE_EXPIRY: Duration = Duration::from_secs(60 * 60 *
7575use crate :: prelude:: * ;
7676
7777macro_rules! expect_recent_payment {
78- ( $node: expr, $payment_state: path, $payment_id: expr) => {
79- match $node. node. list_recent_payments( ) . first( ) {
80- Some ( & $payment_state { payment_id: actual_payment_id, .. } ) => {
81- assert_eq!( $payment_id, actual_payment_id) ;
82- } ,
83- Some ( _) => panic!( "Unexpected recent payment state" ) ,
84- None => panic!( "No recent payments" ) ,
78+ ( $node: expr, $payment_state: path, $payment_id: expr) => { {
79+ let mut found_payment = false ;
80+ for payment in $node. node. list_recent_payments( ) . iter( ) {
81+ match payment {
82+ $payment_state { payment_id: actual_payment_id, .. } => {
83+ if $payment_id == * actual_payment_id {
84+ found_payment = true ;
85+ break ;
86+ }
87+ } ,
88+ _ => { } ,
89+ }
8590 }
86- }
91+ assert!( found_payment) ;
92+ } }
8793}
8894
8995fn connect_peers < ' a , ' b , ' c > ( node_a : & Node < ' a , ' b , ' c > , node_b : & Node < ' a , ' b , ' c > ) {
@@ -2572,3 +2578,92 @@ fn no_double_pay_with_stale_channelmanager() {
25722578 // generated in response to the duplicate invoice.
25732579 assert ! ( nodes[ 0 ] . node. get_and_clear_pending_events( ) . is_empty( ) ) ;
25742580}
2581+
2582+ #[ test]
2583+ fn creates_and_pays_for_phantom_offer ( ) {
2584+ // Tests that we can pay a "phantom offer" to any participating node.
2585+ let mut chanmon_cfgs = create_chanmon_cfgs ( 1 ) ;
2586+ chanmon_cfgs. append ( & mut create_phantom_chanmon_cfgs ( 2 ) ) ;
2587+ let node_cfgs = create_node_cfgs ( 3 , & chanmon_cfgs) ;
2588+ let node_chanmgrs = create_node_chanmgrs ( 3 , & node_cfgs, & [ None , None , None ] ) ;
2589+ let nodes = create_network ( 3 , & node_cfgs, & node_chanmgrs) ;
2590+
2591+ create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 10_000_000 , 1_000_000_000 ) ;
2592+ create_announced_chan_between_nodes_with_value ( & nodes, 0 , 2 , 10_000_000 , 1_000_000_000 ) ;
2593+
2594+ let node_a_id = nodes[ 0 ] . node . get_our_node_id ( ) ;
2595+ let node_b_id = nodes[ 1 ] . node . get_our_node_id ( ) ;
2596+ let node_c_id = nodes[ 2 ] . node . get_our_node_id ( ) ;
2597+
2598+ let offer = nodes[ 1 ] . node
2599+ . create_phantom_offer_builder ( vec ! [ ( node_c_id, nodes[ 2 ] . node. list_channels( ) ) ] , 2 )
2600+ . unwrap ( )
2601+ . amount_msats ( 10_000_000 )
2602+ . build ( ) . unwrap ( ) ;
2603+
2604+ // The offer should be resolvable by either of node B or C but signed by a derived key
2605+ assert ! ( offer. issuer_signing_pubkey( ) . is_some( ) ) ;
2606+ assert_ne ! ( offer. issuer_signing_pubkey( ) , Some ( node_b_id) ) ;
2607+ assert_ne ! ( offer. issuer_signing_pubkey( ) , Some ( node_c_id) ) ;
2608+ assert_eq ! ( offer. paths( ) . len( ) , 2 ) ;
2609+ let mut b_path_count = 0 ;
2610+ let mut c_path_count = 0 ;
2611+ for path in offer. paths ( ) {
2612+ if check_compact_path_introduction_node ( & path, & nodes[ 0 ] , node_b_id) {
2613+ b_path_count += 1 ;
2614+ }
2615+ if check_compact_path_introduction_node ( & path, & nodes[ 0 ] , node_c_id) {
2616+ c_path_count += 1 ;
2617+ }
2618+ }
2619+ assert_eq ! ( b_path_count, 1 ) ;
2620+ assert_eq ! ( c_path_count, 1 ) ;
2621+
2622+ // Pay twice, first via node B (the node that actually built the offer) then pay via node C
2623+ // (which won't have seen the offer until it receives the invoice_request).
2624+ for ( payment_id, recipient) in [ ( [ 1 ; 32 ] , & nodes[ 1 ] ) , ( [ 2 ; 32 ] , & nodes[ 2 ] ) ] {
2625+ let payment_id = PaymentId ( payment_id) ;
2626+ nodes[ 0 ] . node . pay_for_offer ( & offer, None , payment_id, Default :: default ( ) ) . unwrap ( ) ;
2627+ expect_recent_payment ! ( nodes[ 0 ] , RecentPaymentDetails :: AwaitingInvoice , payment_id) ;
2628+
2629+ let recipient_id = recipient. node . get_our_node_id ( ) ;
2630+ let non_recipient_id = if node_b_id == recipient_id {
2631+ node_c_id
2632+ } else {
2633+ node_b_id
2634+ } ;
2635+
2636+ let onion_message =
2637+ nodes[ 0 ] . onion_messenger . next_onion_message_for_peer ( recipient_id) . unwrap ( ) ;
2638+ let _discard =
2639+ nodes[ 0 ] . onion_messenger . next_onion_message_for_peer ( non_recipient_id) . unwrap ( ) ;
2640+ recipient. onion_messenger . handle_onion_message ( node_a_id, & onion_message) ;
2641+
2642+ let ( invoice_request, _) = extract_invoice_request ( & recipient, & onion_message) ;
2643+ let payment_context = PaymentContext :: Bolt12Offer ( Bolt12OfferContext {
2644+ offer_id : offer. id ( ) ,
2645+ invoice_request : InvoiceRequestFields {
2646+ payer_signing_pubkey : invoice_request. payer_signing_pubkey ( ) ,
2647+ quantity : None ,
2648+ payer_note_truncated : None ,
2649+ human_readable_name : None ,
2650+ } ,
2651+ } ) ;
2652+
2653+ let onion_message =
2654+ recipient. onion_messenger . next_onion_message_for_peer ( node_a_id) . unwrap ( ) ;
2655+ nodes[ 0 ] . onion_messenger . handle_onion_message ( recipient_id, & onion_message) ;
2656+
2657+ let ( invoice, _) = extract_invoice ( & nodes[ 0 ] , & onion_message) ;
2658+ assert_eq ! ( invoice. amount_msats( ) , 10_000_000 ) ;
2659+
2660+ route_bolt12_payment ( & nodes[ 0 ] , & [ recipient] , & invoice) ;
2661+ expect_recent_payment ! ( & nodes[ 0 ] , RecentPaymentDetails :: Pending , payment_id) ;
2662+
2663+ claim_bolt12_payment ( & nodes[ 0 ] , & [ recipient] , payment_context, & invoice) ;
2664+ expect_recent_payment ! ( & nodes[ 0 ] , RecentPaymentDetails :: Fulfilled , payment_id) ;
2665+
2666+ assert ! ( nodes[ 0 ] . onion_messenger. next_onion_message_for_peer( node_b_id) . is_none( ) ) ;
2667+ assert ! ( nodes[ 0 ] . onion_messenger. next_onion_message_for_peer( node_c_id) . is_none( ) ) ;
2668+ }
2669+ }
0 commit comments