Skip to content

Commit 30d6932

Browse files
committed
Score in-flight amounts as amounts, not a capacity reduction
When we started considering the in-flight amounts when scoring, we took the approach of considering the in-flight amount as an effective reduction in the channel's total capacity. When we were scoring using a flat success probability PDF, that was fine, however in the next commit we'll move to a highly nonlinear one, which makes this a pretty confusing heuristic. Here, instead, we move to considering the in-flight amount as simply an extension of the amount we're trying to send over the channel, which is equivalent for the flat success probability PDF, but makes much more sense in a nonlinear world.
1 parent e2532fc commit 30d6932

File tree

1 file changed

+41
-51
lines changed

1 file changed

+41
-51
lines changed

lightning/src/routing/scoring.rs

Lines changed: 41 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -733,7 +733,6 @@ struct DirectedChannelLiquidity<L: Deref<Target = u64>, BRT: Deref<Target = Hist
733733
min_liquidity_offset_msat: L,
734734
max_liquidity_offset_msat: L,
735735
liquidity_history: HistoricalMinMaxBuckets<BRT>,
736-
inflight_htlc_msat: u64,
737736
capacity_msat: u64,
738737
last_updated: U,
739738
now: T,
@@ -771,7 +770,7 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> ProbabilisticScorerU
771770
let log_direction = |source, target| {
772771
if let Some((directed_info, _)) = chan_debug.as_directed_to(target) {
773772
let amt = directed_info.effective_capacity().as_msat();
774-
let dir_liq = liq.as_directed(source, target, 0, amt, self.decay_params);
773+
let dir_liq = liq.as_directed(source, target, amt, self.decay_params);
775774

776775
let (min_buckets, max_buckets) = dir_liq.liquidity_history
777776
.get_decayed_buckets(now, *dir_liq.last_updated,
@@ -825,7 +824,7 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> ProbabilisticScorerU
825824
if let Some(liq) = self.channel_liquidities.get(&scid) {
826825
if let Some((directed_info, source)) = chan.as_directed_to(target) {
827826
let amt = directed_info.effective_capacity().as_msat();
828-
let dir_liq = liq.as_directed(source, target, 0, amt, self.decay_params);
827+
let dir_liq = liq.as_directed(source, target, amt, self.decay_params);
829828
return Some((dir_liq.min_liquidity_msat(), dir_liq.max_liquidity_msat()));
830829
}
831830
}
@@ -867,7 +866,7 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> ProbabilisticScorerU
867866
if let Some(liq) = self.channel_liquidities.get(&scid) {
868867
if let Some((directed_info, source)) = chan.as_directed_to(target) {
869868
let amt = directed_info.effective_capacity().as_msat();
870-
let dir_liq = liq.as_directed(source, target, 0, amt, self.decay_params);
869+
let dir_liq = liq.as_directed(source, target, amt, self.decay_params);
871870

872871
let (min_buckets, mut max_buckets) =
873872
dir_liq.liquidity_history.get_decayed_buckets(
@@ -901,7 +900,7 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> ProbabilisticScorerU
901900
if let Some(liq) = self.channel_liquidities.get(&scid) {
902901
if let Some((directed_info, source)) = chan.as_directed_to(target) {
903902
let capacity_msat = directed_info.effective_capacity().as_msat();
904-
let dir_liq = liq.as_directed(source, target, 0, capacity_msat, self.decay_params);
903+
let dir_liq = liq.as_directed(source, target, capacity_msat, self.decay_params);
905904

906905
return dir_liq.liquidity_history.calculate_success_probability_times_billion(
907906
dir_liq.now, *dir_liq.last_updated,
@@ -930,7 +929,7 @@ impl<T: Time> ChannelLiquidity<T> {
930929
/// Returns a view of the channel liquidity directed from `source` to `target` assuming
931930
/// `capacity_msat`.
932931
fn as_directed(
933-
&self, source: &NodeId, target: &NodeId, inflight_htlc_msat: u64, capacity_msat: u64, decay_params: ProbabilisticScoringDecayParameters
932+
&self, source: &NodeId, target: &NodeId, capacity_msat: u64, decay_params: ProbabilisticScoringDecayParameters
934933
) -> DirectedChannelLiquidity<&u64, &HistoricalBucketRangeTracker, T, &T> {
935934
let (min_liquidity_offset_msat, max_liquidity_offset_msat, min_liquidity_offset_history, max_liquidity_offset_history) =
936935
if source < target {
@@ -948,7 +947,6 @@ impl<T: Time> ChannelLiquidity<T> {
948947
min_liquidity_offset_history,
949948
max_liquidity_offset_history,
950949
},
951-
inflight_htlc_msat,
952950
capacity_msat,
953951
last_updated: &self.last_updated,
954952
now: T::now(),
@@ -959,7 +957,7 @@ impl<T: Time> ChannelLiquidity<T> {
959957
/// Returns a mutable view of the channel liquidity directed from `source` to `target` assuming
960958
/// `capacity_msat`.
961959
fn as_directed_mut(
962-
&mut self, source: &NodeId, target: &NodeId, inflight_htlc_msat: u64, capacity_msat: u64, decay_params: ProbabilisticScoringDecayParameters
960+
&mut self, source: &NodeId, target: &NodeId, capacity_msat: u64, decay_params: ProbabilisticScoringDecayParameters
963961
) -> DirectedChannelLiquidity<&mut u64, &mut HistoricalBucketRangeTracker, T, &mut T> {
964962
let (min_liquidity_offset_msat, max_liquidity_offset_msat, min_liquidity_offset_history, max_liquidity_offset_history) =
965963
if source < target {
@@ -977,7 +975,6 @@ impl<T: Time> ChannelLiquidity<T> {
977975
min_liquidity_offset_history,
978976
max_liquidity_offset_history,
979977
},
980-
inflight_htlc_msat,
981978
capacity_msat,
982979
last_updated: &mut self.last_updated,
983980
now: T::now(),
@@ -1033,7 +1030,7 @@ impl<L: Deref<Target = u64>, BRT: Deref<Target = HistoricalBucketRangeTracker>,
10331030
/// Returns a liquidity penalty for routing the given HTLC `amount_msat` through the channel in
10341031
/// this direction.
10351032
fn penalty_msat(&self, amount_msat: u64, score_params: &ProbabilisticScoringFeeParameters) -> u64 {
1036-
let available_capacity = self.available_capacity();
1033+
let available_capacity = self.capacity_msat;
10371034
let max_liquidity_msat = self.max_liquidity_msat();
10381035
let min_liquidity_msat = core::cmp::min(self.min_liquidity_msat(), max_liquidity_msat);
10391036

@@ -1129,16 +1126,10 @@ impl<L: Deref<Target = u64>, BRT: Deref<Target = HistoricalBucketRangeTracker>,
11291126
/// Returns the upper bound of the channel liquidity balance in this direction.
11301127
#[inline(always)]
11311128
fn max_liquidity_msat(&self) -> u64 {
1132-
self.available_capacity()
1129+
self.capacity_msat
11331130
.saturating_sub(self.decayed_offset_msat(*self.max_liquidity_offset_msat))
11341131
}
11351132

1136-
/// Returns the capacity minus the in-flight HTLCs in this direction.
1137-
#[inline(always)]
1138-
fn available_capacity(&self) -> u64 {
1139-
self.capacity_msat.saturating_sub(self.inflight_htlc_msat)
1140-
}
1141-
11421133
fn decayed_offset_msat(&self, offset_msat: u64) -> u64 {
11431134
let half_life = self.decay_params.liquidity_offset_half_life.as_secs();
11441135
if half_life != 0 {
@@ -1273,13 +1264,12 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> ScoreLookUp for Prob
12731264
_ => {},
12741265
}
12751266

1276-
let amount_msat = usage.amount_msat;
1267+
let amount_msat = usage.amount_msat.saturating_add(usage.inflight_htlc_msat);
12771268
let capacity_msat = usage.effective_capacity.as_msat();
1278-
let inflight_htlc_msat = usage.inflight_htlc_msat;
12791269
self.channel_liquidities
12801270
.get(&short_channel_id)
12811271
.unwrap_or(&ChannelLiquidity::new())
1282-
.as_directed(source, target, inflight_htlc_msat, capacity_msat, self.decay_params)
1272+
.as_directed(source, target, capacity_msat, self.decay_params)
12831273
.penalty_msat(amount_msat, score_params)
12841274
.saturating_add(anti_probing_penalty_msat)
12851275
.saturating_add(base_penalty_msat)
@@ -1309,13 +1299,13 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> ScoreUpdate for Prob
13091299
self.channel_liquidities
13101300
.entry(hop.short_channel_id)
13111301
.or_insert_with(ChannelLiquidity::new)
1312-
.as_directed_mut(source, &target, 0, capacity_msat, self.decay_params)
1302+
.as_directed_mut(source, &target, capacity_msat, self.decay_params)
13131303
.failed_at_channel(amount_msat, format_args!("SCID {}, towards {:?}", hop.short_channel_id, target), &self.logger);
13141304
} else {
13151305
self.channel_liquidities
13161306
.entry(hop.short_channel_id)
13171307
.or_insert_with(ChannelLiquidity::new)
1318-
.as_directed_mut(source, &target, 0, capacity_msat, self.decay_params)
1308+
.as_directed_mut(source, &target, capacity_msat, self.decay_params)
13191309
.failed_downstream(amount_msat, format_args!("SCID {}, towards {:?}", hop.short_channel_id, target), &self.logger);
13201310
}
13211311
} else {
@@ -1343,7 +1333,7 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> ScoreUpdate for Prob
13431333
self.channel_liquidities
13441334
.entry(hop.short_channel_id)
13451335
.or_insert_with(ChannelLiquidity::new)
1346-
.as_directed_mut(source, &target, 0, capacity_msat, self.decay_params)
1336+
.as_directed_mut(source, &target, capacity_msat, self.decay_params)
13471337
.successful(amount_msat, format_args!("SCID {}, towards {:?}", hop.short_channel_id, target), &self.logger);
13481338
} else {
13491339
log_debug!(self.logger, "Not able to learn for channel with SCID {} as we do not have graph info for it (likely a route-hint last-hop).",
@@ -2259,52 +2249,52 @@ mod tests {
22592249
// Update minimum liquidity.
22602250

22612251
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
2262-
.as_directed(&source, &target, 0, 1_000, decay_params);
2252+
.as_directed(&source, &target, 1_000, decay_params);
22632253
assert_eq!(liquidity.min_liquidity_msat(), 100);
22642254
assert_eq!(liquidity.max_liquidity_msat(), 300);
22652255

22662256
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
2267-
.as_directed(&target, &source, 0, 1_000, decay_params);
2257+
.as_directed(&target, &source, 1_000, decay_params);
22682258
assert_eq!(liquidity.min_liquidity_msat(), 700);
22692259
assert_eq!(liquidity.max_liquidity_msat(), 900);
22702260

22712261
scorer.channel_liquidities.get_mut(&42).unwrap()
2272-
.as_directed_mut(&source, &target, 0, 1_000, decay_params)
2262+
.as_directed_mut(&source, &target, 1_000, decay_params)
22732263
.set_min_liquidity_msat(200);
22742264

22752265
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
2276-
.as_directed(&source, &target, 0, 1_000, decay_params);
2266+
.as_directed(&source, &target, 1_000, decay_params);
22772267
assert_eq!(liquidity.min_liquidity_msat(), 200);
22782268
assert_eq!(liquidity.max_liquidity_msat(), 300);
22792269

22802270
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
2281-
.as_directed(&target, &source, 0, 1_000, decay_params);
2271+
.as_directed(&target, &source, 1_000, decay_params);
22822272
assert_eq!(liquidity.min_liquidity_msat(), 700);
22832273
assert_eq!(liquidity.max_liquidity_msat(), 800);
22842274

22852275
// Update maximum liquidity.
22862276

22872277
let liquidity = scorer.channel_liquidities.get(&43).unwrap()
2288-
.as_directed(&target, &recipient, 0, 1_000, decay_params);
2278+
.as_directed(&target, &recipient, 1_000, decay_params);
22892279
assert_eq!(liquidity.min_liquidity_msat(), 700);
22902280
assert_eq!(liquidity.max_liquidity_msat(), 900);
22912281

22922282
let liquidity = scorer.channel_liquidities.get(&43).unwrap()
2293-
.as_directed(&recipient, &target, 0, 1_000, decay_params);
2283+
.as_directed(&recipient, &target, 1_000, decay_params);
22942284
assert_eq!(liquidity.min_liquidity_msat(), 100);
22952285
assert_eq!(liquidity.max_liquidity_msat(), 300);
22962286

22972287
scorer.channel_liquidities.get_mut(&43).unwrap()
2298-
.as_directed_mut(&target, &recipient, 0, 1_000, decay_params)
2288+
.as_directed_mut(&target, &recipient, 1_000, decay_params)
22992289
.set_max_liquidity_msat(200);
23002290

23012291
let liquidity = scorer.channel_liquidities.get(&43).unwrap()
2302-
.as_directed(&target, &recipient, 0, 1_000, decay_params);
2292+
.as_directed(&target, &recipient, 1_000, decay_params);
23032293
assert_eq!(liquidity.min_liquidity_msat(), 0);
23042294
assert_eq!(liquidity.max_liquidity_msat(), 200);
23052295

23062296
let liquidity = scorer.channel_liquidities.get(&43).unwrap()
2307-
.as_directed(&recipient, &target, 0, 1_000, decay_params);
2297+
.as_directed(&recipient, &target, 1_000, decay_params);
23082298
assert_eq!(liquidity.min_liquidity_msat(), 800);
23092299
assert_eq!(liquidity.max_liquidity_msat(), 1000);
23102300
}
@@ -2328,42 +2318,42 @@ mod tests {
23282318

23292319
// Check initial bounds.
23302320
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
2331-
.as_directed(&source, &target, 0, 1_000, decay_params);
2321+
.as_directed(&source, &target, 1_000, decay_params);
23322322
assert_eq!(liquidity.min_liquidity_msat(), 400);
23332323
assert_eq!(liquidity.max_liquidity_msat(), 800);
23342324

23352325
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
2336-
.as_directed(&target, &source, 0, 1_000, decay_params);
2326+
.as_directed(&target, &source, 1_000, decay_params);
23372327
assert_eq!(liquidity.min_liquidity_msat(), 200);
23382328
assert_eq!(liquidity.max_liquidity_msat(), 600);
23392329

23402330
// Reset from source to target.
23412331
scorer.channel_liquidities.get_mut(&42).unwrap()
2342-
.as_directed_mut(&source, &target, 0, 1_000, decay_params)
2332+
.as_directed_mut(&source, &target, 1_000, decay_params)
23432333
.set_min_liquidity_msat(900);
23442334

23452335
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
2346-
.as_directed(&source, &target, 0, 1_000, decay_params);
2336+
.as_directed(&source, &target, 1_000, decay_params);
23472337
assert_eq!(liquidity.min_liquidity_msat(), 900);
23482338
assert_eq!(liquidity.max_liquidity_msat(), 1_000);
23492339

23502340
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
2351-
.as_directed(&target, &source, 0, 1_000, decay_params);
2341+
.as_directed(&target, &source, 1_000, decay_params);
23522342
assert_eq!(liquidity.min_liquidity_msat(), 0);
23532343
assert_eq!(liquidity.max_liquidity_msat(), 100);
23542344

23552345
// Reset from target to source.
23562346
scorer.channel_liquidities.get_mut(&42).unwrap()
2357-
.as_directed_mut(&target, &source, 0, 1_000, decay_params)
2347+
.as_directed_mut(&target, &source, 1_000, decay_params)
23582348
.set_min_liquidity_msat(400);
23592349

23602350
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
2361-
.as_directed(&source, &target, 0, 1_000, decay_params);
2351+
.as_directed(&source, &target, 1_000, decay_params);
23622352
assert_eq!(liquidity.min_liquidity_msat(), 0);
23632353
assert_eq!(liquidity.max_liquidity_msat(), 600);
23642354

23652355
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
2366-
.as_directed(&target, &source, 0, 1_000, decay_params);
2356+
.as_directed(&target, &source, 1_000, decay_params);
23672357
assert_eq!(liquidity.min_liquidity_msat(), 400);
23682358
assert_eq!(liquidity.max_liquidity_msat(), 1_000);
23692359
}
@@ -2387,42 +2377,42 @@ mod tests {
23872377

23882378
// Check initial bounds.
23892379
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
2390-
.as_directed(&source, &target, 0, 1_000, decay_params);
2380+
.as_directed(&source, &target, 1_000, decay_params);
23912381
assert_eq!(liquidity.min_liquidity_msat(), 400);
23922382
assert_eq!(liquidity.max_liquidity_msat(), 800);
23932383

23942384
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
2395-
.as_directed(&target, &source, 0, 1_000, decay_params);
2385+
.as_directed(&target, &source, 1_000, decay_params);
23962386
assert_eq!(liquidity.min_liquidity_msat(), 200);
23972387
assert_eq!(liquidity.max_liquidity_msat(), 600);
23982388

23992389
// Reset from source to target.
24002390
scorer.channel_liquidities.get_mut(&42).unwrap()
2401-
.as_directed_mut(&source, &target, 0, 1_000, decay_params)
2391+
.as_directed_mut(&source, &target, 1_000, decay_params)
24022392
.set_max_liquidity_msat(300);
24032393

24042394
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
2405-
.as_directed(&source, &target, 0, 1_000, decay_params);
2395+
.as_directed(&source, &target, 1_000, decay_params);
24062396
assert_eq!(liquidity.min_liquidity_msat(), 0);
24072397
assert_eq!(liquidity.max_liquidity_msat(), 300);
24082398

24092399
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
2410-
.as_directed(&target, &source, 0, 1_000, decay_params);
2400+
.as_directed(&target, &source, 1_000, decay_params);
24112401
assert_eq!(liquidity.min_liquidity_msat(), 700);
24122402
assert_eq!(liquidity.max_liquidity_msat(), 1_000);
24132403

24142404
// Reset from target to source.
24152405
scorer.channel_liquidities.get_mut(&42).unwrap()
2416-
.as_directed_mut(&target, &source, 0, 1_000, decay_params)
2406+
.as_directed_mut(&target, &source, 1_000, decay_params)
24172407
.set_max_liquidity_msat(600);
24182408

24192409
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
2420-
.as_directed(&source, &target, 0, 1_000, decay_params);
2410+
.as_directed(&source, &target, 1_000, decay_params);
24212411
assert_eq!(liquidity.min_liquidity_msat(), 400);
24222412
assert_eq!(liquidity.max_liquidity_msat(), 1_000);
24232413

24242414
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
2425-
.as_directed(&target, &source, 0, 1_000, decay_params);
2415+
.as_directed(&target, &source, 1_000, decay_params);
24262416
assert_eq!(liquidity.min_liquidity_msat(), 0);
24272417
assert_eq!(liquidity.max_liquidity_msat(), 600);
24282418
}
@@ -3230,7 +3220,7 @@ mod tests {
32303220
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024, htlc_maximum_msat: 1_024 },
32313221
};
32323222
scorer.payment_path_failed(&payment_path_for_amount(1), 42);
3233-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 2048);
3223+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 2050);
32343224
usage.inflight_htlc_msat = 0;
32353225
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 866);
32363226

@@ -3344,7 +3334,7 @@ mod tests {
33443334
scorer.payment_path_failed(&path, 43);
33453335

33463336
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
3347-
.as_directed(&source, &target, 0, 1_000, decay_params);
3337+
.as_directed(&source, &target, 1_000, decay_params);
33483338
assert_eq!(liquidity.min_liquidity_msat(), 256);
33493339
assert_eq!(liquidity.max_liquidity_msat(), 768);
33503340
}

0 commit comments

Comments
 (0)