Skip to content

Commit 6cbb34b

Browse files
f don't manually create message contexts
1 parent 00fceb2 commit 6cbb34b

File tree

1 file changed

+105
-85
lines changed

1 file changed

+105
-85
lines changed

lightning/src/ln/blinded_payment_tests.rs

+105-85
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,18 @@ use crate::util::ser::WithoutLength;
3535
use crate::util::test_utils;
3636
use 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

5052
fn 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]
113133
fn 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

Comments
 (0)