Skip to content

Commit 78ddb01

Browse files
committed
WIP: three-hop blinded payment paths
1 parent 492e563 commit 78ddb01

File tree

1 file changed

+76
-23
lines changed

1 file changed

+76
-23
lines changed

lightning/src/routing/router.rs

+76-23
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ impl<G: Deref<Target = NetworkGraph<L>> + Clone, L: Deref, S: Deref, SP: Sized,
9090
&self, recipient: PublicKey, first_hops: Vec<ChannelDetails>, tlvs: ReceiveTlvs,
9191
amount_msats: u64, entropy_source: &ES, secp_ctx: &Secp256k1<T>
9292
) -> Result<Vec<(BlindedPayInfo, BlindedPath)>, ()> {
93+
let recipient_node_id = NodeId::from_pubkey(&recipient);
94+
9395
// Limit the number of blinded paths that are computed.
9496
const MAX_PAYMENT_PATHS: usize = 3;
9597

@@ -98,37 +100,88 @@ impl<G: Deref<Target = NetworkGraph<L>> + Clone, L: Deref, S: Deref, SP: Sized,
98100
const MIN_PEER_CHANNELS: usize = 3;
99101

100102
let network_graph = self.network_graph.deref().read_only();
101-
first_hops.into_iter()
102-
.filter(|details| details.is_public)
103+
first_hops.iter()
103104
.filter(|details| details.counterparty.features.supports_route_blinding())
104105
.filter(|details| amount_msats <= details.inbound_capacity_msat)
105106
.filter(|details| amount_msats >= details.inbound_htlc_minimum_msat.unwrap_or(0))
106107
.filter(|details| amount_msats <= details.inbound_htlc_maximum_msat.unwrap_or(0))
107-
.filter(|details| network_graph
108-
.node(&NodeId::from_pubkey(&details.counterparty.node_id))
109-
.map(|node_info| node_info.channels.len() >= MIN_PEER_CHANNELS)
110-
.unwrap_or(false)
108+
.map(|details| (details, NodeId::from_pubkey(&details.counterparty.node_id)))
109+
// Limit to counterparties with announced channels
110+
.filter_map(|(details, counterparty_node_id)|
111+
network_graph
112+
.node(&counterparty_node_id)
113+
.map(|info| &info.channels[..])
114+
.and_then(|channels| (channels.len() >= MIN_PEER_CHANNELS).then(|| channels))
115+
.map(|channels| (details, counterparty_node_id, channels))
116+
)
117+
// Pair counterparties with their other channels
118+
.flat_map(|(details, counterparty_node_id, counterparty_channels)|
119+
counterparty_channels
120+
.iter()
121+
.filter_map(|scid| network_graph.channels().get_key_value(scid))
122+
.filter_map(move |(scid, info)| info
123+
.as_directed_to(&counterparty_node_id)
124+
.map(|(info, source)| (source, *scid, info))
125+
)
126+
.filter(|(source, _, _)| **source != recipient_node_id)
127+
.filter(|(source, _, _)| network_graph
128+
.node(source)
129+
.and_then(|info| info.announcement_info.as_ref())
130+
.map(|info| info.features.supports_route_blinding())
131+
.unwrap_or(false)
132+
)
133+
.filter(|(_, _, info)| amount_msats >= info.direction().htlc_minimum_msat)
134+
.filter(|(_, _, info)| amount_msats <= info.direction().htlc_maximum_msat)
135+
.map(move |(source, scid, info)| (source, scid, info, details))
111136
)
112-
.map(|details| {
113-
let short_channel_id = details.get_inbound_payment_scid().unwrap();
114-
let payment_relay: PaymentRelay = details.counterparty.forwarding_info.unwrap().into();
115-
let payment_constraints = PaymentConstraints {
116-
max_cltv_expiry: tlvs.payment_constraints.max_cltv_expiry
117-
+ payment_relay.cltv_expiry_delta as u32,
118-
htlc_minimum_msat: details.inbound_htlc_minimum_msat.unwrap_or(0),
137+
// Construct blinded paths where the counterparty's counterparty is the introduction
138+
// node:
139+
//
140+
// source --- info ---> counterparty --- details ---> recipient
141+
.map(|(introduction_node_id, scid, info, details)| {
142+
let counterparty_forward_node = {
143+
let short_channel_id = details.get_inbound_payment_scid().unwrap();
144+
let payment_relay: PaymentRelay =
145+
details.counterparty.forwarding_info.clone().unwrap().into();
146+
let payment_constraints = PaymentConstraints {
147+
max_cltv_expiry: payment_relay.cltv_expiry_delta as u32
148+
+ tlvs.payment_constraints.max_cltv_expiry,
149+
htlc_minimum_msat: details.inbound_htlc_minimum_msat.unwrap_or(0),
150+
};
151+
ForwardNode {
152+
tlvs: ForwardTlvs {
153+
short_channel_id,
154+
payment_relay,
155+
payment_constraints,
156+
features: BlindedHopFeatures::empty(),
157+
},
158+
node_id: details.counterparty.node_id,
159+
htlc_maximum_msat: details.inbound_htlc_maximum_msat.unwrap_or(0),
160+
}
119161
};
120-
let forward_node = ForwardNode {
121-
tlvs: ForwardTlvs {
122-
short_channel_id,
123-
payment_relay,
124-
payment_constraints,
125-
features: BlindedHopFeatures::empty(),
126-
},
127-
node_id: details.counterparty.node_id,
128-
htlc_maximum_msat: details.inbound_htlc_maximum_msat.unwrap_or(0),
162+
let introduction_forward_node = {
163+
let htlc_minimum_msat = info.direction().htlc_minimum_msat;
164+
let htlc_maximum_msat = info.direction().htlc_maximum_msat;
165+
let payment_relay: PaymentRelay = info.into();
166+
let payment_constraints = PaymentConstraints {
167+
max_cltv_expiry: payment_relay.cltv_expiry_delta as u32
168+
+ counterparty_forward_node.tlvs.payment_constraints.max_cltv_expiry,
169+
htlc_minimum_msat,
170+
};
171+
ForwardNode {
172+
tlvs: ForwardTlvs {
173+
short_channel_id: scid,
174+
payment_relay,
175+
payment_constraints,
176+
features: BlindedHopFeatures::empty(),
177+
},
178+
node_id: introduction_node_id.as_pubkey().unwrap(),
179+
htlc_maximum_msat,
180+
}
129181
};
130182
BlindedPath::new_for_payment(
131-
&[forward_node], recipient, tlvs.clone(), u64::MAX, entropy_source, secp_ctx
183+
&[introduction_forward_node, counterparty_forward_node], recipient,
184+
tlvs.clone(), u64::MAX, entropy_source, secp_ctx
132185
)
133186
})
134187
.take(MAX_PAYMENT_PATHS)

0 commit comments

Comments
 (0)