mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-01-18 21:35:24 +01:00
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:
parent
a73581610e
commit
75a9dc9103
@ -16,31 +16,24 @@ const (
|
||||
// capacity-related probability reweighting works. CapacityFraction
|
||||
// defines the fraction of the channel capacity at which the effect
|
||||
// roughly sets in and capacitySmearingFraction defines over which range
|
||||
// the factor changes from 1 to 0.
|
||||
//
|
||||
// We may fall below the minimum required probability
|
||||
// (DefaultMinRouteProbability) when the amount comes close to the
|
||||
// available capacity of a single channel of the route in case of no
|
||||
// prior knowledge about the channels. We want such routes still to be
|
||||
// available and therefore a probability reduction should not completely
|
||||
// drop the total probability below DefaultMinRouteProbability.
|
||||
// For this to hold for a three-hop route we require:
|
||||
// (DefaultAprioriHopProbability)^3 * minCapacityFactor >
|
||||
// DefaultMinRouteProbability
|
||||
//
|
||||
// For DefaultAprioriHopProbability = 0.6 and
|
||||
// DefaultMinRouteProbability = 0.01 this results in
|
||||
// minCapacityFactor ~ 0.05. The following combination of parameters
|
||||
// fulfill the requirement with capacityFactor(cap, cap) ~ 0.076 (see
|
||||
// tests).
|
||||
// the factor changes from 1 to minCapacityFactor.
|
||||
|
||||
// DefaultCapacityFraction is the default value for CapacityFraction.
|
||||
DefaultCapacityFraction = 0.75
|
||||
// It is chosen such that the capacity factor is active but with a small
|
||||
// effect. This value together with capacitySmearingFraction leads to a
|
||||
// noticeable reduction in probability if the amount starts to come
|
||||
// close to 90% of a channel's capacity.
|
||||
DefaultCapacityFraction = 0.9999
|
||||
|
||||
// We don't want to have a sharp drop of the capacity factor to zero at
|
||||
// capacityCutoffFraction, but a smooth smearing such that some residual
|
||||
// probability is left when spending the whole amount, see above.
|
||||
capacitySmearingFraction = 0.1
|
||||
// capacitySmearingFraction defines how quickly the capacity factor
|
||||
// drops from 1 to minCapacityFactor. This value results in about a
|
||||
// variation over 20% of the capacity.
|
||||
capacitySmearingFraction = 0.025
|
||||
|
||||
// minCapacityFactor is the minimal value the capacityFactor can take.
|
||||
// Having a too low value can lead to discarding of paths due to the
|
||||
// enforced minimal proability or to too high pathfinding weights.
|
||||
minCapacityFactor = 0.5
|
||||
|
||||
// minCapacityFraction is the minimum allowed value for
|
||||
// CapacityFraction. The success probability in the random balance model
|
||||
@ -265,10 +258,13 @@ func (p *AprioriEstimator) getWeight(age time.Duration) float64 {
|
||||
}
|
||||
|
||||
// capacityFactor is a multiplier that can be used to reduce the probability
|
||||
// depending on how much of the capacity is sent. The limits are 1 for amt == 0
|
||||
// and 0 for amt >> cutoffMsat. The function drops significantly when amt
|
||||
// reaches cutoffMsat. smearingMsat determines over which scale the reduction
|
||||
// takes place.
|
||||
// depending on how much of the capacity is sent. In other words, the factor
|
||||
// sorts out channels that don't provide enough liquidity. Effectively, this
|
||||
// leads to usage of larger channels in total to increase success probability,
|
||||
// but it may also increase fees. The limits are 1 for amt == 0 and
|
||||
// minCapacityFactor for amt >> capacityCutoffFraction. The function drops
|
||||
// significantly when amt reaches cutoffMsat. smearingMsat determines over which
|
||||
// scale the reduction takes place.
|
||||
func capacityFactor(amt lnwire.MilliSatoshi, capacity btcutil.Amount,
|
||||
capacityCutoffFraction float64) float64 {
|
||||
|
||||
@ -299,7 +295,11 @@ func capacityFactor(amt lnwire.MilliSatoshi, capacity btcutil.Amount,
|
||||
// at cutoffMsat, decaying over the smearingMsat scale.
|
||||
denominator := 1 + math.Exp(-(amtMsat-cutoffMsat)/smearingMsat)
|
||||
|
||||
return 1 - 1/denominator
|
||||
// The numerator decides what the minimal value of this function will
|
||||
// be. The minimal value is set by minCapacityFactor.
|
||||
numerator := 1 - minCapacityFactor
|
||||
|
||||
return 1 - numerator/denominator
|
||||
}
|
||||
|
||||
// PairProbability estimates the probability of successfully traversing to
|
||||
|
@ -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",
|
||||
|
Loading…
Reference in New Issue
Block a user