mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-01-18 21:35:24 +01:00
routing+routerrpc: add capacity in rpcs
FetchPairCapacity is used by the following endpoints to introduce the capacity for probability calculations: * QueryProbability * QueryRoutes
This commit is contained in:
parent
66ffc64776
commit
454c115b6e
@ -45,6 +45,11 @@ type RouterBackend struct {
|
||||
// capacity of a channel to populate in responses.
|
||||
FetchChannelCapacity func(chanID uint64) (btcutil.Amount, error)
|
||||
|
||||
// FetchAmountPairCapacity determines the maximal channel capacity
|
||||
// between two nodes given a certain amount.
|
||||
FetchAmountPairCapacity func(nodeFrom, nodeTo route.Vertex,
|
||||
amount lnwire.MilliSatoshi) (btcutil.Amount, error)
|
||||
|
||||
// FetchChannelEndpoints returns the pubkeys of both endpoints of the
|
||||
// given channel id.
|
||||
FetchChannelEndpoints func(chanID uint64) (route.Vertex,
|
||||
@ -325,7 +330,7 @@ func (r *RouterBackend) QueryRoutes(ctx context.Context,
|
||||
// Query the channel router for a possible path to the destination that
|
||||
// can carry `in.Amt` satoshis _including_ the total fee required on
|
||||
// the route.
|
||||
route, _, err := r.FindRoute(
|
||||
route, successProb, err := r.FindRoute(
|
||||
sourcePubKey, targetPubKey, amt, in.TimePref, restrictions,
|
||||
customRecords, routeHintEdges, finalCLTVDelta,
|
||||
)
|
||||
@ -340,11 +345,6 @@ func (r *RouterBackend) QueryRoutes(ctx context.Context,
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Calculate route success probability. Do not rely on a probability
|
||||
// that could have been returned from path finding, because mission
|
||||
// control may have been disabled in the provided ProbabilitySource.
|
||||
successProb := r.getSuccessProbability(route)
|
||||
|
||||
routeResp := &lnrpc.QueryRoutesResponse{
|
||||
Routes: []*lnrpc.Route{rpcRoute},
|
||||
SuccessProb: successProb,
|
||||
@ -353,28 +353,6 @@ func (r *RouterBackend) QueryRoutes(ctx context.Context,
|
||||
return routeResp, nil
|
||||
}
|
||||
|
||||
// getSuccessProbability returns the success probability for the given route
|
||||
// based on the current state of mission control.
|
||||
func (r *RouterBackend) getSuccessProbability(rt *route.Route) float64 {
|
||||
fromNode := rt.SourcePubKey
|
||||
amtToFwd := rt.TotalAmount
|
||||
successProb := 1.0
|
||||
for _, hop := range rt.Hops {
|
||||
toNode := hop.PubKeyBytes
|
||||
|
||||
probability := r.MissionControl.GetProbability(
|
||||
fromNode, toNode, amtToFwd, 0,
|
||||
)
|
||||
|
||||
successProb *= probability
|
||||
|
||||
amtToFwd = hop.AmtToForward
|
||||
fromNode = toNode
|
||||
}
|
||||
|
||||
return successProb
|
||||
}
|
||||
|
||||
// rpcEdgeToPair looks up the provided channel and returns the channel endpoints
|
||||
// as a directed pair.
|
||||
func (r *RouterBackend) rpcEdgeToPair(e *lnrpc.EdgeLocator) (
|
||||
|
@ -200,6 +200,11 @@ func testQueryRoutes(t *testing.T, useMissionControl bool, useMsat bool,
|
||||
|
||||
return 1, nil
|
||||
},
|
||||
FetchAmountPairCapacity: func(nodeFrom, nodeTo route.Vertex,
|
||||
amount lnwire.MilliSatoshi) (btcutil.Amount, error) {
|
||||
|
||||
return 1, nil
|
||||
},
|
||||
MissionControl: &mockMissionControl{},
|
||||
FetchChannelEndpoints: func(chanID uint64) (route.Vertex,
|
||||
route.Vertex, error) {
|
||||
|
@ -709,8 +709,22 @@ func (s *Server) QueryProbability(ctx context.Context,
|
||||
|
||||
amt := lnwire.MilliSatoshi(req.AmtMsat)
|
||||
|
||||
// Compute the probability.
|
||||
var prob float64
|
||||
mc := s.cfg.RouterBackend.MissionControl
|
||||
prob := mc.GetProbability(fromNode, toNode, amt, 0)
|
||||
capacity, err := s.cfg.RouterBackend.FetchAmountPairCapacity(
|
||||
fromNode, toNode, amt,
|
||||
)
|
||||
|
||||
// If we cannot query the capacity this means that either we don't have
|
||||
// information available or that the channel fails min/maxHtlc
|
||||
// constraints, so we return a zero probability.
|
||||
if err != nil {
|
||||
log.Errorf("Cannot fetch capacity: %v", err)
|
||||
} else {
|
||||
prob = mc.GetProbability(fromNode, toNode, amt, capacity)
|
||||
}
|
||||
|
||||
history := mc.GetPairHistorySnapshot(fromNode, toNode)
|
||||
|
||||
return &QueryProbabilityResponse{
|
||||
|
@ -111,7 +111,7 @@ func testRestAPI(net *lntest.NetworkHarness, ht *harnessTest) {
|
||||
resp := &routerrpc.QueryProbabilityResponse{}
|
||||
err := invokeGET(a, url, resp)
|
||||
require.Nil(t, err, "query probability")
|
||||
assert.Greater(t, resp.Probability, 0.5, "probability")
|
||||
require.Zero(t, resp.Probability)
|
||||
},
|
||||
}, {
|
||||
name: "GET with map type query param",
|
||||
|
@ -1,6 +1,9 @@
|
||||
package routing
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/btcsuite/btcd/btcutil"
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/kvdb"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
@ -20,6 +23,11 @@ type routingGraph interface {
|
||||
|
||||
// fetchNodeFeatures returns the features of the given node.
|
||||
fetchNodeFeatures(nodePub route.Vertex) (*lnwire.FeatureVector, error)
|
||||
|
||||
// FetchAmountPairCapacity determines the maximal capacity between two
|
||||
// pairs of nodes.
|
||||
FetchAmountPairCapacity(nodeFrom, nodeTo route.Vertex,
|
||||
amount lnwire.MilliSatoshi) (btcutil.Amount, error)
|
||||
}
|
||||
|
||||
// CachedGraph is a routingGraph implementation that retrieves from the
|
||||
@ -51,9 +59,9 @@ func NewCachedGraph(sourceNode *channeldb.LightningNode,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// close attempts to close the underlying db transaction. This is a no-op in
|
||||
// Close attempts to close the underlying db transaction. This is a no-op in
|
||||
// case the underlying graph uses an in-memory cache.
|
||||
func (g *CachedGraph) close() error {
|
||||
func (g *CachedGraph) Close() error {
|
||||
if g.tx == nil {
|
||||
return nil
|
||||
}
|
||||
@ -86,3 +94,33 @@ func (g *CachedGraph) fetchNodeFeatures(nodePub route.Vertex) (
|
||||
|
||||
return g.graph.FetchNodeFeatures(nodePub)
|
||||
}
|
||||
|
||||
// FetchAmountPairCapacity determines the maximal public capacity between two
|
||||
// nodes depending on the amount we try to send.
|
||||
//
|
||||
// NOTE: Part of the routingGraph interface.
|
||||
func (g *CachedGraph) FetchAmountPairCapacity(nodeFrom, nodeTo route.Vertex,
|
||||
amount lnwire.MilliSatoshi) (btcutil.Amount, error) {
|
||||
|
||||
// Create unified edges for all incoming connections.
|
||||
u := newNodeEdgeUnifier(g.sourceNode(), nodeTo, nil)
|
||||
|
||||
err := u.addGraphPolicies(g)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
edgeUnifier, ok := u.edgeUnifiers[nodeFrom]
|
||||
if !ok {
|
||||
return 0, fmt.Errorf("no edge info for node pair %v -> %v",
|
||||
nodeFrom, nodeTo)
|
||||
}
|
||||
|
||||
edge := edgeUnifier.getEdgeNetwork(amount)
|
||||
if edge == nil {
|
||||
return 0, fmt.Errorf("no edge for node pair %v -> %v "+
|
||||
"(amount %v)", nodeFrom, nodeTo, amount)
|
||||
}
|
||||
|
||||
return edge.capacity, nil
|
||||
}
|
||||
|
@ -226,6 +226,31 @@ func (m *mockGraph) fetchNodeFeatures(nodePub route.Vertex) (
|
||||
return lnwire.EmptyFeatureVector(), nil
|
||||
}
|
||||
|
||||
// FetchAmountPairCapacity returns the maximal capacity between nodes in the
|
||||
// graph.
|
||||
//
|
||||
// NOTE: Part of the routingGraph interface.
|
||||
func (m *mockGraph) FetchAmountPairCapacity(nodeFrom, nodeTo route.Vertex,
|
||||
amount lnwire.MilliSatoshi) (btcutil.Amount, error) {
|
||||
|
||||
var capacity btcutil.Amount
|
||||
|
||||
cb := func(channel *channeldb.DirectedChannel) error {
|
||||
if channel.OtherNode == nodeTo {
|
||||
capacity = channel.Capacity
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
err := m.forEachNodeChannel(nodeFrom, cb)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return capacity, nil
|
||||
}
|
||||
|
||||
// htlcResult describes the resolution of an htlc. If failure is nil, the htlc
|
||||
// was settled.
|
||||
type htlcResult struct {
|
||||
|
@ -3112,7 +3112,7 @@ func dbFindPath(graph *channeldb.ChannelGraph,
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err := routingGraph.close(); err != nil {
|
||||
if err := routingGraph.Close(); err != nil {
|
||||
log.Errorf("Error closing db tx: %v", err)
|
||||
}
|
||||
}()
|
||||
|
@ -51,7 +51,7 @@ func (m *SessionSource) getRoutingGraph() (routingGraph, func(), error) {
|
||||
return nil, nil, err
|
||||
}
|
||||
return routingTx, func() {
|
||||
err := routingTx.close()
|
||||
err := routingTx.Close()
|
||||
if err != nil {
|
||||
log.Errorf("Error closing db tx: %v", err)
|
||||
}
|
||||
|
23
rpcserver.go
23
rpcserver.go
@ -689,6 +689,7 @@ func (r *rpcServer) addDeps(s *server, macService *macaroons.Service,
|
||||
return err
|
||||
}
|
||||
graph := s.graphDB
|
||||
|
||||
routerBackend := &routerrpc.RouterBackend{
|
||||
SelfNode: selfNode.PubKeyBytes,
|
||||
FetchChannelCapacity: func(chanID uint64) (btcutil.Amount,
|
||||
@ -700,6 +701,28 @@ func (r *rpcServer) addDeps(s *server, macService *macaroons.Service,
|
||||
}
|
||||
return info.Capacity, nil
|
||||
},
|
||||
FetchAmountPairCapacity: func(nodeFrom, nodeTo route.Vertex,
|
||||
amount lnwire.MilliSatoshi) (btcutil.Amount, error) {
|
||||
|
||||
routingGraph, err := routing.NewCachedGraph(
|
||||
selfNode, graph,
|
||||
)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer func() {
|
||||
closeErr := routingGraph.Close()
|
||||
if closeErr != nil {
|
||||
rpcsLog.Errorf("not able to close "+
|
||||
"routing graph tx: %v",
|
||||
closeErr)
|
||||
}
|
||||
}()
|
||||
|
||||
return routingGraph.FetchAmountPairCapacity(
|
||||
nodeFrom, nodeTo, amount,
|
||||
)
|
||||
},
|
||||
FetchChannelEndpoints: func(chanID uint64) (route.Vertex,
|
||||
route.Vertex, error) {
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user