@@ -35,16 +35,18 @@ use crate::util::ser::WithoutLength;
35
35
use crate :: util:: test_utils;
36
36
use lightning_invoice:: RawBolt11Invoice ;
37
37
#[ cfg( async_payments) ] use {
38
- crate :: blinded_path:: BlindedHop ,
39
- crate :: blinded_path:: message:: { AsyncPaymentsContext , BlindedMessagePath , OffersContext } ,
40
- crate :: ln:: channelmanager:: Verification ,
38
+ crate :: blinded_path:: message:: { BlindedMessagePath , MessageContext , OffersContext } ,
41
39
crate :: ln:: inbound_payment,
42
40
crate :: ln:: msgs:: OnionMessageHandler ,
43
41
crate :: offers:: nonce:: Nonce ,
44
42
crate :: onion_message:: async_payments:: { AsyncPaymentsMessage , AsyncPaymentsMessageHandler , ReleaseHeldHtlc } ,
45
- crate :: onion_message:: offers:: { OffersMessage , OffersMessageHandler } ,
43
+ crate :: onion_message:: messenger:: { Destination , MessageSendInstructions , MessageRouter , PeeledOnion } ,
44
+ crate :: onion_message:: offers:: OffersMessage ,
45
+ crate :: onion_message:: packet:: ParsedOnionMessageContents ,
46
46
crate :: types:: features:: Bolt12InvoiceFeatures ,
47
47
crate :: types:: payment:: PaymentPreimage ,
48
+
49
+ core:: convert:: Infallible ,
48
50
} ;
49
51
50
52
fn blinded_payment_path (
@@ -109,6 +111,24 @@ pub fn get_blinded_route_parameters(
109
111
)
110
112
}
111
113
114
+ fn extract_invoice_request_reply_path < ' a , ' b , ' c > (
115
+ invreq_recipient : & Node < ' a , ' b , ' c > , message : & msgs:: OnionMessage
116
+ ) -> BlindedMessagePath {
117
+ match invreq_recipient. onion_messenger . peel_onion_message ( message) {
118
+ Ok ( PeeledOnion :: Receive ( invreq, context, reply_path) ) => {
119
+ assert ! (
120
+ matches!( invreq, ParsedOnionMessageContents :: Offers ( OffersMessage :: InvoiceRequest ( _) ) )
121
+ ) ;
122
+ assert ! (
123
+ matches!( context, Some ( MessageContext :: Offers ( OffersContext :: InvoiceRequest { .. } ) ) )
124
+ ) ;
125
+ reply_path. unwrap ( )
126
+ } ,
127
+ Ok ( PeeledOnion :: Forward ( _, _) ) => panic ! ( "Unexpected onion message forward" ) ,
128
+ Err ( e) => panic ! ( "Failed to process onion message {:?}" , e) ,
129
+ }
130
+ }
131
+
112
132
#[ test]
113
133
fn one_hop_blinded_path ( ) {
114
134
do_one_hop_blinded_path ( true ) ;
@@ -1436,13 +1456,13 @@ fn static_invoice_unknown_required_features() {
1436
1456
create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 1_000_000 , 0 ) ;
1437
1457
create_unannounced_chan_between_nodes_with_value ( & nodes, 1 , 2 , 1_000_000 , 0 ) ;
1438
1458
1439
- // Use a dummy blinded path because we don't support retrieving the static invoice from the
1440
- // recipient's LSP yet.
1441
- let dummy_blinded_path_to_always_online_node = BlindedMessagePath :: from_raw (
1442
- nodes [ 1 ] . node . get_our_node_id ( ) , test_utils :: pubkey ( 42 ) ,
1443
- vec ! [ BlindedHop { blinded_node_id : test_utils :: pubkey ( 42 ) , encrypted_payload : vec! [ 42 ; 32 ] } ]
1444
- ) ;
1445
- let ( offer_builder , nonce ) = nodes[ 2 ] . node . create_async_receive_offer_builder ( vec ! [ dummy_blinded_path_to_always_online_node ] ) . unwrap ( ) ;
1459
+ let blinded_paths_to_always_online_node = nodes [ 1 ] . message_router . create_blinded_paths (
1460
+ nodes [ 1 ] . node . get_our_node_id ( ) ,
1461
+ MessageContext :: Offers ( OffersContext :: InvoiceRequest { nonce : Nonce ( [ 42 ; 16 ] ) } ) ,
1462
+ Vec :: new ( ) , & secp_ctx
1463
+ ) . unwrap ( ) ;
1464
+ let ( offer_builder , nonce ) =
1465
+ nodes[ 2 ] . node . create_async_receive_offer_builder ( blinded_paths_to_always_online_node ) . unwrap ( ) ;
1446
1466
let offer = offer_builder. build ( ) . unwrap ( ) ;
1447
1467
let static_invoice_unknown_req_features = nodes[ 2 ] . node . create_static_invoice_builder_for_async_receive_offer (
1448
1468
& offer, nonce, None
@@ -1453,24 +1473,19 @@ fn static_invoice_unknown_required_features() {
1453
1473
1454
1474
let amt_msat = 5000 ;
1455
1475
let payment_id = PaymentId ( [ 1 ; 32 ] ) ;
1456
- // Set the random bytes so we can predict the offer outbound payment context nonce.
1457
- * nodes[ 0 ] . keys_manager . override_random_bytes . lock ( ) . unwrap ( ) = Some ( [ 42 ; 32 ] ) ;
1458
1476
nodes[ 0 ] . node . pay_for_offer ( & offer, None , Some ( amt_msat) , None , payment_id, Retry :: Attempts ( 0 ) , None ) . unwrap ( ) ;
1459
1477
1460
1478
// Don't forward the invreq since we don't support retrieving the static invoice from the
1461
- // recipient's LSP yet, instead just provide the invoice directly to the payer.
1462
- let _invreq_om = nodes[ 0 ] . onion_messenger . next_onion_message_for_peer ( nodes[ 1 ] . node . get_our_node_id ( ) ) . unwrap ( ) ;
1463
-
1464
- let inbound_payment_key = inbound_payment:: ExpandedKey :: new (
1465
- & nodes[ 0 ] . keys_manager . get_inbound_payment_key_material ( )
1466
- ) ;
1467
- let offer_outbound_context_nonce = Nonce :: from_entropy_source ( nodes[ 0 ] . keys_manager ) ;
1468
- let hmac = payment_id. hmac_for_offer_payment ( offer_outbound_context_nonce, & inbound_payment_key) ;
1469
- if nodes[ 0 ] . node . handle_message (
1470
- OffersMessage :: StaticInvoice ( static_invoice_unknown_req_features) ,
1471
- Some ( OffersContext :: OutboundPayment { payment_id, nonce : offer_outbound_context_nonce, hmac : Some ( hmac) } ) , None
1472
- ) . is_some ( ) { panic ! ( ) }
1479
+ // recipient's LSP yet, instead manually construct the response.
1480
+ let invreq_om = nodes[ 0 ] . onion_messenger . next_onion_message_for_peer ( nodes[ 1 ] . node . get_our_node_id ( ) ) . unwrap ( ) ;
1481
+ let invreq_reply_path = extract_invoice_request_reply_path ( & nodes[ 1 ] , & invreq_om) ;
1482
+ nodes[ 1 ] . onion_messenger . send_onion_message (
1483
+ ParsedOnionMessageContents :: < Infallible > :: Offers ( OffersMessage :: StaticInvoice ( static_invoice_unknown_req_features) ) ,
1484
+ MessageSendInstructions :: WithoutReplyPath { destination : Destination :: BlindedPath ( invreq_reply_path) }
1485
+ ) . unwrap ( ) ;
1473
1486
1487
+ let static_invoice_om = nodes[ 1 ] . onion_messenger . next_onion_message_for_peer ( nodes[ 0 ] . node . get_our_node_id ( ) ) . unwrap ( ) ;
1488
+ nodes[ 0 ] . onion_messenger . handle_onion_message ( nodes[ 1 ] . node . get_our_node_id ( ) , & static_invoice_om) ;
1474
1489
let events = nodes[ 0 ] . node . get_and_clear_pending_events ( ) ;
1475
1490
assert_eq ! ( events. len( ) , 1 ) ;
1476
1491
match events[ 0 ] {
@@ -1497,25 +1512,25 @@ fn ignore_unexpected_static_invoice() {
1497
1512
create_unannounced_chan_between_nodes_with_value ( & nodes, 1 , 2 , 1_000_000 , 0 ) ;
1498
1513
1499
1514
// Initiate payment to the sender's intended offer.
1500
- let dummy_blinded_path_to_always_online_node = BlindedMessagePath :: from_raw (
1501
- nodes[ 1 ] . node . get_our_node_id ( ) , test_utils:: pubkey ( 42 ) ,
1502
- vec ! [ BlindedHop { blinded_node_id: test_utils:: pubkey( 42 ) , encrypted_payload: vec![ 42 ; 32 ] } ]
1503
- ) ;
1504
- let ( offer_builder, offer_nonce) = nodes[ 2 ] . node . create_async_receive_offer_builder ( vec ! [ dummy_blinded_path_to_always_online_node. clone( ) ] ) . unwrap ( ) ;
1515
+ let blinded_paths_to_always_online_node = nodes[ 1 ] . message_router . create_blinded_paths (
1516
+ nodes[ 1 ] . node . get_our_node_id ( ) ,
1517
+ MessageContext :: Offers ( OffersContext :: InvoiceRequest { nonce : Nonce ( [ 42 ; 16 ] ) } ) ,
1518
+ Vec :: new ( ) , & secp_ctx
1519
+ ) . unwrap ( ) ;
1520
+ let ( offer_builder, offer_nonce) = nodes[ 2 ] . node . create_async_receive_offer_builder ( blinded_paths_to_always_online_node. clone ( ) ) . unwrap ( ) ;
1505
1521
let offer = offer_builder. build ( ) . unwrap ( ) ;
1506
1522
let amt_msat = 5000 ;
1507
1523
let payment_id = PaymentId ( [ 1 ; 32 ] ) ;
1508
- // Set the random bytes so we can predict the offer outbound payment context nonce.
1509
- * nodes[ 0 ] . keys_manager . override_random_bytes . lock ( ) . unwrap ( ) = Some ( [ 42 ; 32 ] ) ;
1510
1524
nodes[ 0 ] . node . pay_for_offer ( & offer, None , Some ( amt_msat) , None , payment_id, Retry :: Attempts ( 0 ) , None ) . unwrap ( ) ;
1511
1525
1512
1526
// Don't forward the invreq since we don't support retrieving the static invoice from the
1513
- // recipient's LSP yet, instead just provide the invoice directly to the payer.
1514
- let _invreq_om = nodes[ 0 ] . onion_messenger . next_onion_message_for_peer ( nodes[ 1 ] . node . get_our_node_id ( ) ) . unwrap ( ) ;
1527
+ // recipient's LSP yet, instead manually construct the responses below.
1528
+ let invreq_om = nodes[ 0 ] . onion_messenger . next_onion_message_for_peer ( nodes[ 1 ] . node . get_our_node_id ( ) ) . unwrap ( ) ;
1529
+ let invreq_reply_path = extract_invoice_request_reply_path ( & nodes[ 1 ] , & invreq_om) ;
1515
1530
1516
1531
// Create a static invoice with the same payment_id but corresponding to a different offer.
1517
1532
let unexpected_static_invoice = {
1518
- let ( offer_builder, nonce) = nodes[ 2 ] . node . create_async_receive_offer_builder ( vec ! [ dummy_blinded_path_to_always_online_node ] ) . unwrap ( ) ;
1533
+ let ( offer_builder, nonce) = nodes[ 2 ] . node . create_async_receive_offer_builder ( blinded_paths_to_always_online_node ) . unwrap ( ) ;
1519
1534
let sender_unintended_offer = offer_builder. build ( ) . unwrap ( ) ;
1520
1535
1521
1536
nodes[ 2 ] . node . create_static_invoice_builder_for_async_receive_offer (
@@ -1524,15 +1539,12 @@ fn ignore_unexpected_static_invoice() {
1524
1539
} ;
1525
1540
1526
1541
// Check that we'll ignore the unexpected static invoice.
1527
- let inbound_payment_key = inbound_payment:: ExpandedKey :: new (
1528
- & nodes[ 0 ] . keys_manager . get_inbound_payment_key_material ( )
1529
- ) ;
1530
- let offer_outbound_context_nonce = Nonce :: from_entropy_source ( nodes[ 0 ] . keys_manager ) ;
1531
- let hmac = payment_id. hmac_for_offer_payment ( offer_outbound_context_nonce, & inbound_payment_key) ;
1532
- assert ! ( nodes[ 0 ] . node. handle_message(
1533
- OffersMessage :: StaticInvoice ( unexpected_static_invoice) ,
1534
- Some ( OffersContext :: OutboundPayment { payment_id, nonce: offer_outbound_context_nonce, hmac: Some ( hmac) } ) , None
1535
- ) . is_none( ) ) ;
1542
+ nodes[ 1 ] . onion_messenger . send_onion_message (
1543
+ ParsedOnionMessageContents :: < Infallible > :: Offers ( OffersMessage :: StaticInvoice ( unexpected_static_invoice) ) ,
1544
+ MessageSendInstructions :: WithoutReplyPath { destination : Destination :: BlindedPath ( invreq_reply_path. clone ( ) ) }
1545
+ ) . unwrap ( ) ;
1546
+ let unexpected_static_invoice_om = nodes[ 1 ] . onion_messenger . next_onion_message_for_peer ( nodes[ 0 ] . node . get_our_node_id ( ) ) . unwrap ( ) ;
1547
+ nodes[ 0 ] . onion_messenger . handle_onion_message ( nodes[ 1 ] . node . get_our_node_id ( ) , & unexpected_static_invoice_om) ;
1536
1548
let async_pmts_msgs = AsyncPaymentsMessageHandler :: release_pending_messages ( nodes[ 0 ] . node ) ;
1537
1549
assert ! ( async_pmts_msgs. is_empty( ) ) ;
1538
1550
assert ! ( nodes[ 0 ] . node. get_and_clear_pending_events( ) . is_empty( ) ) ;
@@ -1543,19 +1555,23 @@ fn ignore_unexpected_static_invoice() {
1543
1555
& offer, offer_nonce, None
1544
1556
) . unwrap ( ) . build_and_sign ( & secp_ctx) . unwrap ( ) ;
1545
1557
1546
- assert ! ( nodes[ 0 ] . node. handle_message(
1547
- OffersMessage :: StaticInvoice ( valid_static_invoice. clone( ) ) ,
1548
- Some ( OffersContext :: OutboundPayment { payment_id, nonce: offer_outbound_context_nonce, hmac: Some ( hmac) } ) , None
1549
- ) . is_none( ) ) ;
1558
+ nodes[ 1 ] . onion_messenger . send_onion_message (
1559
+ ParsedOnionMessageContents :: < Infallible > :: Offers ( OffersMessage :: StaticInvoice ( valid_static_invoice. clone ( ) ) ) ,
1560
+ MessageSendInstructions :: WithoutReplyPath { destination : Destination :: BlindedPath ( invreq_reply_path. clone ( ) ) }
1561
+ ) . unwrap ( ) ;
1562
+ let static_invoice_om = nodes[ 1 ] . onion_messenger . next_onion_message_for_peer ( nodes[ 0 ] . node . get_our_node_id ( ) ) . unwrap ( ) ;
1563
+ nodes[ 0 ] . onion_messenger . handle_onion_message ( nodes[ 1 ] . node . get_our_node_id ( ) , & static_invoice_om) ;
1550
1564
let async_pmts_msgs = AsyncPaymentsMessageHandler :: release_pending_messages ( nodes[ 0 ] . node ) ;
1551
1565
assert ! ( !async_pmts_msgs. is_empty( ) ) ;
1552
1566
assert ! ( async_pmts_msgs. into_iter( ) . all( |( msg, _) | matches!( msg, AsyncPaymentsMessage :: HeldHtlcAvailable ( _) ) ) ) ;
1553
1567
1554
1568
// Receiving a duplicate invoice will have no effect.
1555
- assert ! ( nodes[ 0 ] . node. handle_message(
1556
- OffersMessage :: StaticInvoice ( valid_static_invoice) ,
1557
- Some ( OffersContext :: OutboundPayment { payment_id, nonce: offer_outbound_context_nonce, hmac: Some ( hmac) } ) , None
1558
- ) . is_none( ) ) ;
1569
+ nodes[ 1 ] . onion_messenger . send_onion_message (
1570
+ ParsedOnionMessageContents :: < Infallible > :: Offers ( OffersMessage :: StaticInvoice ( valid_static_invoice) ) ,
1571
+ MessageSendInstructions :: WithoutReplyPath { destination : Destination :: BlindedPath ( invreq_reply_path) }
1572
+ ) . unwrap ( ) ;
1573
+ let dup_static_invoice_om = nodes[ 1 ] . onion_messenger . next_onion_message_for_peer ( nodes[ 0 ] . node . get_our_node_id ( ) ) . unwrap ( ) ;
1574
+ nodes[ 0 ] . onion_messenger . handle_onion_message ( nodes[ 1 ] . node . get_our_node_id ( ) , & dup_static_invoice_om) ;
1559
1575
let async_pmts_msgs = AsyncPaymentsMessageHandler :: release_pending_messages ( nodes[ 0 ] . node ) ;
1560
1576
assert ! ( async_pmts_msgs. is_empty( ) ) ;
1561
1577
}
@@ -1573,57 +1589,61 @@ fn pays_static_invoice() {
1573
1589
create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 1_000_000 , 0 ) ;
1574
1590
create_unannounced_chan_between_nodes_with_value ( & nodes, 1 , 2 , 1_000_000 , 0 ) ;
1575
1591
1576
- let dummy_blinded_path_to_always_online_node = BlindedMessagePath :: from_raw (
1577
- nodes[ 1 ] . node . get_our_node_id ( ) , test_utils:: pubkey ( 42 ) ,
1578
- vec ! [ BlindedHop { blinded_node_id: test_utils:: pubkey( 42 ) , encrypted_payload: vec![ 42 ; 32 ] } ]
1579
- ) ;
1580
- let ( offer_builder, offer_nonce) = nodes[ 2 ] . node . create_async_receive_offer_builder ( vec ! [ dummy_blinded_path_to_always_online_node. clone( ) ] ) . unwrap ( ) ;
1592
+ let blinded_paths_to_always_online_node = nodes[ 1 ] . message_router . create_blinded_paths (
1593
+ nodes[ 1 ] . node . get_our_node_id ( ) ,
1594
+ MessageContext :: Offers ( OffersContext :: InvoiceRequest { nonce : Nonce ( [ 42 ; 16 ] ) } ) ,
1595
+ Vec :: new ( ) , & secp_ctx
1596
+ ) . unwrap ( ) ;
1597
+ let ( offer_builder, offer_nonce) = nodes[ 2 ] . node . create_async_receive_offer_builder ( blinded_paths_to_always_online_node) . unwrap ( ) ;
1581
1598
let offer = offer_builder. build ( ) . unwrap ( ) ;
1582
1599
let amt_msat = 5000 ;
1583
1600
let payment_id = PaymentId ( [ 1 ; 32 ] ) ;
1584
- // Set the random bytes so we can predict the offer outbound payment context nonce.
1585
- * nodes[ 0 ] . keys_manager . override_random_bytes . lock ( ) . unwrap ( ) = Some ( [ 42 ; 32 ] ) ;
1586
- nodes[ 0 ] . node . pay_for_offer ( & offer, None , Some ( amt_msat) , None , payment_id, Retry :: Attempts ( 0 ) , None ) . unwrap ( ) ;
1587
-
1588
- // Don't forward the invreq since we don't support retrieving the static invoice from the
1589
- // recipient's LSP yet, instead just provide the invoice directly to the payer.
1590
- let _invreq_om = nodes[ 0 ] . onion_messenger . next_onion_message_for_peer ( nodes[ 1 ] . node . get_our_node_id ( ) ) . unwrap ( ) ;
1591
-
1592
- let inbound_payment_key = inbound_payment:: ExpandedKey :: new (
1593
- & nodes[ 0 ] . keys_manager . get_inbound_payment_key_material ( )
1594
- ) ;
1595
- let offer_outbound_context_nonce = Nonce :: from_entropy_source ( nodes[ 0 ] . keys_manager ) ;
1596
- let hmac = payment_id. hmac_for_offer_payment ( offer_outbound_context_nonce, & inbound_payment_key) ;
1597
-
1598
1601
let static_invoice = nodes[ 2 ] . node . create_static_invoice_builder_for_async_receive_offer (
1599
1602
& offer, offer_nonce, None
1600
1603
) . unwrap ( ) . build_and_sign ( & secp_ctx) . unwrap ( ) ;
1601
1604
1602
- assert ! ( nodes[ 0 ] . node. handle_message(
1603
- OffersMessage :: StaticInvoice ( static_invoice) ,
1604
- Some ( OffersContext :: OutboundPayment { payment_id, nonce: offer_outbound_context_nonce, hmac: Some ( hmac) } ) , None
1605
- ) . is_none( ) ) ;
1606
- let async_pmts_msgs = AsyncPaymentsMessageHandler :: release_pending_messages ( nodes[ 0 ] . node ) ;
1605
+ nodes[ 0 ] . node . pay_for_offer ( & offer, None , Some ( amt_msat) , None , payment_id, Retry :: Attempts ( 0 ) , None ) . unwrap ( ) ;
1606
+
1607
+ // Don't forward the invreq since we don't support retrieving the static invoice from the
1608
+ // recipient's LSP yet, instead manually construct the response.
1609
+ let invreq_om = nodes[ 0 ] . onion_messenger . next_onion_message_for_peer ( nodes[ 1 ] . node . get_our_node_id ( ) ) . unwrap ( ) ;
1610
+ let invreq_reply_path = extract_invoice_request_reply_path ( & nodes[ 1 ] , & invreq_om) ;
1611
+
1612
+ nodes[ 1 ] . onion_messenger . send_onion_message (
1613
+ ParsedOnionMessageContents :: < Infallible > :: Offers ( OffersMessage :: StaticInvoice ( static_invoice) ) ,
1614
+ MessageSendInstructions :: WithoutReplyPath { destination : Destination :: BlindedPath ( invreq_reply_path) }
1615
+ ) . unwrap ( ) ;
1616
+ let static_invoice_om = nodes[ 1 ] . onion_messenger . next_onion_message_for_peer ( nodes[ 0 ] . node . get_our_node_id ( ) ) . unwrap ( ) ;
1617
+ nodes[ 0 ] . onion_messenger . handle_onion_message ( nodes[ 1 ] . node . get_our_node_id ( ) , & static_invoice_om) ;
1618
+ let mut async_pmts_msgs = AsyncPaymentsMessageHandler :: release_pending_messages ( nodes[ 0 ] . node ) ;
1607
1619
assert ! ( !async_pmts_msgs. is_empty( ) ) ;
1608
- assert ! ( async_pmts_msgs. into_iter ( ) . all( |( msg, _) | matches!( msg, AsyncPaymentsMessage :: HeldHtlcAvailable ( _) ) ) ) ;
1620
+ assert ! ( async_pmts_msgs. iter ( ) . all( |( msg, _) | matches!( msg, AsyncPaymentsMessage :: HeldHtlcAvailable ( _) ) ) ) ;
1609
1621
1610
- // Manually create the message and context releasing the HTLC since the recipient doesn't support
1622
+ // Manually send the message and context releasing the HTLC since the recipient doesn't support
1611
1623
// responding themselves yet.
1612
- let outbound_async_payment_context_nonce = Nonce :: from_entropy_source ( nodes[ 0 ] . keys_manager ) ;
1613
- let outbound_async_payment_context = AsyncPaymentsContext :: OutboundPayment {
1614
- payment_id,
1615
- nonce : outbound_async_payment_context_nonce,
1616
- hmac : payment_id. hmac_for_async_payment ( outbound_async_payment_context_nonce, & inbound_payment_key) ,
1624
+ let held_htlc_avail_reply_path = match async_pmts_msgs. pop ( ) . unwrap ( ) . 1 {
1625
+ MessageSendInstructions :: WithSpecifiedReplyPath { reply_path, .. } => reply_path,
1626
+ _ => panic ! ( )
1617
1627
} ;
1618
- nodes[ 0 ] . node . handle_release_held_htlc ( ReleaseHeldHtlc { } , outbound_async_payment_context. clone ( ) ) ;
1628
+ nodes[ 2 ] . onion_messenger . send_onion_message (
1629
+ ParsedOnionMessageContents :: < Infallible > :: AsyncPayments (
1630
+ AsyncPaymentsMessage :: ReleaseHeldHtlc ( ReleaseHeldHtlc { } ) ,
1631
+ ) ,
1632
+ MessageSendInstructions :: WithoutReplyPath {
1633
+ destination : Destination :: BlindedPath ( held_htlc_avail_reply_path)
1634
+ }
1635
+ ) . unwrap ( ) ;
1636
+
1637
+ let release_held_htlc_om = nodes[ 2 ] . onion_messenger . next_onion_message_for_peer ( nodes[ 0 ] . node . get_our_node_id ( ) ) . unwrap ( ) ;
1638
+ nodes[ 0 ] . onion_messenger . handle_onion_message ( nodes[ 2 ] . node . get_our_node_id ( ) , & release_held_htlc_om) ;
1619
1639
1620
1640
// Check that we've queued the HTLCs of the async keysend payment.
1621
1641
let htlc_updates = get_htlc_update_msgs ! ( nodes[ 0 ] , nodes[ 1 ] . node. get_our_node_id( ) ) ;
1622
1642
assert_eq ! ( htlc_updates. update_add_htlcs. len( ) , 1 ) ;
1623
1643
check_added_monitors ! ( nodes[ 0 ] , 1 ) ;
1624
1644
1625
1645
// Receiving a duplicate release_htlc message doesn't result in duplicate payment.
1626
- nodes[ 0 ] . node . handle_release_held_htlc ( ReleaseHeldHtlc { } , outbound_async_payment_context . clone ( ) ) ;
1646
+ nodes[ 0 ] . onion_messenger . handle_onion_message ( nodes [ 2 ] . node . get_our_node_id ( ) , & release_held_htlc_om ) ;
1627
1647
assert ! ( nodes[ 0 ] . node. get_and_clear_pending_msg_events( ) . is_empty( ) ) ;
1628
1648
}
1629
1649
0 commit comments