mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-07-12 06:02:51 +02:00
routing+lnrpc: make capacity factor configurable
We make the capacity factor configurable via an lnd.conf routerrpc apriori parameter. The capacity factor trades off increased success probability with a reduced set of channel candidates, which may lead to increased fees. To let users choose whether the factor is active or not, we add a config setting where a capacity fraction of 1.0 disables the factor. We limit the capacity fraction to values between 0.75 and 1.0. Lower values may discard too many channels.
This commit is contained in:
@ -12,11 +12,11 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
// capacityCutoffFraction and capacitySmearingFraction define how
|
||||
// capacity-related probability reweighting works.
|
||||
// capacityCutoffFraction 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.
|
||||
// CapacityFraction and capacitySmearingFraction define how
|
||||
// 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
|
||||
@ -34,19 +34,23 @@ const (
|
||||
// fulfill the requirement with capacityFactor(cap, cap) ~ 0.076 (see
|
||||
// tests).
|
||||
|
||||
// The capacityCutoffFraction is a trade-off between usage of the
|
||||
// provided capacity and expected probability reduction when we send the
|
||||
// full amount. The success probability in the random balance model can
|
||||
// be approximated with P(a) = 1 - a/c, for amount a and capacity c. If
|
||||
// we require a probability P(a) > 0.25, this translates into a value of
|
||||
// 0.75 for a/c.
|
||||
capacityCutoffFraction = 0.75
|
||||
// DefaultCapacityFraction is the default value for CapacityFraction.
|
||||
DefaultCapacityFraction = 0.75
|
||||
|
||||
// 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
|
||||
|
||||
// minCapacityFraction is the minimum allowed value for
|
||||
// CapacityFraction. The success probability in the random balance model
|
||||
// (which may not be an accurate description of the liquidity
|
||||
// distribution in the network) can be approximated with P(a) = 1 - a/c,
|
||||
// for amount a and capacity c. If we require a probability P(a) = 0.25,
|
||||
// this translates into a value of 0.75 for a/c. We limit this value in
|
||||
// order to not discard too many channels.
|
||||
minCapacityFraction = 0.75
|
||||
|
||||
// AprioriEstimatorName is used to identify the apriori probability
|
||||
// estimator.
|
||||
AprioriEstimatorName = "apriori"
|
||||
@ -64,6 +68,11 @@ var (
|
||||
// ErrInvalidAprioriWeight is returned when we get an apriori weight
|
||||
// that is out of range.
|
||||
ErrInvalidAprioriWeight = errors.New("apriori weight must be in [0, 1]")
|
||||
|
||||
// ErrInvalidCapacityFraction is returned when we get a capacity
|
||||
// fraction that is out of range.
|
||||
ErrInvalidCapacityFraction = fmt.Errorf("capacity fraction must be in "+
|
||||
"[%v, 1]", minCapacityFraction)
|
||||
)
|
||||
|
||||
// AprioriConfig contains configuration for our probability estimator.
|
||||
@ -84,6 +93,12 @@ type AprioriConfig struct {
|
||||
// probability completely and only base the probability on historical
|
||||
// results, unless there are none available.
|
||||
AprioriWeight float64
|
||||
|
||||
// CapacityFraction is the fraction of a channel's capacity that we
|
||||
// consider to have liquidity. For amounts that come close to or exceed
|
||||
// the fraction, an additional penalty is applied. A value of 1.0
|
||||
// disables the capacityFactor.
|
||||
CapacityFraction float64
|
||||
}
|
||||
|
||||
// validate checks the configuration of the estimator for allowed values.
|
||||
@ -100,6 +115,10 @@ func (p AprioriConfig) validate() error {
|
||||
return ErrInvalidAprioriWeight
|
||||
}
|
||||
|
||||
if p.CapacityFraction < minCapacityFraction || p.CapacityFraction > 1 {
|
||||
return ErrInvalidCapacityFraction
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -109,6 +128,7 @@ func DefaultAprioriConfig() AprioriConfig {
|
||||
PenaltyHalfLife: DefaultPenaltyHalfLife,
|
||||
AprioriHopProbability: DefaultAprioriHopProbability,
|
||||
AprioriWeight: DefaultAprioriWeight,
|
||||
CapacityFraction: DefaultCapacityFraction,
|
||||
}
|
||||
}
|
||||
|
||||
@ -155,9 +175,10 @@ func (p *AprioriEstimator) Config() estimatorConfig {
|
||||
func (p *AprioriEstimator) String() string {
|
||||
return fmt.Sprintf("estimator type: %v, penalty halflife time: %v, "+
|
||||
"apriori hop probability: %v, apriori weight: %v, previous "+
|
||||
"success probability: %v", AprioriEstimatorName,
|
||||
p.PenaltyHalfLife, p.AprioriHopProbability, p.AprioriWeight,
|
||||
p.prevSuccessProbability)
|
||||
"success probability: %v, capacity fraction: %v",
|
||||
AprioriEstimatorName, p.PenaltyHalfLife,
|
||||
p.AprioriHopProbability, p.AprioriWeight,
|
||||
p.prevSuccessProbability, p.CapacityFraction)
|
||||
}
|
||||
|
||||
// getNodeProbability calculates the probability for connections from a node
|
||||
@ -169,7 +190,9 @@ func (p *AprioriEstimator) getNodeProbability(now time.Time,
|
||||
|
||||
// We reduce the apriori hop probability if the amount comes close to
|
||||
// the capacity.
|
||||
apriori := p.AprioriHopProbability * capacityFactor(amt, capacity)
|
||||
apriori := p.AprioriHopProbability * capacityFactor(
|
||||
amt, capacity, p.CapacityFraction,
|
||||
)
|
||||
|
||||
// If the channel history is not to be taken into account, we can return
|
||||
// early here with the configured a priori probability.
|
||||
@ -246,7 +269,15 @@ func (p *AprioriEstimator) getWeight(age time.Duration) float64 {
|
||||
// and 0 for amt >> cutoffMsat. 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) float64 {
|
||||
func capacityFactor(amt lnwire.MilliSatoshi, capacity btcutil.Amount,
|
||||
capacityCutoffFraction float64) float64 {
|
||||
|
||||
// The special value of 1.0 for capacityFactor disables any effect from
|
||||
// this factor.
|
||||
if capacityCutoffFraction == 1 {
|
||||
return 1.0
|
||||
}
|
||||
|
||||
// If we don't have information about the capacity, which can be the
|
||||
// case for hop hints or local channels, we return unity to not alter
|
||||
// anything.
|
||||
|
Reference in New Issue
Block a user