Skip to content

Commit ac35043

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 17231f7 commit ac35043

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
@@ -900,8 +900,18 @@ fn creates_offer_with_blinded_path_using_unannounced_introduction_node() {
900900
let onion_message = bob.onion_messenger.next_onion_message_for_peer(alice_id).unwrap();
901901
alice.onion_messenger.handle_onion_message(&bob_id, &onion_message);
902902

903-
let (_, reply_path) = extract_invoice_request(alice, &onion_message);
903+
let (invoice_request, reply_path) = extract_invoice_request(alice, &onion_message);
904+
assert_ne!(invoice_request.payer_id(), bob_id);
904905
assert_eq!(reply_path.introduction_node, IntroductionNode::NodeId(alice_id));
906+
907+
let onion_message = alice.onion_messenger.next_onion_message_for_peer(bob_id).unwrap();
908+
909+
let invoice = extract_invoice(bob, &onion_message);
910+
assert_ne!(invoice.signing_pubkey(), alice_id);
911+
assert!(!invoice.payment_paths().is_empty());
912+
for (_, path) in invoice.payment_paths() {
913+
assert_eq!(path.introduction_node, IntroductionNode::NodeId(bob_id));
914+
}
905915
}
906916

907917
/// Checks that a refund can be created using an unannounced node as a blinded path's introduction
@@ -934,6 +944,18 @@ fn creates_refund_with_blinded_path_using_unannounced_introduction_node() {
934944
assert_eq!(path.introduction_node, IntroductionNode::NodeId(alice_id));
935945
}
936946
expect_recent_payment!(bob, RecentPaymentDetails::AwaitingInvoice, payment_id);
947+
948+
let expected_invoice = alice.node.request_refund_payment(&refund).unwrap();
949+
950+
let onion_message = alice.onion_messenger.next_onion_message_for_peer(bob_id).unwrap();
951+
952+
let invoice = extract_invoice(bob, &onion_message);
953+
assert_eq!(invoice, expected_invoice);
954+
assert_ne!(invoice.signing_pubkey(), alice_id);
955+
assert!(!invoice.payment_paths().is_empty());
956+
for (_, path) in invoice.payment_paths() {
957+
assert_eq!(path.introduction_node, IntroductionNode::NodeId(bob_id));
958+
}
937959
}
938960

939961
/// 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)