routing: convert to node pair based

Previously mission control tracked failures on a per node, per channel basis.
This commit changes this to tracking on the level of directed node pairs. The goal
of moving to this coarser-grained level is to reduce the number of required
payment attempts without compromising payment reliability.
This commit is contained in:
Joost Jager
2019-07-29 15:10:58 +02:00
parent 6ee2c04190
commit f1769c8c8c
17 changed files with 1133 additions and 995 deletions

View File

@@ -57,10 +57,10 @@ type RouterBackend struct {
// 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
// GetProbability is expected to return the success probability of a
// payment from fromNode to toNode.
GetProbability(fromNode, toNode route.Vertex,
amt lnwire.MilliSatoshi) float64
// ResetHistory resets the history of MissionControl returning it to a
// state as if no payment attempts have been made.
@@ -133,28 +133,50 @@ func (r *RouterBackend) QueryRoutes(ctx context.Context,
ignoredNodes[ignoreVertex] = struct{}{}
}
ignoredEdges := make(map[routing.EdgeLocator]struct{})
ignoredPairs := make(map[routing.DirectedNodePair]struct{})
// Convert deprecated ignoredEdges to pairs.
for _, ignoredEdge := range in.IgnoredEdges {
locator := routing.EdgeLocator{
ChannelID: ignoredEdge.ChannelId,
pair, err := r.rpcEdgeToPair(ignoredEdge)
if err != nil {
log.Warnf("Ignore channel %v skipped: %v",
ignoredEdge.ChannelId, err)
continue
}
if ignoredEdge.DirectionReverse {
locator.Direction = 1
ignoredPairs[pair] = struct{}{}
}
// Add ignored pairs to set.
for _, ignorePair := range in.IgnoredPairs {
from, err := route.NewVertexFromBytes(ignorePair.From)
if err != nil {
return nil, err
}
ignoredEdges[locator] = struct{}{}
to, err := route.NewVertexFromBytes(ignorePair.To)
if err != nil {
return nil, err
}
pair := routing.NewDirectedNodePair(from, to)
ignoredPairs[pair] = struct{}{}
}
restrictions := &routing.RestrictParams{
FeeLimit: feeLimit,
ProbabilitySource: func(node route.Vertex,
edge routing.EdgeLocator,
ProbabilitySource: func(fromNode, toNode route.Vertex,
amt lnwire.MilliSatoshi) float64 {
if _, ok := ignoredNodes[node]; ok {
if _, ok := ignoredNodes[fromNode]; ok {
return 0
}
if _, ok := ignoredEdges[edge]; ok {
pair := routing.DirectedNodePair{
From: fromNode,
To: toNode,
}
if _, ok := ignoredPairs[pair]; ok {
return 0
}
@@ -162,8 +184,8 @@ func (r *RouterBackend) QueryRoutes(ctx context.Context,
return 1
}
return r.MissionControl.GetEdgeProbability(
node, edge, amt,
return r.MissionControl.GetProbability(
fromNode, toNode, amt,
)
},
}
@@ -202,6 +224,26 @@ func (r *RouterBackend) QueryRoutes(ctx context.Context,
return routeResp, nil
}
// rpcEdgeToPair looks up the provided channel and returns the channel endpoints
// as a directed pair.
func (r *RouterBackend) rpcEdgeToPair(e *lnrpc.EdgeLocator) (
routing.DirectedNodePair, error) {
a, b, err := r.FetchChannelEndpoints(e.ChannelId)
if err != nil {
return routing.DirectedNodePair{}, err
}
var pair routing.DirectedNodePair
if e.DirectionReverse {
pair.From, pair.To = b, a
} else {
pair.From, pair.To = a, b
}
return pair, nil
}
// calculateFeeLimit returns the fee limit in millisatoshis. If a percentage
// based fee limit has been requested, we'll factor in the ratio provided with
// the amount of the payment.