7
7
// You may not use this file except in accordance with one or both of these
8
8
// licenses.
9
9
10
- use crate :: blinded_path:: message:: { MessageContext , OffersContext } ;
10
+ use crate :: blinded_path:: message:: { MessageContext , NextMessageHop , OffersContext } ;
11
11
use crate :: blinded_path:: payment:: PaymentContext ;
12
12
use crate :: blinded_path:: payment:: { AsyncBolt12OfferContext , BlindedPaymentTlvs } ;
13
13
use crate :: chain:: channelmonitor:: { HTLC_FAIL_BACK_BUFFER , LATENCY_GRACE_PERIOD_BLOCKS } ;
@@ -54,11 +54,12 @@ use crate::sign::NodeSigner;
54
54
use crate :: sync:: Mutex ;
55
55
use crate :: types:: features:: Bolt12InvoiceFeatures ;
56
56
use crate :: types:: payment:: { PaymentHash , PaymentPreimage , PaymentSecret } ;
57
+ use crate :: util:: config:: UserConfig ;
57
58
use crate :: util:: ser:: Writeable ;
58
59
use bitcoin:: constants:: ChainHash ;
59
60
use bitcoin:: network:: Network ;
60
61
use bitcoin:: secp256k1;
61
- use bitcoin:: secp256k1:: Secp256k1 ;
62
+ use bitcoin:: secp256k1:: { PublicKey , Secp256k1 } ;
62
63
63
64
use core:: convert:: Infallible ;
64
65
use core:: time:: Duration ;
@@ -331,32 +332,114 @@ fn expect_offer_paths_requests(recipient: &Node, next_hop_nodes: &[&Node]) {
331
332
// We want to check that the async recipient has enqueued at least one `OfferPathsRequest` and no
332
333
// other message types. Check this by iterating through all their outbound onion messages, peeling
333
334
// 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 ( ) ;
335
404
let mut pk_to_msg = Vec :: new ( ) ;
336
405
for ( pk, msgs) in per_msg_recipient_msgs {
337
406
for msg in msgs {
338
407
pk_to_msg. push ( ( pk, msg) ) ;
339
408
}
340
409
}
341
- let mut num_offer_paths_reqs : u8 = 0 ;
410
+ let mut msgs = Vec :: new ( ) ;
342
411
while let Some ( ( pk, msg) ) = pk_to_msg. pop ( ) {
343
412
let node = next_hop_nodes. iter ( ) . find ( |node| node. node . get_our_node_id ( ) == pk) . unwrap ( ) ;
344
413
let peeled_msg = node. onion_messenger . peel_onion_message ( & msg) . unwrap ( ) ;
345
414
match peeled_msg {
346
- PeeledOnion :: AsyncPayments ( AsyncPaymentsMessage :: OfferPathsRequest ( _) , _, _) => {
347
- num_offer_paths_reqs += 1 ;
348
- } ,
349
415
PeeledOnion :: Forward ( next_hop, msg) => {
350
416
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
+ } ,
353
434
} ;
354
435
pk_to_msg. push ( ( next_pk, msg) ) ;
355
436
} ,
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) ,
357
439
}
358
440
}
359
- assert ! ( num_offer_paths_reqs > 0 ) ;
441
+ assert ! ( !msgs. is_empty( ) ) ;
442
+ msgs
360
443
}
361
444
362
445
fn advance_time_by ( duration : Duration , node : & Node ) {
@@ -365,6 +448,14 @@ fn advance_time_by(duration: Duration, node: &Node) {
365
448
connect_block ( node, & block) ;
366
449
}
367
450
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. send_payments_async = true ;
456
+ cfg
457
+ }
458
+
368
459
#[ test]
369
460
fn invalid_keysend_payment_secret ( ) {
370
461
let chanmon_cfgs = create_chanmon_cfgs ( 3 ) ;
@@ -2206,3 +2297,108 @@ fn invoice_server_is_not_channel_peer() {
2206
2297
let res = claim_payment_along_route ( ClaimAlongRouteArgs :: new ( sender, route, keysend_preimage) ) ;
2207
2298
assert_eq ! ( res. 0 , Some ( PaidBolt12Invoice :: StaticInvoice ( invoice) ) ) ;
2208
2299
}
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