Merge pull request #3221 from joostjager/queryroutes-mc
routing+routerrpc+lnrpc: add option to use mc in queryroutes
This commit is contained in:
14 files changed
+672
-561
No files matched your search
@@ -2997,6 +2997,10 @@ var queryRoutesCommand = cli.Command{
|
|||||||
Usage: "(optional) number of blocks the last hop has to reveal " +
|
Usage: "(optional) number of blocks the last hop has to reveal " +
|
||||||
"the preimage",
|
"the preimage",
|
||||||
},
|
},
|
||||||
|
cli.BoolFlag{
|
||||||
|
Name: "use_mc",
|
||||||
|
Usage: "use mission control probabilities",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Action: actionDecorator(queryRoutes),
|
Action: actionDecorator(queryRoutes),
|
||||||
}
|
}
|
||||||
@@ -3042,10 +3046,11 @@ func queryRoutes(ctx *cli.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
req := &lnrpc.QueryRoutesRequest{
|
req := &lnrpc.QueryRoutesRequest{
|
||||||
PubKey: dest,
|
PubKey: dest,
|
||||||
Amt: amt,
|
Amt: amt,
|
||||||
FeeLimit: feeLimit,
|
FeeLimit: feeLimit,
|
||||||
FinalCltvDelta: int32(ctx.Int("final_cltv_delta")),
|
FinalCltvDelta: int32(ctx.Int("final_cltv_delta")),
|
||||||
|
UseMissionControl: ctx.Bool("use_mc"),
|
||||||
}
|
}
|
||||||
|
|
||||||
route, err := client.QueryRoutes(ctxb, req)
|
route, err := client.QueryRoutes(ctxb, req)
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ type RouterBackend struct {
|
|||||||
amt lnwire.MilliSatoshi, restrictions *routing.RestrictParams,
|
amt lnwire.MilliSatoshi, restrictions *routing.RestrictParams,
|
||||||
finalExpiry ...uint16) (*route.Route, error)
|
finalExpiry ...uint16) (*route.Route, error)
|
||||||
|
|
||||||
MissionControl *routing.MissionControl
|
MissionControl MissionControl
|
||||||
|
|
||||||
// ActiveNetParams are the network parameters of the primary network
|
// ActiveNetParams are the network parameters of the primary network
|
||||||
// that the route is operating on. This is necessary so we can ensure
|
// that the route is operating on. This is necessary so we can ensure
|
||||||
@@ -55,6 +55,22 @@ type RouterBackend struct {
|
|||||||
Tower routing.ControlTower
|
Tower routing.ControlTower
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MissionControl defines the mission control dependencies of routerrpc.
|
||||||
|
type MissionControl interface {
|
||||||
|
// GetEdgeProbability is expected to return the success probability of a payment
|
||||||
|
// from fromNode along edge.
|
||||||
|
GetEdgeProbability(fromNode route.Vertex,
|
||||||
|
edge routing.EdgeLocator, amt lnwire.MilliSatoshi) float64
|
||||||
|
|
||||||
|
// ResetHistory resets the history of MissionControl returning it to a state as
|
||||||
|
// if no payment attempts have been made.
|
||||||
|
ResetHistory()
|
||||||
|
|
||||||
|
// GetHistorySnapshot takes a snapshot from the current mission control state
|
||||||
|
// and actual probability estimates.
|
||||||
|
GetHistorySnapshot() *routing.MissionControlSnapshot
|
||||||
|
}
|
||||||
|
|
||||||
// QueryRoutes attempts to query the daemons' Channel Router for a possible
|
// QueryRoutes attempts to query the daemons' Channel Router for a possible
|
||||||
// route to a target destination capable of carrying a specific amount of
|
// route to a target destination capable of carrying a specific amount of
|
||||||
// satoshis within the route's flow. The retuned route contains the full
|
// satoshis within the route's flow. The retuned route contains the full
|
||||||
@@ -151,9 +167,14 @@ func (r *RouterBackend) QueryRoutes(ctx context.Context,
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1
|
if !in.UseMissionControl {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.MissionControl.GetEdgeProbability(
|
||||||
|
node, edge, amt,
|
||||||
|
)
|
||||||
},
|
},
|
||||||
PaymentAttemptPenalty: routing.DefaultPaymentAttemptPenalty,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Query the channel router for a possible path to the destination that
|
// Query the channel router for a possible path to the destination that
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ import (
|
|||||||
const (
|
const (
|
||||||
destKey = "0286098b97bc843372b4426d4b276cea9aa2f48f0428d6f5b66ae101befc14f8b4"
|
destKey = "0286098b97bc843372b4426d4b276cea9aa2f48f0428d6f5b66ae101befc14f8b4"
|
||||||
ignoreNodeKey = "02f274f48f3c0d590449a6776e3ce8825076ac376e470e992246eebc565ef8bb2a"
|
ignoreNodeKey = "02f274f48f3c0d590449a6776e3ce8825076ac376e470e992246eebc565ef8bb2a"
|
||||||
|
|
||||||
|
testMissionControlProb = 0.5
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -26,6 +28,15 @@ var (
|
|||||||
// TestQueryRoutes asserts that query routes rpc parameters are properly parsed
|
// TestQueryRoutes asserts that query routes rpc parameters are properly parsed
|
||||||
// and passed onto path finding.
|
// and passed onto path finding.
|
||||||
func TestQueryRoutes(t *testing.T) {
|
func TestQueryRoutes(t *testing.T) {
|
||||||
|
t.Run("no mission control", func(t *testing.T) {
|
||||||
|
testQueryRoutes(t, false)
|
||||||
|
})
|
||||||
|
t.Run("with mission control", func(t *testing.T) {
|
||||||
|
testQueryRoutes(t, true)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func testQueryRoutes(t *testing.T, useMissionControl bool) {
|
||||||
ignoreNodeBytes, err := hex.DecodeString(ignoreNodeKey)
|
ignoreNodeBytes, err := hex.DecodeString(ignoreNodeKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -58,6 +69,7 @@ func TestQueryRoutes(t *testing.T) {
|
|||||||
ChannelId: 555,
|
ChannelId: 555,
|
||||||
DirectionReverse: true,
|
DirectionReverse: true,
|
||||||
}},
|
}},
|
||||||
|
UseMissionControl: useMissionControl,
|
||||||
}
|
}
|
||||||
|
|
||||||
findRoute := func(source, target route.Vertex,
|
findRoute := func(source, target route.Vertex,
|
||||||
@@ -92,9 +104,13 @@ func TestQueryRoutes(t *testing.T) {
|
|||||||
t.Fatal("expecting 0% probability for ignored node")
|
t.Fatal("expecting 0% probability for ignored node")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
expectedProb := 1.0
|
||||||
|
if useMissionControl {
|
||||||
|
expectedProb = testMissionControlProb
|
||||||
|
}
|
||||||
if restrictions.ProbabilitySource(route.Vertex{},
|
if restrictions.ProbabilitySource(route.Vertex{},
|
||||||
routing.EdgeLocator{}, 0,
|
routing.EdgeLocator{}, 0,
|
||||||
) != 1 {
|
) != expectedProb {
|
||||||
t.Fatal("expecting 100% probability")
|
t.Fatal("expecting 100% probability")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,6 +127,7 @@ func TestQueryRoutes(t *testing.T) {
|
|||||||
|
|
||||||
return 1, nil
|
return 1, nil
|
||||||
},
|
},
|
||||||
|
MissionControl: &mockMissionControl{},
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := backend.QueryRoutes(context.Background(), request)
|
resp, err := backend.QueryRoutes(context.Background(), request)
|
||||||
@@ -121,3 +138,17 @@ func TestQueryRoutes(t *testing.T) {
|
|||||||
t.Fatal("expected a single route response")
|
t.Fatal("expected a single route response")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type mockMissionControl struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockMissionControl) GetEdgeProbability(fromNode route.Vertex,
|
||||||
|
edge routing.EdgeLocator, amt lnwire.MilliSatoshi) float64 {
|
||||||
|
return testMissionControlProb
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockMissionControl) ResetHistory() {}
|
||||||
|
|
||||||
|
func (m *mockMissionControl) GetHistorySnapshot() *routing.MissionControlSnapshot {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
+510
-498
File diff suppressed because it is too large.
Load diff
@@ -1651,6 +1651,12 @@ message QueryRoutesRequest {
|
|||||||
self is assumed.
|
self is assumed.
|
||||||
*/
|
*/
|
||||||
string source_pub_key = 8;
|
string source_pub_key = 8;
|
||||||
|
|
||||||
|
/**
|
||||||
|
If set to true, edge probabilities from mission control will be used to get
|
||||||
|
the optimal route.
|
||||||
|
*/
|
||||||
|
bool use_mission_control = 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
message EdgeLocator {
|
message EdgeLocator {
|
||||||
|
|||||||
@@ -722,6 +722,14 @@
|
|||||||
"in": "query",
|
"in": "query",
|
||||||
"required": false,
|
"required": false,
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "use_mission_control",
|
||||||
|
"description": "*\nIf set to true, edge probabilities from mission control will be used to get\nthe optimal route.",
|
||||||
|
"in": "query",
|
||||||
|
"required": false,
|
||||||
|
"type": "boolean",
|
||||||
|
"format": "boolean"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
|
|||||||
+12
-6
@@ -37,8 +37,8 @@ const (
|
|||||||
|
|
||||||
// pathFinder defines the interface of a path finding algorithm.
|
// pathFinder defines the interface of a path finding algorithm.
|
||||||
type pathFinder = func(g *graphParams, r *RestrictParams,
|
type pathFinder = func(g *graphParams, r *RestrictParams,
|
||||||
source, target route.Vertex, amt lnwire.MilliSatoshi) (
|
cfg *PathFindingConfig, source, target route.Vertex,
|
||||||
[]*channeldb.ChannelEdgePolicy, error)
|
amt lnwire.MilliSatoshi) ([]*channeldb.ChannelEdgePolicy, error)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// DefaultPaymentAttemptPenalty is the virtual cost in path finding weight
|
// DefaultPaymentAttemptPenalty is the virtual cost in path finding weight
|
||||||
@@ -261,7 +261,11 @@ type RestrictParams struct {
|
|||||||
// ctlv. After path finding is complete, the caller needs to increase
|
// ctlv. After path finding is complete, the caller needs to increase
|
||||||
// all cltv expiry heights with the required final cltv delta.
|
// all cltv expiry heights with the required final cltv delta.
|
||||||
CltvLimit *uint32
|
CltvLimit *uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
// PathFindingConfig defines global parameters that control the trade-off in
|
||||||
|
// path finding between fees and probabiity.
|
||||||
|
type PathFindingConfig struct {
|
||||||
// PaymentAttemptPenalty is the virtual cost in path finding weight
|
// PaymentAttemptPenalty is the virtual cost in path finding weight
|
||||||
// units of executing a payment attempt that fails. It is used to trade
|
// units of executing a payment attempt that fails. It is used to trade
|
||||||
// off potentially better routes against their probability of
|
// off potentially better routes against their probability of
|
||||||
@@ -284,8 +288,9 @@ type RestrictParams struct {
|
|||||||
// destination node back to source. This is to properly accumulate fees
|
// destination node back to source. This is to properly accumulate fees
|
||||||
// that need to be paid along the path and accurately check the amount
|
// that need to be paid along the path and accurately check the amount
|
||||||
// to forward at every node against the available bandwidth.
|
// to forward at every node against the available bandwidth.
|
||||||
func findPath(g *graphParams, r *RestrictParams, source, target route.Vertex,
|
func findPath(g *graphParams, r *RestrictParams, cfg *PathFindingConfig,
|
||||||
amt lnwire.MilliSatoshi) ([]*channeldb.ChannelEdgePolicy, error) {
|
source, target route.Vertex, amt lnwire.MilliSatoshi) (
|
||||||
|
[]*channeldb.ChannelEdgePolicy, error) {
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
tx := g.tx
|
tx := g.tx
|
||||||
@@ -476,7 +481,7 @@ func findPath(g *graphParams, r *RestrictParams, source, target route.Vertex,
|
|||||||
// If the probability is below the specified lower bound, we can
|
// If the probability is below the specified lower bound, we can
|
||||||
// abandon this direction. Adding further nodes can only lower
|
// abandon this direction. Adding further nodes can only lower
|
||||||
// the probability more.
|
// the probability more.
|
||||||
if probability < r.MinProbability {
|
if probability < cfg.MinProbability {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -494,7 +499,8 @@ func findPath(g *graphParams, r *RestrictParams, source, target route.Vertex,
|
|||||||
// Add an extra factor to the weight to take into account the
|
// Add an extra factor to the weight to take into account the
|
||||||
// probability.
|
// probability.
|
||||||
tempDist := getProbabilityBasedDist(
|
tempDist := getProbabilityBasedDist(
|
||||||
tempWeight, probability, int64(r.PaymentAttemptPenalty),
|
tempWeight, probability,
|
||||||
|
int64(cfg.PaymentAttemptPenalty),
|
||||||
)
|
)
|
||||||
|
|
||||||
// If the current best route is better than this candidate
|
// If the current best route is better than this candidate
|
||||||
|
|||||||
+25
-17
@@ -55,6 +55,8 @@ var (
|
|||||||
FeeLimit: noFeeLimit,
|
FeeLimit: noFeeLimit,
|
||||||
ProbabilitySource: noProbabilitySource,
|
ProbabilitySource: noProbabilitySource,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
testPathFindingConfig = &PathFindingConfig{}
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -650,6 +652,7 @@ func TestFindLowestFeePath(t *testing.T) {
|
|||||||
graph: testGraphInstance.graph,
|
graph: testGraphInstance.graph,
|
||||||
},
|
},
|
||||||
noRestrictions,
|
noRestrictions,
|
||||||
|
testPathFindingConfig,
|
||||||
sourceNode.PubKeyBytes, target, paymentAmt,
|
sourceNode.PubKeyBytes, target, paymentAmt,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -791,6 +794,7 @@ func testBasicGraphPathFindingCase(t *testing.T, graphInstance *testGraphInstanc
|
|||||||
FeeLimit: test.feeLimit,
|
FeeLimit: test.feeLimit,
|
||||||
ProbabilitySource: noProbabilitySource,
|
ProbabilitySource: noProbabilitySource,
|
||||||
},
|
},
|
||||||
|
testPathFindingConfig,
|
||||||
sourceNode.PubKeyBytes, target, paymentAmt,
|
sourceNode.PubKeyBytes, target, paymentAmt,
|
||||||
)
|
)
|
||||||
if test.expectFailureNoPath {
|
if test.expectFailureNoPath {
|
||||||
@@ -957,7 +961,7 @@ func TestPathFindingWithAdditionalEdges(t *testing.T) {
|
|||||||
graph: graph.graph,
|
graph: graph.graph,
|
||||||
additionalEdges: additionalEdges,
|
additionalEdges: additionalEdges,
|
||||||
},
|
},
|
||||||
noRestrictions,
|
noRestrictions, testPathFindingConfig,
|
||||||
sourceNode.PubKeyBytes, doge.PubKeyBytes, paymentAmt,
|
sourceNode.PubKeyBytes, doge.PubKeyBytes, paymentAmt,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1211,7 +1215,7 @@ func TestNewRoutePathTooLong(t *testing.T) {
|
|||||||
&graphParams{
|
&graphParams{
|
||||||
graph: graph.graph,
|
graph: graph.graph,
|
||||||
},
|
},
|
||||||
noRestrictions,
|
noRestrictions, testPathFindingConfig,
|
||||||
sourceNode.PubKeyBytes, target, paymentAmt,
|
sourceNode.PubKeyBytes, target, paymentAmt,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1225,7 +1229,7 @@ func TestNewRoutePathTooLong(t *testing.T) {
|
|||||||
&graphParams{
|
&graphParams{
|
||||||
graph: graph.graph,
|
graph: graph.graph,
|
||||||
},
|
},
|
||||||
noRestrictions,
|
noRestrictions, testPathFindingConfig,
|
||||||
sourceNode.PubKeyBytes, target, paymentAmt,
|
sourceNode.PubKeyBytes, target, paymentAmt,
|
||||||
)
|
)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@@ -1265,7 +1269,7 @@ func TestPathNotAvailable(t *testing.T) {
|
|||||||
&graphParams{
|
&graphParams{
|
||||||
graph: graph.graph,
|
graph: graph.graph,
|
||||||
},
|
},
|
||||||
noRestrictions,
|
noRestrictions, testPathFindingConfig,
|
||||||
sourceNode.PubKeyBytes, unknownNode, 100,
|
sourceNode.PubKeyBytes, unknownNode, 100,
|
||||||
)
|
)
|
||||||
if !IsError(err, ErrNoPathFound) {
|
if !IsError(err, ErrNoPathFound) {
|
||||||
@@ -1302,7 +1306,7 @@ func TestPathInsufficientCapacity(t *testing.T) {
|
|||||||
&graphParams{
|
&graphParams{
|
||||||
graph: graph.graph,
|
graph: graph.graph,
|
||||||
},
|
},
|
||||||
noRestrictions,
|
noRestrictions, testPathFindingConfig,
|
||||||
sourceNode.PubKeyBytes, target, payAmt,
|
sourceNode.PubKeyBytes, target, payAmt,
|
||||||
)
|
)
|
||||||
if !IsError(err, ErrNoPathFound) {
|
if !IsError(err, ErrNoPathFound) {
|
||||||
@@ -1335,7 +1339,7 @@ func TestRouteFailMinHTLC(t *testing.T) {
|
|||||||
&graphParams{
|
&graphParams{
|
||||||
graph: graph.graph,
|
graph: graph.graph,
|
||||||
},
|
},
|
||||||
noRestrictions,
|
noRestrictions, testPathFindingConfig,
|
||||||
sourceNode.PubKeyBytes, target, payAmt,
|
sourceNode.PubKeyBytes, target, payAmt,
|
||||||
)
|
)
|
||||||
if !IsError(err, ErrNoPathFound) {
|
if !IsError(err, ErrNoPathFound) {
|
||||||
@@ -1393,7 +1397,7 @@ func TestRouteFailMaxHTLC(t *testing.T) {
|
|||||||
&graphParams{
|
&graphParams{
|
||||||
graph: graph.graph,
|
graph: graph.graph,
|
||||||
},
|
},
|
||||||
noRestrictions,
|
noRestrictions, testPathFindingConfig,
|
||||||
sourceNode.PubKeyBytes, target, payAmt,
|
sourceNode.PubKeyBytes, target, payAmt,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1415,7 +1419,7 @@ func TestRouteFailMaxHTLC(t *testing.T) {
|
|||||||
&graphParams{
|
&graphParams{
|
||||||
graph: graph.graph,
|
graph: graph.graph,
|
||||||
},
|
},
|
||||||
noRestrictions,
|
noRestrictions, testPathFindingConfig,
|
||||||
sourceNode.PubKeyBytes, target, payAmt,
|
sourceNode.PubKeyBytes, target, payAmt,
|
||||||
)
|
)
|
||||||
if !IsError(err, ErrNoPathFound) {
|
if !IsError(err, ErrNoPathFound) {
|
||||||
@@ -1450,7 +1454,7 @@ func TestRouteFailDisabledEdge(t *testing.T) {
|
|||||||
&graphParams{
|
&graphParams{
|
||||||
graph: graph.graph,
|
graph: graph.graph,
|
||||||
},
|
},
|
||||||
noRestrictions,
|
noRestrictions, testPathFindingConfig,
|
||||||
sourceNode.PubKeyBytes, target, payAmt,
|
sourceNode.PubKeyBytes, target, payAmt,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1478,7 +1482,7 @@ func TestRouteFailDisabledEdge(t *testing.T) {
|
|||||||
&graphParams{
|
&graphParams{
|
||||||
graph: graph.graph,
|
graph: graph.graph,
|
||||||
},
|
},
|
||||||
noRestrictions,
|
noRestrictions, testPathFindingConfig,
|
||||||
sourceNode.PubKeyBytes, target, payAmt,
|
sourceNode.PubKeyBytes, target, payAmt,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1503,7 +1507,7 @@ func TestRouteFailDisabledEdge(t *testing.T) {
|
|||||||
&graphParams{
|
&graphParams{
|
||||||
graph: graph.graph,
|
graph: graph.graph,
|
||||||
},
|
},
|
||||||
noRestrictions,
|
noRestrictions, testPathFindingConfig,
|
||||||
sourceNode.PubKeyBytes, target, payAmt,
|
sourceNode.PubKeyBytes, target, payAmt,
|
||||||
)
|
)
|
||||||
if !IsError(err, ErrNoPathFound) {
|
if !IsError(err, ErrNoPathFound) {
|
||||||
@@ -1537,7 +1541,7 @@ func TestPathSourceEdgesBandwidth(t *testing.T) {
|
|||||||
&graphParams{
|
&graphParams{
|
||||||
graph: graph.graph,
|
graph: graph.graph,
|
||||||
},
|
},
|
||||||
noRestrictions,
|
noRestrictions, testPathFindingConfig,
|
||||||
sourceNode.PubKeyBytes, target, payAmt,
|
sourceNode.PubKeyBytes, target, payAmt,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1561,7 +1565,7 @@ func TestPathSourceEdgesBandwidth(t *testing.T) {
|
|||||||
graph: graph.graph,
|
graph: graph.graph,
|
||||||
bandwidthHints: bandwidths,
|
bandwidthHints: bandwidths,
|
||||||
},
|
},
|
||||||
noRestrictions,
|
noRestrictions, testPathFindingConfig,
|
||||||
sourceNode.PubKeyBytes, target, payAmt,
|
sourceNode.PubKeyBytes, target, payAmt,
|
||||||
)
|
)
|
||||||
if !IsError(err, ErrNoPathFound) {
|
if !IsError(err, ErrNoPathFound) {
|
||||||
@@ -1579,7 +1583,7 @@ func TestPathSourceEdgesBandwidth(t *testing.T) {
|
|||||||
graph: graph.graph,
|
graph: graph.graph,
|
||||||
bandwidthHints: bandwidths,
|
bandwidthHints: bandwidths,
|
||||||
},
|
},
|
||||||
noRestrictions,
|
noRestrictions, testPathFindingConfig,
|
||||||
sourceNode.PubKeyBytes, target, payAmt,
|
sourceNode.PubKeyBytes, target, payAmt,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1610,7 +1614,7 @@ func TestPathSourceEdgesBandwidth(t *testing.T) {
|
|||||||
graph: graph.graph,
|
graph: graph.graph,
|
||||||
bandwidthHints: bandwidths,
|
bandwidthHints: bandwidths,
|
||||||
},
|
},
|
||||||
noRestrictions,
|
noRestrictions, testPathFindingConfig,
|
||||||
sourceNode.PubKeyBytes, target, payAmt,
|
sourceNode.PubKeyBytes, target, payAmt,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1903,6 +1907,7 @@ func TestRestrictOutgoingChannel(t *testing.T) {
|
|||||||
OutgoingChannelID: &outgoingChannelID,
|
OutgoingChannelID: &outgoingChannelID,
|
||||||
ProbabilitySource: noProbabilitySource,
|
ProbabilitySource: noProbabilitySource,
|
||||||
},
|
},
|
||||||
|
testPathFindingConfig,
|
||||||
sourceVertex, target, paymentAmt,
|
sourceVertex, target, paymentAmt,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1998,6 +2003,7 @@ func testCltvLimit(t *testing.T, limit uint32, expectedChannel uint64) {
|
|||||||
CltvLimit: cltvLimit,
|
CltvLimit: cltvLimit,
|
||||||
ProbabilitySource: noProbabilitySource,
|
ProbabilitySource: noProbabilitySource,
|
||||||
},
|
},
|
||||||
|
testPathFindingConfig,
|
||||||
sourceVertex, target, paymentAmt,
|
sourceVertex, target, paymentAmt,
|
||||||
)
|
)
|
||||||
if expectedChannel == 0 {
|
if expectedChannel == 0 {
|
||||||
@@ -2174,8 +2180,10 @@ func testProbabilityRouting(t *testing.T, p10, p11, p20, minProbability float64,
|
|||||||
graph: testGraphInstance.graph,
|
graph: testGraphInstance.graph,
|
||||||
},
|
},
|
||||||
&RestrictParams{
|
&RestrictParams{
|
||||||
FeeLimit: noFeeLimit,
|
FeeLimit: noFeeLimit,
|
||||||
ProbabilitySource: probabilitySource,
|
ProbabilitySource: probabilitySource,
|
||||||
|
},
|
||||||
|
&PathFindingConfig{
|
||||||
PaymentAttemptPenalty: lnwire.NewMSatFromSatoshis(10),
|
PaymentAttemptPenalty: lnwire.NewMSatFromSatoshis(10),
|
||||||
MinProbability: minProbability,
|
MinProbability: minProbability,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -83,12 +83,10 @@ func (p *paymentSession) RequestRoute(payment *LightningPayment,
|
|||||||
ss := p.sessionSource
|
ss := p.sessionSource
|
||||||
|
|
||||||
restrictions := &RestrictParams{
|
restrictions := &RestrictParams{
|
||||||
ProbabilitySource: ss.MissionControl.GetEdgeProbability,
|
ProbabilitySource: ss.MissionControl.GetEdgeProbability,
|
||||||
FeeLimit: payment.FeeLimit,
|
FeeLimit: payment.FeeLimit,
|
||||||
OutgoingChannelID: payment.OutgoingChannelID,
|
OutgoingChannelID: payment.OutgoingChannelID,
|
||||||
CltvLimit: cltvLimit,
|
CltvLimit: cltvLimit,
|
||||||
PaymentAttemptPenalty: ss.PaymentAttemptPenalty,
|
|
||||||
MinProbability: ss.MinRouteProbability,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
path, err := p.pathFinder(
|
path, err := p.pathFinder(
|
||||||
@@ -97,7 +95,8 @@ func (p *paymentSession) RequestRoute(payment *LightningPayment,
|
|||||||
additionalEdges: p.additionalEdges,
|
additionalEdges: p.additionalEdges,
|
||||||
bandwidthHints: p.bandwidthHints,
|
bandwidthHints: p.bandwidthHints,
|
||||||
},
|
},
|
||||||
restrictions, ss.SelfNode.PubKeyBytes, payment.Target,
|
restrictions, &ss.PathFindingConfig,
|
||||||
|
ss.SelfNode.PubKeyBytes, payment.Target,
|
||||||
payment.Amount,
|
payment.Amount,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -38,15 +38,9 @@ type SessionSource struct {
|
|||||||
// execution.
|
// execution.
|
||||||
MissionControl MissionController
|
MissionControl MissionController
|
||||||
|
|
||||||
// PaymentAttemptPenalty is the virtual cost in path finding weight
|
// PathFindingConfig defines global parameters that control the
|
||||||
// units of executing a payment attempt that fails. It is used to trade
|
// trade-off in path finding between fees and probabiity.
|
||||||
// off potentially better routes against their probability of
|
PathFindingConfig PathFindingConfig
|
||||||
// succeeding.
|
|
||||||
PaymentAttemptPenalty lnwire.MilliSatoshi
|
|
||||||
|
|
||||||
// MinProbability defines the minimum success probability of the
|
|
||||||
// returned route.
|
|
||||||
MinRouteProbability float64
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPaymentSession creates a new payment session backed by the latest prune
|
// NewPaymentSession creates a new payment session backed by the latest prune
|
||||||
|
|||||||
@@ -14,8 +14,9 @@ func TestRequestRoute(t *testing.T) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
findPath := func(g *graphParams, r *RestrictParams,
|
findPath := func(g *graphParams, r *RestrictParams,
|
||||||
source, target route.Vertex, amt lnwire.MilliSatoshi) (
|
cfg *PathFindingConfig, source, target route.Vertex,
|
||||||
[]*channeldb.ChannelEdgePolicy, error) {
|
amt lnwire.MilliSatoshi) ([]*channeldb.ChannelEdgePolicy,
|
||||||
|
error) {
|
||||||
|
|
||||||
// We expect find path to receive a cltv limit excluding the
|
// We expect find path to receive a cltv limit excluding the
|
||||||
// final cltv delta.
|
// final cltv delta.
|
||||||
|
|||||||
+5
-1
@@ -287,6 +287,9 @@ type Config struct {
|
|||||||
// spentness of channel outpoints. For neutrino, this saves long rescans
|
// spentness of channel outpoints. For neutrino, this saves long rescans
|
||||||
// from blocking initial usage of the daemon.
|
// from blocking initial usage of the daemon.
|
||||||
AssumeChannelValid bool
|
AssumeChannelValid bool
|
||||||
|
|
||||||
|
// PathFindingConfig defines global path finding parameters.
|
||||||
|
PathFindingConfig PathFindingConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
// routeTuple is an entry within the ChannelRouter's route cache. We cache
|
// routeTuple is an entry within the ChannelRouter's route cache. We cache
|
||||||
@@ -1455,7 +1458,8 @@ func (r *ChannelRouter) FindRoute(source, target route.Vertex,
|
|||||||
graph: r.cfg.Graph,
|
graph: r.cfg.Graph,
|
||||||
bandwidthHints: bandwidthHints,
|
bandwidthHints: bandwidthHints,
|
||||||
},
|
},
|
||||||
restrictions, source, target, amt,
|
restrictions, &r.cfg.PathFindingConfig,
|
||||||
|
source, target, amt,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
+18
-7
@@ -90,11 +90,18 @@ func createTestCtxFromGraphInstance(startingHeight uint32, graphInstance *testGr
|
|||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pathFindingConfig := &PathFindingConfig{
|
||||||
|
MinProbability: 0.01,
|
||||||
|
PaymentAttemptPenalty: 100,
|
||||||
|
}
|
||||||
|
|
||||||
|
mcConfig := &MissionControlConfig{
|
||||||
|
PenaltyHalfLife: time.Hour,
|
||||||
|
AprioriHopProbability: 0.9,
|
||||||
|
}
|
||||||
|
|
||||||
mc := NewMissionControl(
|
mc := NewMissionControl(
|
||||||
&MissionControlConfig{
|
mcConfig,
|
||||||
PenaltyHalfLife: time.Hour,
|
|
||||||
AprioriHopProbability: 0.9,
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
|
|
||||||
sessionSource := &SessionSource{
|
sessionSource := &SessionSource{
|
||||||
@@ -103,9 +110,11 @@ func createTestCtxFromGraphInstance(startingHeight uint32, graphInstance *testGr
|
|||||||
QueryBandwidth: func(e *channeldb.ChannelEdgeInfo) lnwire.MilliSatoshi {
|
QueryBandwidth: func(e *channeldb.ChannelEdgeInfo) lnwire.MilliSatoshi {
|
||||||
return lnwire.NewMSatFromSatoshis(e.Capacity)
|
return lnwire.NewMSatFromSatoshis(e.Capacity)
|
||||||
},
|
},
|
||||||
MinRouteProbability: 0.01,
|
PathFindingConfig: PathFindingConfig{
|
||||||
PaymentAttemptPenalty: 100,
|
MinProbability: 0.01,
|
||||||
MissionControl: mc,
|
PaymentAttemptPenalty: 100,
|
||||||
|
},
|
||||||
|
MissionControl: mc,
|
||||||
}
|
}
|
||||||
|
|
||||||
router, err := New(Config{
|
router, err := New(Config{
|
||||||
@@ -125,6 +134,7 @@ func createTestCtxFromGraphInstance(startingHeight uint32, graphInstance *testGr
|
|||||||
next := atomic.AddUint64(&uniquePaymentID, 1)
|
next := atomic.AddUint64(&uniquePaymentID, 1)
|
||||||
return next, nil
|
return next, nil
|
||||||
},
|
},
|
||||||
|
PathFindingConfig: *pathFindingConfig,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, fmt.Errorf("unable to create router %v", err)
|
return nil, nil, fmt.Errorf("unable to create router %v", err)
|
||||||
@@ -2163,6 +2173,7 @@ func TestFindPathFeeWeighting(t *testing.T) {
|
|||||||
graph: ctx.graph,
|
graph: ctx.graph,
|
||||||
},
|
},
|
||||||
noRestrictions,
|
noRestrictions,
|
||||||
|
testPathFindingConfig,
|
||||||
sourceNode.PubKeyBytes, target, amt,
|
sourceNode.PubKeyBytes, target, amt,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -666,13 +666,17 @@ func newServer(listenAddrs []net.Addr, chanDB *channeldb.DB,
|
|||||||
int64(routingConfig.PaymentAttemptPenalty.ToSatoshis()),
|
int64(routingConfig.PaymentAttemptPenalty.ToSatoshis()),
|
||||||
routingConfig.MinRouteProbability)
|
routingConfig.MinRouteProbability)
|
||||||
|
|
||||||
paymentSessionSource := &routing.SessionSource{
|
pathFindingConfig := routing.PathFindingConfig{
|
||||||
Graph: chanGraph,
|
|
||||||
MissionControl: s.missionControl,
|
|
||||||
QueryBandwidth: queryBandwidth,
|
|
||||||
SelfNode: selfNode,
|
|
||||||
PaymentAttemptPenalty: routingConfig.PaymentAttemptPenalty,
|
PaymentAttemptPenalty: routingConfig.PaymentAttemptPenalty,
|
||||||
MinRouteProbability: routingConfig.MinRouteProbability,
|
MinProbability: routingConfig.MinRouteProbability,
|
||||||
|
}
|
||||||
|
|
||||||
|
paymentSessionSource := &routing.SessionSource{
|
||||||
|
Graph: chanGraph,
|
||||||
|
MissionControl: s.missionControl,
|
||||||
|
QueryBandwidth: queryBandwidth,
|
||||||
|
SelfNode: selfNode,
|
||||||
|
PathFindingConfig: pathFindingConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
paymentControl := channeldb.NewPaymentControl(chanDB)
|
paymentControl := channeldb.NewPaymentControl(chanDB)
|
||||||
@@ -692,6 +696,7 @@ func newServer(listenAddrs []net.Addr, chanDB *channeldb.DB,
|
|||||||
QueryBandwidth: queryBandwidth,
|
QueryBandwidth: queryBandwidth,
|
||||||
AssumeChannelValid: cfg.Routing.UseAssumeChannelValid(),
|
AssumeChannelValid: cfg.Routing.UseAssumeChannelValid(),
|
||||||
NextPaymentID: sequencer.NextID,
|
NextPaymentID: sequencer.NextID,
|
||||||
|
PathFindingConfig: pathFindingConfig,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("can't create router: %v", err)
|
return nil, fmt.Errorf("can't create router: %v", err)
|
||||||
|
|||||||
Reference in new issue
Block a user