@@ -35,16 +35,18 @@ use crate::util::ser::WithoutLength;
3535use crate :: util:: test_utils;
3636use lightning_invoice:: RawBolt11Invoice ;
3737#[ 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 } ,
4139 crate :: ln:: inbound_payment,
4240 crate :: ln:: msgs:: OnionMessageHandler ,
4341 crate :: offers:: nonce:: Nonce ,
4442 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 ,
4646 crate :: types:: features:: Bolt12InvoiceFeatures ,
4747 crate :: types:: payment:: PaymentPreimage ,
48+
49+ core:: convert:: Infallible ,
4850} ;
4951
5052fn blinded_payment_path (
@@ -109,6 +111,24 @@ pub fn get_blinded_route_parameters(
109111 )
110112}
111113
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+
112132#[ test]
113133fn one_hop_blinded_path ( ) {
114134 do_one_hop_blinded_path ( true ) ;
@@ -1436,13 +1456,13 @@ fn static_invoice_unknown_required_features() {
14361456 create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 1_000_000 , 0 ) ;
14371457 create_unannounced_chan_between_nodes_with_value ( & nodes, 1 , 2 , 1_000_000 , 0 ) ;
14381458
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 ( ) ;
14461466 let offer = offer_builder. build ( ) . unwrap ( ) ;
14471467 let static_invoice_unknown_req_features = nodes[ 2 ] . node . create_static_invoice_builder_for_async_receive_offer (
14481468 & offer, nonce, None
@@ -1453,24 +1473,19 @@ fn static_invoice_unknown_required_features() {
14531473
14541474 let amt_msat = 5000 ;
14551475 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 ] ) ;
14581476 nodes[ 0 ] . node . pay_for_offer ( & offer, None , Some ( amt_msat) , None , payment_id, Retry :: Attempts ( 0 ) , None ) . unwrap ( ) ;
14591477
14601478 // 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 ( ) ;
14731486
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) ;
14741489 let events = nodes[ 0 ] . node . get_and_clear_pending_events ( ) ;
14751490 assert_eq ! ( events. len( ) , 1 ) ;
14761491 match events[ 0 ] {
@@ -1497,25 +1512,25 @@ fn ignore_unexpected_static_invoice() {
14971512 create_unannounced_chan_between_nodes_with_value ( & nodes, 1 , 2 , 1_000_000 , 0 ) ;
14981513
14991514 // 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 ( ) ;
15051521 let offer = offer_builder. build ( ) . unwrap ( ) ;
15061522 let amt_msat = 5000 ;
15071523 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 ] ) ;
15101524 nodes[ 0 ] . node . pay_for_offer ( & offer, None , Some ( amt_msat) , None , payment_id, Retry :: Attempts ( 0 ) , None ) . unwrap ( ) ;
15111525
15121526 // 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) ;
15151530
15161531 // Create a static invoice with the same payment_id but corresponding to a different offer.
15171532 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 ( ) ;
15191534 let sender_unintended_offer = offer_builder. build ( ) . unwrap ( ) ;
15201535
15211536 nodes[ 2 ] . node . create_static_invoice_builder_for_async_receive_offer (
@@ -1524,15 +1539,12 @@ fn ignore_unexpected_static_invoice() {
15241539 } ;
15251540
15261541 // 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) ;
15361548 let async_pmts_msgs = AsyncPaymentsMessageHandler :: release_pending_messages ( nodes[ 0 ] . node ) ;
15371549 assert ! ( async_pmts_msgs. is_empty( ) ) ;
15381550 assert ! ( nodes[ 0 ] . node. get_and_clear_pending_events( ) . is_empty( ) ) ;
@@ -1543,19 +1555,23 @@ fn ignore_unexpected_static_invoice() {
15431555 & offer, offer_nonce, None
15441556 ) . unwrap ( ) . build_and_sign ( & secp_ctx) . unwrap ( ) ;
15451557
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) ;
15501564 let async_pmts_msgs = AsyncPaymentsMessageHandler :: release_pending_messages ( nodes[ 0 ] . node ) ;
15511565 assert ! ( !async_pmts_msgs. is_empty( ) ) ;
15521566 assert ! ( async_pmts_msgs. into_iter( ) . all( |( msg, _) | matches!( msg, AsyncPaymentsMessage :: HeldHtlcAvailable ( _) ) ) ) ;
15531567
15541568 // 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) ;
15591575 let async_pmts_msgs = AsyncPaymentsMessageHandler :: release_pending_messages ( nodes[ 0 ] . node ) ;
15601576 assert ! ( async_pmts_msgs. is_empty( ) ) ;
15611577}
@@ -1573,57 +1589,61 @@ fn pays_static_invoice() {
15731589 create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 1_000_000 , 0 ) ;
15741590 create_unannounced_chan_between_nodes_with_value ( & nodes, 1 , 2 , 1_000_000 , 0 ) ;
15751591
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 ( ) ;
15811598 let offer = offer_builder. build ( ) . unwrap ( ) ;
15821599 let amt_msat = 5000 ;
15831600 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-
15981601 let static_invoice = nodes[ 2 ] . node . create_static_invoice_builder_for_async_receive_offer (
15991602 & offer, offer_nonce, None
16001603 ) . unwrap ( ) . build_and_sign ( & secp_ctx) . unwrap ( ) ;
16011604
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 ) ;
16071619 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 ( _) ) ) ) ;
16091621
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
16111623 // 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 ! ( )
16171627 } ;
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) ;
16191639
16201640 // Check that we've queued the HTLCs of the async keysend payment.
16211641 let htlc_updates = get_htlc_update_msgs ! ( nodes[ 0 ] , nodes[ 1 ] . node. get_our_node_id( ) ) ;
16221642 assert_eq ! ( htlc_updates. update_add_htlcs. len( ) , 1 ) ;
16231643 check_added_monitors ! ( nodes[ 0 ] , 1 ) ;
16241644
16251645 // 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 ) ;
16271647 assert ! ( nodes[ 0 ] . node. get_and_clear_pending_msg_events( ) . is_empty( ) ) ;
16281648}
16291649
0 commit comments