Skip to content

Commit be59d01

Browse files
Routing: accommodate for blinded paths in used liquidity tracking
1 parent a291881 commit be59d01

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
@@ -1001,6 +1001,17 @@ impl<'a> CandidateRouteHop<'a> {
10011001
EffectiveCapacity::Infinite,
10021002
}
10031003
}
1004+
fn id(&self, channel_direction: bool /* src_node_id < target_node_id */) -> CandidateHopId {
1005+
CandidateHopId::Clear((self.short_channel_id(), channel_direction))
1006+
}
1007+
}
1008+
1009+
#[derive(Eq, Hash, PartialEq)]
1010+
enum CandidateHopId {
1011+
/// Contains (scid, src_node_id < target_node_id)
1012+
Clear((u64, bool)),
1013+
/// Index of the blinded route hint in [`Payee::Blinded::route_hints`].
1014+
Blinded(usize),
10041015
}
10051016

10061017
#[inline]
@@ -1244,7 +1255,7 @@ impl fmt::Display for LoggedPayeePubkey {
12441255

12451256
#[inline]
12461257
fn sort_first_hop_channels(
1247-
channels: &mut Vec<&ChannelDetails>, used_channel_liquidities: &HashMap<(u64, bool), u64>,
1258+
channels: &mut Vec<&ChannelDetails>, used_liquidities: &HashMap<CandidateHopId, u64>,
12481259
recommended_value_msat: u64, our_node_pubkey: &PublicKey
12491260
) {
12501261
// Sort the first_hops channels to the same node(s) in priority order of which channel we'd
@@ -1262,11 +1273,11 @@ fn sort_first_hop_channels(
12621273
// Available outbound balances factor in liquidity already reserved for previously found paths.
12631274
channels.sort_unstable_by(|chan_a, chan_b| {
12641275
let chan_a_outbound_limit_msat = chan_a.next_outbound_htlc_limit_msat
1265-
.saturating_sub(*used_channel_liquidities.get(&(chan_a.get_outbound_payment_scid().unwrap(),
1266-
our_node_pubkey < &chan_a.counterparty.node_id)).unwrap_or(&0));
1276+
.saturating_sub(*used_liquidities.get(&CandidateHopId::Clear((chan_a.get_outbound_payment_scid().unwrap(),
1277+
our_node_pubkey < &chan_a.counterparty.node_id))).unwrap_or(&0));
12671278
let chan_b_outbound_limit_msat = chan_b.next_outbound_htlc_limit_msat
1268-
.saturating_sub(*used_channel_liquidities.get(&(chan_b.get_outbound_payment_scid().unwrap(),
1269-
our_node_pubkey < &chan_b.counterparty.node_id)).unwrap_or(&0));
1279+
.saturating_sub(*used_liquidities.get(&CandidateHopId::Clear((chan_b.get_outbound_payment_scid().unwrap(),
1280+
our_node_pubkey < &chan_b.counterparty.node_id))).unwrap_or(&0));
12701281
if chan_b_outbound_limit_msat < recommended_value_msat || chan_a_outbound_limit_msat < recommended_value_msat {
12711282
// Sort in descending order
12721283
chan_b_outbound_limit_msat.cmp(&chan_a_outbound_limit_msat)
@@ -1510,19 +1521,20 @@ where L::Target: Logger {
15101521
// drop the requirement by setting this to 0.
15111522
let mut channel_saturation_pow_half = payment_params.max_channel_saturation_power_of_half;
15121523

1513-
// Keep track of how much liquidity has been used in selected channels. Used to determine
1514-
// if the channel can be used by additional MPP paths or to inform path finding decisions. It is
1515-
// aware of direction *only* to ensure that the correct htlc_maximum_msat value is used. Hence,
1516-
// liquidity used in one direction will not offset any used in the opposite direction.
1517-
let mut used_channel_liquidities: HashMap<(u64, bool), u64> =
1524+
// Keep track of how much liquidity has been used in selected channels or blinded paths. Used to
1525+
// determine if the channel can be used by additional MPP paths or to inform path finding
1526+
// decisions. It is aware of direction *only* to ensure that the correct htlc_maximum_msat value
1527+
// is used. Hence, liquidity used in one direction will not offset any used in the opposite
1528+
// direction.
1529+
let mut used_liquidities: HashMap<CandidateHopId, u64> =
15181530
HashMap::with_capacity(network_nodes.len());
15191531

15201532
// Keeping track of how much value we already collected across other paths. Helps to decide
15211533
// when we want to stop looking for new paths.
15221534
let mut already_collected_value_msat = 0;
15231535

15241536
for (_, channels) in first_hop_targets.iter_mut() {
1525-
sort_first_hop_channels(channels, &used_channel_liquidities, recommended_value_msat,
1537+
sort_first_hop_channels(channels, &used_liquidities, recommended_value_msat,
15261538
our_node_pubkey);
15271539
}
15281540

@@ -1557,8 +1569,8 @@ where L::Target: Logger {
15571569
// if the amount being transferred over this path is lower.
15581570
// We do this for now, but this is a subject for removal.
15591571
if let Some(mut available_value_contribution_msat) = htlc_maximum_msat.checked_sub($next_hops_fee_msat) {
1560-
let used_liquidity_msat = used_channel_liquidities
1561-
.get(&(short_channel_id, $src_node_id < $dest_node_id))
1572+
let used_liquidity_msat = used_liquidities
1573+
.get(&$candidate.id($src_node_id < $dest_node_id))
15621574
.map_or(0, |used_liquidity_msat| {
15631575
available_value_contribution_msat = available_value_contribution_msat
15641576
.saturating_sub(*used_liquidity_msat);
@@ -1829,7 +1841,7 @@ where L::Target: Logger {
18291841

18301842
// TODO: diversify by nodes (so that all paths aren't doomed if one node is offline).
18311843
'paths_collection: loop {
1832-
// For every new path, start from scratch, except for used_channel_liquidities, which
1844+
// For every new path, start from scratch, except for used_liquidities, which
18331845
// helps to avoid reusing previously selected paths in future iterations.
18341846
targets.clear();
18351847
dist.clear();
@@ -1915,8 +1927,9 @@ where L::Target: Logger {
19151927
hop_used = false;
19161928
}
19171929

1918-
let used_liquidity_msat = used_channel_liquidities
1919-
.get(&(hop.short_channel_id, source < target)).copied().unwrap_or(0);
1930+
let used_liquidity_msat = used_liquidities
1931+
.get(&candidate.id(source < target)).copied()
1932+
.unwrap_or(0);
19201933
let channel_usage = ChannelUsage {
19211934
amount_msat: final_value_msat + aggregate_next_hops_fee_msat,
19221935
inflight_htlc_msat: used_liquidity_msat,
@@ -1936,7 +1949,7 @@ where L::Target: Logger {
19361949

19371950
// Searching for a direct channel between last checked hop and first_hop_targets
19381951
if let Some(first_channels) = first_hop_targets.get_mut(&NodeId::from_pubkey(&prev_hop_id)) {
1939-
sort_first_hop_channels(first_channels, &used_channel_liquidities,
1952+
sort_first_hop_channels(first_channels, &used_liquidities,
19401953
recommended_value_msat, our_node_pubkey);
19411954
for details in first_channels {
19421955
let first_hop_candidate = CandidateRouteHop::FirstHop { details };
@@ -1977,7 +1990,7 @@ where L::Target: Logger {
19771990
// always assumes that the third argument is a node to which we have a
19781991
// path.
19791992
if let Some(first_channels) = first_hop_targets.get_mut(&NodeId::from_pubkey(&hop.src_node_id)) {
1980-
sort_first_hop_channels(first_channels, &used_channel_liquidities,
1993+
sort_first_hop_channels(first_channels, &used_liquidities,
19811994
recommended_value_msat, our_node_pubkey);
19821995
for details in first_channels {
19831996
let first_hop_candidate = CandidateRouteHop::FirstHop { details };
@@ -2095,8 +2108,8 @@ where L::Target: Logger {
20952108
.chain(payment_path.hops.iter().map(|(hop, _)| &hop.node_id));
20962109
for (prev_hop, (hop, _)) in prev_hop_iter.zip(payment_path.hops.iter()) {
20972110
let spent_on_hop_msat = value_contribution_msat + hop.next_hops_fee_msat;
2098-
let used_liquidity_msat = used_channel_liquidities
2099-
.entry((hop.candidate.short_channel_id(), *prev_hop < hop.node_id))
2111+
let used_liquidity_msat = used_liquidities
2112+
.entry(hop.candidate.id(*prev_hop < hop.node_id))
21002113
.and_modify(|used_liquidity_msat| *used_liquidity_msat += spent_on_hop_msat)
21012114
.or_insert(spent_on_hop_msat);
21022115
let hop_capacity = hop.candidate.effective_capacity();
@@ -2115,8 +2128,8 @@ where L::Target: Logger {
21152128
let victim_scid = payment_path.hops[(payment_path.hops.len()) / 2].0.candidate.short_channel_id();
21162129
let exhausted = u64::max_value();
21172130
log_trace!(logger, "Disabling channel {} for future path building iterations to avoid duplicates.", victim_scid);
2118-
*used_channel_liquidities.entry((victim_scid, false)).or_default() = exhausted;
2119-
*used_channel_liquidities.entry((victim_scid, true)).or_default() = exhausted;
2131+
*used_liquidities.entry(CandidateHopId::Clear((victim_scid, false))).or_default() = exhausted;
2132+
*used_liquidities.entry(CandidateHopId::Clear((victim_scid, true))).or_default() = exhausted;
21202133
}
21212134

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

0 commit comments

Comments
 (0)