routing: limit capacity factor and tune parameters

* The maximal reduction in the probability is limited to 0.5 (previously
  ~0.05), such that we don't get too low apriori probabilities.
  Otherwise, this may lead to a too strong selection of large (and maybe
  expensive) channels. A two-hop path would get total probability
  penalties of:

  - 1000PPM/(0.6*0.6) = 2778 PPM in the unsaturated case
  - 1000PPM/(0.6*(0.6*0.5)) = 5556 PPM in the saturated case, where the
    second hop is saturated

  The difference in PPM of 2778 PPM should be enough to bias towards the
  first path.

* The smearing factor is reduced. Previously we had to keep a higher
  smearing factor in order to make the capacity factor not go to zero
  for high amounts, to still give a fully saturated channel a chance.
  This is not needed anymore due to the capping to 0.5. A lower value of
  the smearing factor lets us more precisely choose a capacity fraction
  and the capacity factor is more neutral when it comes to intermediate
  amounts.

We set a conservative default value for the capacity fraction, which
still has the effect of discarding exhausted channels, giving a
noticeable effect when about 90% of the capacity is being used.
This commit is contained in:
bitromortac committed 2023-02-24 15:28:55 +01:00
1 parent a73581610e
commit 75a9dc9103
2 files changed
+59 -36

No files matched your search

+32 -9
View File
@@ -28,11 +28,12 @@ const (
// testCapacity is used to define a capacity for some channels.
testCapacity = btcutil.Amount(100_000)
testAmount = lnwire.MilliSatoshi(50_000_000)
testCapacityFraction = 0.75
testAmount = lnwire.MilliSatoshi(90_000_000)
testCapacityFraction = 0.9999
// Defines the capacityFactor for testAmount and testCapacity.
capFactor = 0.9241
// capFactor is the capacityFactor for testAmount, testCapacity and
// testCapacityFraction.
capFactor = 0.9909715
)
type estimatorTestContext struct {
@@ -244,13 +245,13 @@ func TestCapacityCutoff(t *testing.T) {
name: "low amount",
capacityFraction: 0.75,
amountMsat: capacityMSat / 10,
expectedFactor: 0.998,
expectedFactor: 1,
},
{
name: "half amount",
capacityFraction: 0.75,
amountMsat: capacityMSat / 2,
expectedFactor: 0.924,
expectedFactor: 1,
},
{
name: "cutoff amount",
@@ -258,13 +259,13 @@ func TestCapacityCutoff(t *testing.T) {
amountMsat: int(
0.75 * float64(capacityMSat),
),
expectedFactor: 0.5,
expectedFactor: 0.75,
},
{
name: "high amount",
capacityFraction: 0.75,
amountMsat: capacityMSat * 80 / 100,
expectedFactor: 0.377,
expectedFactor: 0.560,
},
{
// Even when we spend the full capacity, we still want
@@ -274,7 +275,7 @@ func TestCapacityCutoff(t *testing.T) {
name: "full amount",
capacityFraction: 0.75,
amountMsat: capacityMSat,
expectedFactor: 0.076,
expectedFactor: 0.5,
},
{
name: "more than capacity",
@@ -282,6 +283,28 @@ func TestCapacityCutoff(t *testing.T) {
amountMsat: capacityMSat + 1,
expectedFactor: 0.0,
},
// Default CapacityFactor of 0.9999.
{
name: "zero amount",
capacityFraction: 0.9999,
amountMsat: 0,
expectedFactor: 1.00,
},
{
name: "90% of the channel capacity",
capacityFraction: 0.9999,
amountMsat: capacityMSat * 90 / 100,
expectedFactor: 0.990,
},
{
// We won't saturate at 0.5 as in the other case but at
// a higher value of 0.75 due to the smearing, this
// translates to a penalty increase of a factor of 1.33.
name: "full amount",
capacityFraction: 0.9999,
amountMsat: capacityMSat,
expectedFactor: 0.75,
},
// Inactive capacity factor.
{
name: "inactive capacity factor",