Skip to content

Commit 812aaec

Browse files
Routing: accommodate for blinded paths in used liquidity tracking
1 parent 30cc23a commit 812aaec

File tree

1 file changed

+35
-22
lines changed

1 file changed

+35
-22
lines changed

lightning/src/routing/router.rs

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -993,6 +993,17 @@ impl<'a> CandidateRouteHop<'a> {
993993
EffectiveCapacity::Infinite,
994994
}
995995
}
996+
fn id(&self, channel_direction: bool /* src_node_id < target_node_id */) -> CandidateHopId {
997+
CandidateHopId::Clear((self.short_channel_id(), channel_direction))
998+
}
999+
}
1000+
1001+
#[derive(Eq, Hash, PartialEq)]
1002+
enum CandidateHopId {
1003+
/// Contains (scid, src_node_id < target_node_id)
1004+
Clear((u64, bool)),
1005+
/// Index of the blinded route hint in [`Payee::Blinded::route_hints`].
1006+
Blinded(usize),
9961007
}
9971008

9981009
#[inline]
@@ -1236,7 +1247,7 @@ impl fmt::Display for LoggedPayeePubkey {
12361247

12371248
#[inline]
12381249
fn sort_first_hop_channels(
1239-
channels: &mut Vec<&ChannelDetails>, used_channel_liquidities: &HashMap<(u64, bool), u64>,
1250+
channels: &mut Vec<&ChannelDetails>, used_liquidities: &HashMap<CandidateHopId, u64>,
12401251
recommended_value_msat: u64, our_node_pubkey: &PublicKey
12411252
) {
12421253
// Sort the first_hops channels to the same node(s) in priority order of which channel we'd
@@ -1254,11 +1265,11 @@ fn sort_first_hop_channels(
12541265
// Available outbound balances factor in liquidity already reserved for previously found paths.
12551266
channels.sort_unstable_by(|chan_a, chan_b| {
12561267
let chan_a_outbound_limit_msat = chan_a.next_outbound_htlc_limit_msat
1257-
.saturating_sub(*used_channel_liquidities.get(&(chan_a.get_outbound_payment_scid().unwrap(),
1258-
our_node_pubkey < &chan_a.counterparty.node_id)).unwrap_or(&0));
1268+
.saturating_sub(*used_liquidities.get(&CandidateHopId::Clear((chan_a.get_outbound_payment_scid().unwrap(),
1269+
our_node_pubkey < &chan_a.counterparty.node_id))).unwrap_or(&0));
12591270
let chan_b_outbound_limit_msat = chan_b.next_outbound_htlc_limit_msat
1260-
.saturating_sub(*used_channel_liquidities.get(&(chan_b.get_outbound_payment_scid().unwrap(),
1261-
our_node_pubkey < &chan_b.counterparty.node_id)).unwrap_or(&0));
1271+
.saturating_sub(*used_liquidities.get(&CandidateHopId::Clear((chan_b.get_outbound_payment_scid().unwrap(),
1272+
our_node_pubkey < &chan_b.counterparty.node_id))).unwrap_or(&0));
12621273
if chan_b_outbound_limit_msat < recommended_value_msat || chan_a_outbound_limit_msat < recommended_value_msat {
12631274
// Sort in descending order
12641275
chan_b_outbound_limit_msat.cmp(&chan_a_outbound_limit_msat)
@@ -1502,19 +1513,20 @@ where L::Target: Logger {
15021513
// drop the requirement by setting this to 0.
15031514
let mut channel_saturation_pow_half = payment_params.max_channel_saturation_power_of_half;
15041515

1505-
// Keep track of how much liquidity has been used in selected channels. Used to determine
1506-
// if the channel can be used by additional MPP paths or to inform path finding decisions. It is
1507-
// aware of direction *only* to ensure that the correct htlc_maximum_msat value is used. Hence,
1508-
// liquidity used in one direction will not offset any used in the opposite direction.
1509-
let mut used_channel_liquidities: HashMap<(u64, bool), u64> =
1516+
// Keep track of how much liquidity has been used in selected channels or blinded paths. Used to
1517+
// determine if the channel can be used by additional MPP paths or to inform path finding
1518+
// decisions. It is aware of direction *only* to ensure that the correct htlc_maximum_msat value
1519+
// is used. Hence, liquidity used in one direction will not offset any used in the opposite
1520+
// direction.
1521+
let mut used_liquidities: HashMap<CandidateHopId, u64> =
15101522
HashMap::with_capacity(network_nodes.len());
15111523

15121524
// Keeping track of how much value we already collected across other paths. Helps to decide
15131525
// when we want to stop looking for new paths.
15141526
let mut already_collected_value_msat = 0;
15151527

15161528
for (_, channels) in first_hop_targets.iter_mut() {
1517-
sort_first_hop_channels(channels, &used_channel_liquidities, recommended_value_msat,
1529+
sort_first_hop_channels(channels, &used_liquidities, recommended_value_msat,
15181530
our_node_pubkey);
15191531
}
15201532

@@ -1549,8 +1561,8 @@ where L::Target: Logger {
15491561
// if the amount being transferred over this path is lower.
15501562
// We do this for now, but this is a subject for removal.
15511563
if let Some(mut available_value_contribution_msat) = htlc_maximum_msat.checked_sub($next_hops_fee_msat) {
1552-
let used_liquidity_msat = used_channel_liquidities
1553-
.get(&(short_channel_id, $src_node_id < $dest_node_id))
1564+
let used_liquidity_msat = used_liquidities
1565+
.get(&$candidate.id($src_node_id < $dest_node_id))
15541566
.map_or(0, |used_liquidity_msat| {
15551567
available_value_contribution_msat = available_value_contribution_msat
15561568
.saturating_sub(*used_liquidity_msat);
@@ -1821,7 +1833,7 @@ where L::Target: Logger {
18211833

18221834
// TODO: diversify by nodes (so that all paths aren't doomed if one node is offline).
18231835
'paths_collection: loop {
1824-
// For every new path, start from scratch, except for used_channel_liquidities, which
1836+
// For every new path, start from scratch, except for used_liquidities, which
18251837
// helps to avoid reusing previously selected paths in future iterations.
18261838
targets.clear();
18271839
dist.clear();
@@ -1907,8 +1919,9 @@ where L::Target: Logger {
19071919
hop_used = false;
19081920
}
19091921

1910-
let used_liquidity_msat = used_channel_liquidities
1911-
.get(&(hop.short_channel_id, source < target)).copied().unwrap_or(0);
1922+
let used_liquidity_msat = used_liquidities
1923+
.get(&candidate.id(source < target)).copied()
1924+
.unwrap_or(0);
19121925
let channel_usage = ChannelUsage {
19131926
amount_msat: final_value_msat + aggregate_next_hops_fee_msat,
19141927
inflight_htlc_msat: used_liquidity_msat,
@@ -1928,7 +1941,7 @@ where L::Target: Logger {
19281941

19291942
// Searching for a direct channel between last checked hop and first_hop_targets
19301943
if let Some(first_channels) = first_hop_targets.get_mut(&NodeId::from_pubkey(&prev_hop_id)) {
1931-
sort_first_hop_channels(first_channels, &used_channel_liquidities,
1944+
sort_first_hop_channels(first_channels, &used_liquidities,
19321945
recommended_value_msat, our_node_pubkey);
19331946
for details in first_channels {
19341947
let first_hop_candidate = CandidateRouteHop::FirstHop { details };
@@ -1969,7 +1982,7 @@ where L::Target: Logger {
19691982
// always assumes that the third argument is a node to which we have a
19701983
// path.
19711984
if let Some(first_channels) = first_hop_targets.get_mut(&NodeId::from_pubkey(&hop.src_node_id)) {
1972-
sort_first_hop_channels(first_channels, &used_channel_liquidities,
1985+
sort_first_hop_channels(first_channels, &used_liquidities,
19731986
recommended_value_msat, our_node_pubkey);
19741987
for details in first_channels {
19751988
let first_hop_candidate = CandidateRouteHop::FirstHop { details };
@@ -2087,8 +2100,8 @@ where L::Target: Logger {
20872100
.chain(payment_path.hops.iter().map(|(hop, _)| &hop.node_id));
20882101
for (prev_hop, (hop, _)) in prev_hop_iter.zip(payment_path.hops.iter()) {
20892102
let spent_on_hop_msat = value_contribution_msat + hop.next_hops_fee_msat;
2090-
let used_liquidity_msat = used_channel_liquidities
2091-
.entry((hop.candidate.short_channel_id(), *prev_hop < hop.node_id))
2103+
let used_liquidity_msat = used_liquidities
2104+
.entry(hop.candidate.id(*prev_hop < hop.node_id))
20922105
.and_modify(|used_liquidity_msat| *used_liquidity_msat += spent_on_hop_msat)
20932106
.or_insert(spent_on_hop_msat);
20942107
let hop_capacity = hop.candidate.effective_capacity();
@@ -2107,8 +2120,8 @@ where L::Target: Logger {
21072120
let victim_scid = payment_path.hops[(payment_path.hops.len()) / 2].0.candidate.short_channel_id();
21082121
let exhausted = u64::max_value();
21092122
log_trace!(logger, "Disabling channel {} for future path building iterations to avoid duplicates.", victim_scid);
2110-
*used_channel_liquidities.entry((victim_scid, false)).or_default() = exhausted;
2111-
*used_channel_liquidities.entry((victim_scid, true)).or_default() = exhausted;
2123+
*used_liquidities.entry(CandidateHopId::Clear((victim_scid, false))).or_default() = exhausted;
2124+
*used_liquidities.entry(CandidateHopId::Clear((victim_scid, true))).or_default() = exhausted;
21122125
}
21132126

21142127
// Track the total amount all our collected paths allow to send so that we know

0 commit comments

Comments
 (0)