Skip to content

Commit 3bf8420

Browse files
committed
Blinded payments to unannounced introduction node
When creating blinded paths for receiving onion payments, allow using the recipient's only peer as the introduction node when the recipient is unannounced. This allows for sending payments without going through an intermediary, which is useful for testing or when only connected to an LSP with an empty NetworkGraph.
1 parent 7d1745e commit 3bf8420

File tree

2 files changed

+38
-2
lines changed

2 files changed

+38
-2
lines changed

lightning/src/ln/offers_tests.rs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -985,8 +985,18 @@ fn creates_offer_with_blinded_path_using_unannounced_introduction_node() {
985985
let onion_message = bob.onion_messenger.next_onion_message_for_peer(alice_id).unwrap();
986986
alice.onion_messenger.handle_onion_message(&bob_id, &onion_message);
987987

988-
let (_, reply_path) = extract_invoice_request(alice, &onion_message);
988+
let (invoice_request, reply_path) = extract_invoice_request(alice, &onion_message);
989+
assert_ne!(invoice_request.payer_id(), bob_id);
989990
assert_eq!(reply_path.introduction_node, IntroductionNode::NodeId(alice_id));
991+
992+
let onion_message = alice.onion_messenger.next_onion_message_for_peer(bob_id).unwrap();
993+
994+
let invoice = extract_invoice(bob, &onion_message);
995+
assert_ne!(invoice.signing_pubkey(), alice_id);
996+
assert!(!invoice.payment_paths().is_empty());
997+
for (_, path) in invoice.payment_paths() {
998+
assert_eq!(path.introduction_node, IntroductionNode::NodeId(bob_id));
999+
}
9901000
}
9911001

9921002
/// Checks that a refund can be created using an unannounced node as a blinded path's introduction
@@ -1019,6 +1029,18 @@ fn creates_refund_with_blinded_path_using_unannounced_introduction_node() {
10191029
assert_eq!(path.introduction_node, IntroductionNode::NodeId(alice_id));
10201030
}
10211031
expect_recent_payment!(bob, RecentPaymentDetails::AwaitingInvoice, payment_id);
1032+
1033+
let expected_invoice = alice.node.request_refund_payment(&refund).unwrap();
1034+
1035+
let onion_message = alice.onion_messenger.next_onion_message_for_peer(bob_id).unwrap();
1036+
1037+
let invoice = extract_invoice(bob, &onion_message);
1038+
assert_eq!(invoice, expected_invoice);
1039+
assert_ne!(invoice.signing_pubkey(), alice_id);
1040+
assert!(!invoice.payment_paths().is_empty());
1041+
for (_, path) in invoice.payment_paths() {
1042+
assert_eq!(path.introduction_node, IntroductionNode::NodeId(bob_id));
1043+
}
10221044
}
10231045

10241046
/// Fails creating or paying an offer when a blinded path cannot be created because no peers are

lightning/src/routing/router.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,20 @@ impl<G: Deref<Target = NetworkGraph<L>> + Clone, L: Deref, ES: Deref, S: Deref,
100100
// recipient's node_id.
101101
const MIN_PEER_CHANNELS: usize = 3;
102102

103+
let has_one_peer = first_hops
104+
.first()
105+
.map(|details| details.counterparty.node_id)
106+
.map(|node_id| first_hops
107+
.iter()
108+
.skip(1)
109+
.all(|details| details.counterparty.node_id == node_id)
110+
)
111+
.unwrap_or(false);
112+
103113
let network_graph = self.network_graph.deref().read_only();
114+
let is_recipient_announced =
115+
network_graph.nodes().contains_key(&NodeId::from_pubkey(&recipient));
116+
104117
let paths = first_hops.into_iter()
105118
.filter(|details| details.counterparty.features.supports_route_blinding())
106119
.filter(|details| amount_msats <= details.inbound_capacity_msat)
@@ -109,7 +122,8 @@ impl<G: Deref<Target = NetworkGraph<L>> + Clone, L: Deref, ES: Deref, S: Deref,
109122
.filter(|details| network_graph
110123
.node(&NodeId::from_pubkey(&details.counterparty.node_id))
111124
.map(|node_info| node_info.channels.len() >= MIN_PEER_CHANNELS)
112-
.unwrap_or(false)
125+
// Allow payments directly with the only peer when unannounced.
126+
.unwrap_or(!is_recipient_announced && has_one_peer)
113127
)
114128
.filter_map(|details| {
115129
let short_channel_id = match details.get_inbound_payment_scid() {

0 commit comments

Comments
 (0)