From b8c6227383e254085ab752af417e3c32fcc06757 Mon Sep 17 00:00:00 2001 From: bitromortac Date: Fri, 18 Nov 2022 09:59:26 +0100 Subject: [PATCH] routing: add probability estimator interface We introduce a probability `Estimator` interface which is implemented by the current apriori probability estimator. A second implementation, the bimodal probability estimator follows. --- routing/probability_apriori.go | 54 +++++++++++++++++++++++++++++++- routing/probability_estimator.go | 37 ++++++++++++++++++++++ 2 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 routing/probability_estimator.go diff --git a/routing/probability_apriori.go b/routing/probability_apriori.go index 93d11ef26..dabd47ff9 100644 --- a/routing/probability_apriori.go +++ b/routing/probability_apriori.go @@ -2,6 +2,7 @@ package routing import ( "errors" + "fmt" "math" "time" @@ -45,6 +46,10 @@ const ( // capacityCutoffFraction, but a smooth smearing such that some residual // probability is left when spending the whole amount, see above. capacitySmearingFraction = 0.1 + + // AprioriEstimatorName is used to identify the apriori probability + // estimator. + AprioriEstimatorName = "apriori" ) var ( @@ -81,6 +86,7 @@ type AprioriConfig struct { AprioriWeight float64 } +// validate checks the configuration of the estimator for allowed values. func (p AprioriConfig) validate() error { if p.PenaltyHalfLife < 0 { return ErrInvalidHalflife @@ -97,8 +103,24 @@ func (p AprioriConfig) validate() error { return nil } +// DefaultAprioriConfig returns the default configuration for the estimator. +func DefaultAprioriConfig() AprioriConfig { + return AprioriConfig{ + PenaltyHalfLife: DefaultPenaltyHalfLife, + AprioriHopProbability: DefaultAprioriHopProbability, + AprioriWeight: DefaultAprioriWeight, + } +} + // AprioriEstimator returns node and pair probabilities based on historical -// payment results. +// payment results. It uses a preconfigured success probability value for +// untried hops (AprioriHopProbability) and returns a high success probability +// for hops that could previously conduct a payment (prevSuccessProbability). +// Successful edges are retried until proven otherwise. Recently failed hops are +// penalized by an exponential time decay (PenaltyHalfLife), after which they +// are reconsidered for routing. If information was learned about a forwarding +// node, the information is taken into account to estimate a per node +// probability that mixes with the a priori probability (AprioriWeight). type AprioriEstimator struct { // AprioriConfig contains configuration options for our estimator. AprioriConfig @@ -108,6 +130,36 @@ type AprioriEstimator struct { prevSuccessProbability float64 } +// NewAprioriEstimator creates a new AprioriEstimator. +func NewAprioriEstimator(cfg AprioriConfig) (*AprioriEstimator, error) { + if err := cfg.validate(); err != nil { + return nil, err + } + + return &AprioriEstimator{ + AprioriConfig: cfg, + prevSuccessProbability: prevSuccessProbability, + }, nil +} + +// Compile-time checks that interfaces are implemented. +var _ Estimator = (*AprioriEstimator)(nil) +var _ estimatorConfig = (*AprioriConfig)(nil) + +// Config returns the estimator's configuration. +func (p *AprioriEstimator) Config() estimatorConfig { + return p.AprioriConfig +} + +// String returns the estimator's configuration as a string representation. +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) +} + // getNodeProbability calculates the probability for connections from a node // that have not been tried before. The results parameter is a list of last // payment results for that node. diff --git a/routing/probability_estimator.go b/routing/probability_estimator.go new file mode 100644 index 000000000..c110b748d --- /dev/null +++ b/routing/probability_estimator.go @@ -0,0 +1,37 @@ +package routing + +import ( + "time" + + "github.com/btcsuite/btcd/btcutil" + "github.com/lightningnetwork/lnd/lnwire" + "github.com/lightningnetwork/lnd/routing/route" +) + +// Estimator estimates the probability to reach a node. +type Estimator interface { + // PairProbability estimates the probability of successfully traversing + // to toNode based on historical payment outcomes for the from node. + // Those outcomes are passed in via the results parameter. + PairProbability(now time.Time, results NodeResults, + toNode route.Vertex, amt lnwire.MilliSatoshi, + capacity btcutil.Amount) float64 + + // LocalPairProbability estimates the probability of successfully + // traversing our own local channels to toNode. + LocalPairProbability(now time.Time, results NodeResults, + toNode route.Vertex) float64 + + // Config returns the estimator's configuration. + Config() estimatorConfig + + // String returns the string representation of the estimator's + // configuration. + String() string +} + +// estimatorConfig represents a configuration for a probability estimator. +type estimatorConfig interface { + // validate checks that all configuration parameters are sane. + validate() error +}