77// You may not use this file except in accordance with one or both of these
88// licenses.
99
10- use crate :: blinded_path:: message:: { MessageContext , OffersContext } ;
10+ use crate :: blinded_path:: message:: { MessageContext , NextMessageHop , OffersContext } ;
1111use crate :: blinded_path:: payment:: PaymentContext ;
1212use crate :: blinded_path:: payment:: { AsyncBolt12OfferContext , BlindedPaymentTlvs } ;
1313use crate :: chain:: channelmonitor:: { HTLC_FAIL_BACK_BUFFER , LATENCY_GRACE_PERIOD_BLOCKS } ;
@@ -54,11 +54,12 @@ use crate::sign::NodeSigner;
5454use crate :: sync:: Mutex ;
5555use crate :: types:: features:: Bolt12InvoiceFeatures ;
5656use crate :: types:: payment:: { PaymentHash , PaymentPreimage , PaymentSecret } ;
57+ use crate :: util:: config:: UserConfig ;
5758use crate :: util:: ser:: Writeable ;
5859use bitcoin:: constants:: ChainHash ;
5960use bitcoin:: network:: Network ;
6061use bitcoin:: secp256k1;
61- use bitcoin:: secp256k1:: Secp256k1 ;
62+ use bitcoin:: secp256k1:: { PublicKey , Secp256k1 } ;
6263
6364use core:: convert:: Infallible ;
6465use core:: time:: Duration ;
@@ -331,32 +332,114 @@ fn expect_offer_paths_requests(recipient: &Node, next_hop_nodes: &[&Node]) {
331332 // We want to check that the async recipient has enqueued at least one `OfferPathsRequest` and no
332333 // other message types. Check this by iterating through all their outbound onion messages, peeling
333334 // multiple times if the messages are forwarded through other nodes.
334- let per_msg_recipient_msgs = recipient. onion_messenger . release_pending_msgs ( ) ;
335+ let offer_paths_reqs = extract_expected_om ( recipient, next_hop_nodes, |peeled_onion| {
336+ matches ! (
337+ peeled_onion,
338+ PeeledOnion :: AsyncPayments ( AsyncPaymentsMessage :: OfferPathsRequest ( _) , _, _)
339+ )
340+ } ) ;
341+ assert ! ( !offer_paths_reqs. is_empty( ) ) ;
342+ }
343+
344+ fn extract_invoice_request_om < ' a > (
345+ payer : & ' a Node , next_hop_nodes : & [ & ' a Node ] ,
346+ ) -> ( PublicKey , msgs:: OnionMessage ) {
347+ extract_expected_om ( payer, next_hop_nodes, |peeled_onion| {
348+ matches ! ( peeled_onion, & PeeledOnion :: Offers ( OffersMessage :: InvoiceRequest ( _) , _, _) )
349+ } )
350+ . pop ( )
351+ . unwrap ( )
352+ }
353+
354+ fn extract_static_invoice_om < ' a > (
355+ invoice_server : & ' a Node , next_hop_nodes : & [ & ' a Node ] ,
356+ ) -> ( PublicKey , msgs:: OnionMessage , StaticInvoice ) {
357+ let mut static_invoice = None ;
358+ let ( peer_id, om) = extract_expected_om ( invoice_server, next_hop_nodes, |peeled_onion| {
359+ if let & PeeledOnion :: Offers ( OffersMessage :: StaticInvoice ( inv) , _, _) = & peeled_onion {
360+ static_invoice = Some ( inv. clone ( ) ) ;
361+ true
362+ } else {
363+ false
364+ }
365+ } )
366+ . pop ( )
367+ . unwrap ( ) ;
368+ ( peer_id, om, static_invoice. unwrap ( ) )
369+ }
370+
371+ fn extract_held_htlc_available_om < ' a > (
372+ payer : & ' a Node , next_hop_nodes : & [ & ' a Node ] ,
373+ ) -> ( PublicKey , msgs:: OnionMessage ) {
374+ extract_expected_om ( payer, next_hop_nodes, |peeled_onion| {
375+ matches ! (
376+ peeled_onion,
377+ & PeeledOnion :: AsyncPayments ( AsyncPaymentsMessage :: HeldHtlcAvailable ( _) , _, _)
378+ )
379+ } )
380+ . pop ( )
381+ . unwrap ( )
382+ }
383+
384+ fn extract_release_htlc_om < ' a > (
385+ recipient : & ' a Node , next_hop_nodes : & [ & ' a Node ] ,
386+ ) -> ( PublicKey , msgs:: OnionMessage ) {
387+ extract_expected_om ( recipient, next_hop_nodes, |peeled_onion| {
388+ matches ! (
389+ peeled_onion,
390+ & PeeledOnion :: AsyncPayments ( AsyncPaymentsMessage :: ReleaseHeldHtlc ( _) , _, _)
391+ )
392+ } )
393+ . pop ( )
394+ . unwrap ( )
395+ }
396+
397+ fn extract_expected_om < F > (
398+ msg_sender : & Node , next_hop_nodes : & [ & Node ] , mut expected_msg_type : F ,
399+ ) -> Vec < ( PublicKey , msgs:: OnionMessage ) >
400+ where
401+ F : FnMut ( & PeeledOnion < Infallible > ) -> bool ,
402+ {
403+ let per_msg_recipient_msgs = msg_sender. onion_messenger . release_pending_msgs ( ) ;
335404 let mut pk_to_msg = Vec :: new ( ) ;
336405 for ( pk, msgs) in per_msg_recipient_msgs {
337406 for msg in msgs {
338407 pk_to_msg. push ( ( pk, msg) ) ;
339408 }
340409 }
341- let mut num_offer_paths_reqs : u8 = 0 ;
410+ let mut msgs = Vec :: new ( ) ;
342411 while let Some ( ( pk, msg) ) = pk_to_msg. pop ( ) {
343412 let node = next_hop_nodes. iter ( ) . find ( |node| node. node . get_our_node_id ( ) == pk) . unwrap ( ) ;
344413 let peeled_msg = node. onion_messenger . peel_onion_message ( & msg) . unwrap ( ) ;
345414 match peeled_msg {
346- PeeledOnion :: AsyncPayments ( AsyncPaymentsMessage :: OfferPathsRequest ( _) , _, _) => {
347- num_offer_paths_reqs += 1 ;
348- } ,
349415 PeeledOnion :: Forward ( next_hop, msg) => {
350416 let next_pk = match next_hop {
351- crate :: blinded_path:: message:: NextMessageHop :: NodeId ( pk) => pk,
352- _ => panic ! ( ) ,
417+ NextMessageHop :: NodeId ( pk) => pk,
418+ NextMessageHop :: ShortChannelId ( scid) => {
419+ let mut next_pk = None ;
420+ for node in next_hop_nodes {
421+ if node. node . get_our_node_id ( ) == pk {
422+ continue ;
423+ }
424+ for channel in node. node . list_channels ( ) {
425+ if channel. short_channel_id . unwrap ( ) == scid
426+ || channel. inbound_scid_alias . unwrap_or ( 0 ) == scid
427+ {
428+ next_pk = Some ( node. node . get_our_node_id ( ) ) ;
429+ }
430+ }
431+ }
432+ next_pk. unwrap ( )
433+ } ,
353434 } ;
354435 pk_to_msg. push ( ( next_pk, msg) ) ;
355436 } ,
356- _ => panic ! ( "Unexpected message" ) ,
437+ peeled_onion if expected_msg_type ( & peeled_onion) => msgs. push ( ( pk, msg) ) ,
438+ peeled_onion => panic ! ( "Unexpected message: {:#?}" , peeled_onion) ,
357439 }
358440 }
359- assert ! ( num_offer_paths_reqs > 0 ) ;
441+ assert ! ( !msgs. is_empty( ) ) ;
442+ msgs
360443}
361444
362445fn advance_time_by ( duration : Duration , node : & Node ) {
@@ -365,6 +448,14 @@ fn advance_time_by(duration: Duration, node: &Node) {
365448 connect_block ( node, & block) ;
366449}
367450
451+ fn often_offline_node_cfg ( ) -> UserConfig {
452+ let mut cfg = test_default_channel_config ( ) ;
453+ cfg. channel_handshake_config . announce_for_forwarding = false ;
454+ cfg. channel_handshake_limits . force_announced_channel_preference = true ;
455+ cfg. hold_outbound_htlcs_at_next_hop = true ;
456+ cfg
457+ }
458+
368459#[ test]
369460fn invalid_keysend_payment_secret ( ) {
370461 let chanmon_cfgs = create_chanmon_cfgs ( 3 ) ;
@@ -2206,3 +2297,108 @@ fn invoice_server_is_not_channel_peer() {
22062297 let res = claim_payment_along_route ( ClaimAlongRouteArgs :: new ( sender, route, keysend_preimage) ) ;
22072298 assert_eq ! ( res. 0 , Some ( PaidBolt12Invoice :: StaticInvoice ( invoice) ) ) ;
22082299}
2300+
2301+ #[ test]
2302+ fn simple_async_sender ( ) {
2303+ // Test the basic case of an async sender paying an async recipient.
2304+ let chanmon_cfgs = create_chanmon_cfgs ( 4 ) ;
2305+ let node_cfgs = create_node_cfgs ( 4 , & chanmon_cfgs) ;
2306+ let ( sender_cfg, recipient_cfg) = ( often_offline_node_cfg ( ) , often_offline_node_cfg ( ) ) ;
2307+ let mut invoice_server_cfg = test_default_channel_config ( ) ;
2308+ invoice_server_cfg. accept_forwards_to_priv_channels = true ;
2309+ let node_chanmgrs = create_node_chanmgrs (
2310+ 4 ,
2311+ & node_cfgs,
2312+ & [ Some ( sender_cfg) , None , Some ( invoice_server_cfg) , Some ( recipient_cfg) ] ,
2313+ ) ;
2314+ let nodes = create_network ( 4 , & node_cfgs, & node_chanmgrs) ;
2315+ create_unannounced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 1_000_000 , 0 ) ;
2316+ create_announced_chan_between_nodes_with_value ( & nodes, 1 , 2 , 1_000_000 , 0 ) ;
2317+ create_unannounced_chan_between_nodes_with_value ( & nodes, 2 , 3 , 1_000_000 , 0 ) ;
2318+ // Make sure all nodes are at the same block height
2319+ let node_max_height =
2320+ nodes. iter ( ) . map ( |node| node. blocks . lock ( ) . unwrap ( ) . len ( ) ) . max ( ) . unwrap ( ) as u32 ;
2321+ connect_blocks ( & nodes[ 0 ] , node_max_height - nodes[ 0 ] . best_block_info ( ) . 1 ) ;
2322+ connect_blocks ( & nodes[ 1 ] , node_max_height - nodes[ 1 ] . best_block_info ( ) . 1 ) ;
2323+ connect_blocks ( & nodes[ 2 ] , node_max_height - nodes[ 2 ] . best_block_info ( ) . 1 ) ;
2324+ connect_blocks ( & nodes[ 3 ] , node_max_height - nodes[ 3 ] . best_block_info ( ) . 1 ) ;
2325+ let sender = & nodes[ 0 ] ;
2326+ let sender_lsp = & nodes[ 1 ] ;
2327+ let invoice_server = & nodes[ 2 ] ;
2328+ let recipient = & nodes[ 3 ] ;
2329+
2330+ let recipient_id = vec ! [ 42 ; 32 ] ;
2331+ let inv_server_paths =
2332+ invoice_server. node . blinded_paths_for_async_recipient ( recipient_id. clone ( ) , None ) . unwrap ( ) ;
2333+ recipient. node . set_paths_to_static_invoice_server ( inv_server_paths) . unwrap ( ) ;
2334+ expect_offer_paths_requests ( recipient, & [ sender, sender_lsp, invoice_server] ) ;
2335+ let invoice =
2336+ pass_static_invoice_server_messages ( invoice_server, recipient, recipient_id. clone ( ) )
2337+ . invoice ;
2338+
2339+ let offer = recipient. node . get_async_receive_offer ( ) . unwrap ( ) ;
2340+ let amt_msat = 5000 ;
2341+ let payment_id = PaymentId ( [ 1 ; 32 ] ) ;
2342+ let params = RouteParametersConfig :: default ( ) ;
2343+ sender
2344+ . node
2345+ . pay_for_offer ( & offer, None , Some ( amt_msat) , None , payment_id, Retry :: Attempts ( 0 ) , params)
2346+ . unwrap ( ) ;
2347+
2348+ // Forward invreq to server, pass static invoice back, check that htlc was locked in/monitor was
2349+ // added
2350+ let ( peer_id, invreq_om) = extract_invoice_request_om ( sender, & [ sender_lsp, invoice_server] ) ;
2351+ invoice_server. onion_messenger . handle_onion_message ( peer_id, & invreq_om) ;
2352+
2353+ let mut events = invoice_server. node . get_and_clear_pending_events ( ) ;
2354+ assert_eq ! ( events. len( ) , 1 ) ;
2355+ let reply_path = match events. pop ( ) . unwrap ( ) {
2356+ Event :: StaticInvoiceRequested { recipient_id : ev_id, invoice_slot : _, reply_path } => {
2357+ assert_eq ! ( recipient_id, ev_id) ;
2358+ reply_path
2359+ } ,
2360+ _ => panic ! ( ) ,
2361+ } ;
2362+
2363+ invoice_server. node . send_static_invoice ( invoice, reply_path) . unwrap ( ) ;
2364+ let ( peer_node_id, static_invoice_om, static_invoice) =
2365+ extract_static_invoice_om ( invoice_server, & [ sender_lsp, sender, recipient] ) ;
2366+
2367+ // The sender should lock in the held HTLC with their LSP right after receiving the static invoice.
2368+ sender. onion_messenger . handle_onion_message ( peer_node_id, & static_invoice_om) ;
2369+ check_added_monitors ( sender, 1 ) ;
2370+ let commitment_update = get_htlc_update_msgs ! ( sender, sender_lsp. node. get_our_node_id( ) ) ;
2371+ let update_add = commitment_update. update_add_htlcs [ 0 ] . clone ( ) ;
2372+ let payment_hash = update_add. payment_hash ;
2373+ assert ! ( update_add. hold_htlc. is_some( ) ) ;
2374+ sender_lsp. node . handle_update_add_htlc ( sender. node . get_our_node_id ( ) , & update_add) ;
2375+ commitment_signed_dance ! ( sender_lsp, sender, & commitment_update. commitment_signed, false , true ) ;
2376+
2377+ // Ensure that after the held HTLC is locked in, the sender's lsp does not forward it immediately.
2378+ sender_lsp. node . process_pending_htlc_forwards ( ) ;
2379+ assert ! ( sender_lsp. node. get_and_clear_pending_msg_events( ) . is_empty( ) ) ;
2380+
2381+ let ( peer_id, held_htlc_om) =
2382+ extract_held_htlc_available_om ( sender, & [ sender_lsp, invoice_server, recipient] ) ;
2383+ recipient. onion_messenger . handle_onion_message ( peer_id, & held_htlc_om) ;
2384+ let ( peer_id, release_htlc_om) =
2385+ extract_release_htlc_om ( recipient, & [ sender, sender_lsp, invoice_server] ) ;
2386+ sender_lsp. onion_messenger . handle_onion_message ( peer_id, & release_htlc_om) ;
2387+
2388+ // After the sender's LSP receives release_held_htlc from the recipient, the payment can complete
2389+ sender_lsp. node . process_pending_htlc_forwards ( ) ;
2390+ let mut events = sender_lsp. node . get_and_clear_pending_msg_events ( ) ;
2391+ assert_eq ! ( events. len( ) , 1 ) ;
2392+ let ev = remove_first_msg_event_to_node ( & invoice_server. node . get_our_node_id ( ) , & mut events) ;
2393+ check_added_monitors ! ( sender_lsp, 1 ) ;
2394+
2395+ let path: & [ & Node ] = & [ invoice_server, recipient] ;
2396+ let args = PassAlongPathArgs :: new ( sender_lsp, path, amt_msat, payment_hash, ev) ;
2397+ let claimable_ev = do_pass_along_path ( args) . unwrap ( ) ;
2398+
2399+ let route: & [ & [ & Node ] ] = & [ & [ sender_lsp, invoice_server, recipient] ] ;
2400+ let keysend_preimage = extract_payment_preimage ( & claimable_ev) ;
2401+ let ( res, _) =
2402+ claim_payment_along_route ( ClaimAlongRouteArgs :: new ( sender, route, keysend_preimage) ) ;
2403+ assert_eq ! ( res, Some ( PaidBolt12Invoice :: StaticInvoice ( static_invoice) ) ) ;
2404+ }
0 commit comments