Skip to content

Commit 16a5e9e

Browse files
Routing: accommodate for blinded paths in used liquidity tracking
1 parent a9e64be commit 16a5e9e

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

10091020
#[inline]
@@ -1247,7 +1258,7 @@ impl fmt::Display for LoggedPayeePubkey {
12471258

12481259
#[inline]
12491260
fn sort_first_hop_channels(
1250-
channels: &mut Vec<&ChannelDetails>, used_channel_liquidities: &HashMap<(u64, bool), u64>,
1261+
channels: &mut Vec<&ChannelDetails>, used_liquidities: &HashMap<CandidateHopId, u64>,
12511262
recommended_value_msat: u64, our_node_pubkey: &PublicKey
12521263
) {
12531264
// Sort the first_hops channels to the same node(s) in priority order of which channel we'd
@@ -1265,11 +1276,11 @@ fn sort_first_hop_channels(
12651276
// Available outbound balances factor in liquidity already reserved for previously found paths.
12661277
channels.sort_unstable_by(|chan_a, chan_b| {
12671278
let chan_a_outbound_limit_msat = chan_a.next_outbound_htlc_limit_msat
1268-
.saturating_sub(*used_channel_liquidities.get(&(chan_a.get_outbound_payment_scid().unwrap(),
1269-
our_node_pubkey < &chan_a.counterparty.node_id)).unwrap_or(&0));
1279+
.saturating_sub(*used_liquidities.get(&CandidateHopId::Clear((chan_a.get_outbound_payment_scid().unwrap(),
1280+
our_node_pubkey < &chan_a.counterparty.node_id))).unwrap_or(&0));
12701281
let chan_b_outbound_limit_msat = chan_b.next_outbound_htlc_limit_msat
1271-
.saturating_sub(*used_channel_liquidities.get(&(chan_b.get_outbound_payment_scid().unwrap(),
1272-
our_node_pubkey < &chan_b.counterparty.node_id)).unwrap_or(&0));
1282+
.saturating_sub(*used_liquidities.get(&CandidateHopId::Clear((chan_b.get_outbound_payment_scid().unwrap(),
1283+
our_node_pubkey < &chan_b.counterparty.node_id))).unwrap_or(&0));
12731284
if chan_b_outbound_limit_msat < recommended_value_msat || chan_a_outbound_limit_msat < recommended_value_msat {
12741285
// Sort in descending order
12751286
chan_b_outbound_limit_msat.cmp(&chan_a_outbound_limit_msat)
@@ -1513,19 +1524,20 @@ where L::Target: Logger {
15131524
// drop the requirement by setting this to 0.
15141525
let mut channel_saturation_pow_half = payment_params.max_channel_saturation_power_of_half;
15151526

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

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

15271539
for (_, channels) in first_hop_targets.iter_mut() {
1528-
sort_first_hop_channels(channels, &used_channel_liquidities, recommended_value_msat,
1540+
sort_first_hop_channels(channels, &used_liquidities, recommended_value_msat,
15291541
our_node_pubkey);
15301542
}
15311543

@@ -1560,8 +1572,8 @@ where L::Target: Logger {
15601572
// if the amount being transferred over this path is lower.
15611573
// We do this for now, but this is a subject for removal.
15621574
if let Some(mut available_value_contribution_msat) = htlc_maximum_msat.checked_sub($next_hops_fee_msat) {
1563-
let used_liquidity_msat = used_channel_liquidities
1564-
.get(&(short_channel_id, $src_node_id < $dest_node_id))
1575+
let used_liquidity_msat = used_liquidities
1576+
.get(&$candidate.id($src_node_id < $dest_node_id))
15651577
.map_or(0, |used_liquidity_msat| {
15661578
available_value_contribution_msat = available_value_contribution_msat
15671579
.saturating_sub(*used_liquidity_msat);
@@ -1832,7 +1844,7 @@ where L::Target: Logger {
18321844

18331845
// TODO: diversify by nodes (so that all paths aren't doomed if one node is offline).
18341846
'paths_collection: loop {
1835-
// For every new path, start from scratch, except for used_channel_liquidities, which
1847+
// For every new path, start from scratch, except for used_liquidities, which
18361848
// helps to avoid reusing previously selected paths in future iterations.
18371849
targets.clear();
18381850
dist.clear();
@@ -1918,8 +1930,9 @@ where L::Target: Logger {
19181930
hop_used = false;
19191931
}
19201932

1921-
let used_liquidity_msat = used_channel_liquidities
1922-
.get(&(hop.short_channel_id, source < target)).copied().unwrap_or(0);
1933+
let used_liquidity_msat = used_liquidities
1934+
.get(&candidate.id(source < target)).copied()
1935+
.unwrap_or(0);
19231936
let channel_usage = ChannelUsage {
19241937
amount_msat: final_value_msat + aggregate_next_hops_fee_msat,
19251938
inflight_htlc_msat: used_liquidity_msat,
@@ -1939,7 +1952,7 @@ where L::Target: Logger {
19391952

19401953
// Searching for a direct channel between last checked hop and first_hop_targets
19411954
if let Some(first_channels) = first_hop_targets.get_mut(&NodeId::from_pubkey(&prev_hop_id)) {
1942-
sort_first_hop_channels(first_channels, &used_channel_liquidities,
1955+
sort_first_hop_channels(first_channels, &used_liquidities,
19431956
recommended_value_msat, our_node_pubkey);
19441957
for details in first_channels {
19451958
let first_hop_candidate = CandidateRouteHop::FirstHop { details };
@@ -1980,7 +1993,7 @@ where L::Target: Logger {
19801993
// always assumes that the third argument is a node to which we have a
19811994
// path.
19821995
if let Some(first_channels) = first_hop_targets.get_mut(&NodeId::from_pubkey(&hop.src_node_id)) {
1983-
sort_first_hop_channels(first_channels, &used_channel_liquidities,
1996+
sort_first_hop_channels(first_channels, &used_liquidities,
19841997
recommended_value_msat, our_node_pubkey);
19851998
for details in first_channels {
19861999
let first_hop_candidate = CandidateRouteHop::FirstHop { details };
@@ -2098,8 +2111,8 @@ where L::Target: Logger {
20982111
.chain(payment_path.hops.iter().map(|(hop, _)| &hop.node_id));
20992112
for (prev_hop, (hop, _)) in prev_hop_iter.zip(payment_path.hops.iter()) {
21002113
let spent_on_hop_msat = value_contribution_msat + hop.next_hops_fee_msat;
2101-
let used_liquidity_msat = used_channel_liquidities
2102-
.entry((hop.candidate.short_channel_id(), *prev_hop < hop.node_id))
2114+
let used_liquidity_msat = used_liquidities
2115+
.entry(hop.candidate.id(*prev_hop < hop.node_id))
21032116
.and_modify(|used_liquidity_msat| *used_liquidity_msat += spent_on_hop_msat)
21042117
.or_insert(spent_on_hop_msat);
21052118
let hop_capacity = hop.candidate.effective_capacity();
@@ -2118,8 +2131,8 @@ where L::Target: Logger {
21182131
let victim_scid = payment_path.hops[(payment_path.hops.len()) / 2].0.candidate.short_channel_id();
21192132
let exhausted = u64::max_value();
21202133
log_trace!(logger, "Disabling channel {} for future path building iterations to avoid duplicates.", victim_scid);
2121-
*used_channel_liquidities.entry((victim_scid, false)).or_default() = exhausted;
2122-
*used_channel_liquidities.entry((victim_scid, true)).or_default() = exhausted;
2134+
*used_liquidities.entry(CandidateHopId::Clear((victim_scid, false))).or_default() = exhausted;
2135+
*used_liquidities.entry(CandidateHopId::Clear((victim_scid, true))).or_default() = exhausted;
21232136
}
21242137

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

0 commit comments

Comments
 (0)