routing: add min probability to path finding
This commit adds a new restriction to pathfinding that allows returning only routes with a minimum success probability.
This commit is contained in:
parent
6b70791c2d
commit
3349d517aa
@ -46,6 +46,10 @@ var (
|
|||||||
// off potentially better routes against their probability of
|
// off potentially better routes against their probability of
|
||||||
// succeeding.
|
// succeeding.
|
||||||
DefaultPaymentAttemptPenalty = lnwire.NewMSatFromSatoshis(100)
|
DefaultPaymentAttemptPenalty = lnwire.NewMSatFromSatoshis(100)
|
||||||
|
|
||||||
|
// DefaultMinProbability is the default minimum probability for routes
|
||||||
|
// returned from findPath.
|
||||||
|
DefaultMinProbability = float64(0.01)
|
||||||
)
|
)
|
||||||
|
|
||||||
// edgePolicyWithSource is a helper struct to keep track of the source node
|
// edgePolicyWithSource is a helper struct to keep track of the source node
|
||||||
@ -258,6 +262,10 @@ type RestrictParams struct {
|
|||||||
// off potentially better routes against their probability of
|
// off potentially better routes against their probability of
|
||||||
// succeeding.
|
// succeeding.
|
||||||
PaymentAttemptPenalty lnwire.MilliSatoshi
|
PaymentAttemptPenalty lnwire.MilliSatoshi
|
||||||
|
|
||||||
|
// MinProbability defines the minimum success probability of the
|
||||||
|
// returned route.
|
||||||
|
MinProbability float64
|
||||||
}
|
}
|
||||||
|
|
||||||
// findPath attempts to find a path from the source node within the
|
// findPath attempts to find a path from the source node within the
|
||||||
@ -465,6 +473,13 @@ func findPath(g *graphParams, r *RestrictParams, source, target route.Vertex,
|
|||||||
// of the route must succeed.
|
// of the route must succeed.
|
||||||
probability := toNodeDist.probability * edgeProbability
|
probability := toNodeDist.probability * edgeProbability
|
||||||
|
|
||||||
|
// If the probability is below the specified lower bound, we can
|
||||||
|
// abandon this direction. Adding further nodes can only lower
|
||||||
|
// the probability more.
|
||||||
|
if probability < r.MinProbability {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// By adding fromNode in the route, there will be an extra
|
// By adding fromNode in the route, there will be an extra
|
||||||
// weight composed of the fee that this node will charge and
|
// weight composed of the fee that this node will charge and
|
||||||
// the amount that will be locked for timeLockDelta blocks in
|
// the amount that will be locked for timeLockDelta blocks in
|
||||||
|
@ -2025,9 +2025,10 @@ func TestProbabilityRouting(t *testing.T) {
|
|||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
p10, p11, p20 float64
|
p10, p11, p20 float64
|
||||||
expectedChan uint64
|
minProbability float64
|
||||||
|
expectedChan uint64
|
||||||
}{
|
}{
|
||||||
// Test two variations with probabilities that should multiply
|
// Test two variations with probabilities that should multiply
|
||||||
// to the same total route probability. In both cases the three
|
// to the same total route probability. In both cases the three
|
||||||
@ -2039,12 +2040,14 @@ func TestProbabilityRouting(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "three hop 1",
|
name: "three hop 1",
|
||||||
p10: 0.8, p11: 0.5, p20: 0.7,
|
p10: 0.8, p11: 0.5, p20: 0.7,
|
||||||
expectedChan: 10,
|
minProbability: 0.1,
|
||||||
|
expectedChan: 10,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "three hop 2",
|
name: "three hop 2",
|
||||||
p10: 0.5, p11: 0.8, p20: 0.7,
|
p10: 0.5, p11: 0.8, p20: 0.7,
|
||||||
expectedChan: 10,
|
minProbability: 0.1,
|
||||||
|
expectedChan: 10,
|
||||||
},
|
},
|
||||||
|
|
||||||
// If the probability of the two hop route is increased, its
|
// If the probability of the two hop route is increased, its
|
||||||
@ -2055,20 +2058,42 @@ func TestProbabilityRouting(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "two hop higher cost",
|
name: "two hop higher cost",
|
||||||
p10: 0.5, p11: 0.8, p20: 0.85,
|
p10: 0.5, p11: 0.8, p20: 0.85,
|
||||||
expectedChan: 20,
|
minProbability: 0.1,
|
||||||
|
expectedChan: 20,
|
||||||
|
},
|
||||||
|
|
||||||
|
// If the same probabilities are used with a probability lower bound of
|
||||||
|
// 0.5, we expect the three hop route with probability 0.4 to be
|
||||||
|
// excluded and the two hop route to be picked.
|
||||||
|
{
|
||||||
|
name: "probability limit",
|
||||||
|
p10: 0.8, p11: 0.5, p20: 0.7,
|
||||||
|
minProbability: 0.5,
|
||||||
|
expectedChan: 20,
|
||||||
|
},
|
||||||
|
|
||||||
|
// With a probability limit above the probability of both routes, we
|
||||||
|
// expect no route to be returned. This expectation is signaled by using
|
||||||
|
// expected channel 0.
|
||||||
|
{
|
||||||
|
name: "probability limit no routes",
|
||||||
|
p10: 0.8, p11: 0.5, p20: 0.7,
|
||||||
|
minProbability: 0.8,
|
||||||
|
expectedChan: 0,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
testProbabilityRouting(
|
testProbabilityRouting(
|
||||||
t, tc.p10, tc.p11, tc.p20, tc.expectedChan,
|
t, tc.p10, tc.p11, tc.p20,
|
||||||
|
tc.minProbability, tc.expectedChan,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testProbabilityRouting(t *testing.T, p10, p11, p20 float64,
|
func testProbabilityRouting(t *testing.T, p10, p11, p20, minProbability float64,
|
||||||
expectedChan uint64) {
|
expectedChan uint64) {
|
||||||
|
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
@ -2079,7 +2104,6 @@ func testProbabilityRouting(t *testing.T, p10, p11, p20 float64,
|
|||||||
testChannels := []*testChannel{
|
testChannels := []*testChannel{
|
||||||
symmetricTestChannel("roasbeef", "a1", 100000, &testChannelPolicy{}),
|
symmetricTestChannel("roasbeef", "a1", 100000, &testChannelPolicy{}),
|
||||||
symmetricTestChannel("roasbeef", "b", 100000, &testChannelPolicy{}),
|
symmetricTestChannel("roasbeef", "b", 100000, &testChannelPolicy{}),
|
||||||
symmetricTestChannel("roasbeef", "c", 100000, &testChannelPolicy{}),
|
|
||||||
symmetricTestChannel("a1", "a2", 100000, &testChannelPolicy{
|
symmetricTestChannel("a1", "a2", 100000, &testChannelPolicy{
|
||||||
Expiry: 144,
|
Expiry: 144,
|
||||||
FeeBaseMsat: lnwire.NewMSatFromSatoshis(5),
|
FeeBaseMsat: lnwire.NewMSatFromSatoshis(5),
|
||||||
@ -2135,9 +2159,16 @@ func testProbabilityRouting(t *testing.T, p10, p11, p20 float64,
|
|||||||
FeeLimit: noFeeLimit,
|
FeeLimit: noFeeLimit,
|
||||||
ProbabilitySource: probabilitySource,
|
ProbabilitySource: probabilitySource,
|
||||||
PaymentAttemptPenalty: lnwire.NewMSatFromSatoshis(10),
|
PaymentAttemptPenalty: lnwire.NewMSatFromSatoshis(10),
|
||||||
|
MinProbability: minProbability,
|
||||||
},
|
},
|
||||||
sourceVertex, target, paymentAmt,
|
sourceVertex, target, paymentAmt,
|
||||||
)
|
)
|
||||||
|
if expectedChan == 0 {
|
||||||
|
if err == nil || !IsError(err, ErrNoPathFound) {
|
||||||
|
t.Fatalf("expected no path found, but got %v", err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user