mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-03-28 10:41:57 +01:00
routing+lnrpc: add missing query routes parameters
This commit is contained in:
parent
9c577f3f57
commit
81bf6e15b3
@ -45,6 +45,7 @@ type RouterBackend struct {
|
||||
FindRoute func(source, target route.Vertex,
|
||||
amt lnwire.MilliSatoshi, restrictions *routing.RestrictParams,
|
||||
destCustomRecords record.CustomSet,
|
||||
routeHints map[route.Vertex][]*channeldb.ChannelEdgePolicy,
|
||||
finalExpiry ...uint16) (*route.Route, error)
|
||||
|
||||
MissionControl MissionControl
|
||||
@ -199,6 +200,12 @@ func (r *RouterBackend) QueryRoutes(ctx context.Context,
|
||||
}
|
||||
cltvLimit -= uint32(finalCLTVDelta)
|
||||
|
||||
// Parse destination feature bits.
|
||||
features, err := UnmarshalFeatures(in.DestFeatures)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
restrictions := &routing.RestrictParams{
|
||||
FeeLimit: feeLimit,
|
||||
ProbabilitySource: func(fromNode, toNode route.Vertex,
|
||||
@ -226,6 +233,23 @@ func (r *RouterBackend) QueryRoutes(ctx context.Context,
|
||||
},
|
||||
DestCustomRecords: record.CustomSet(in.DestCustomRecords),
|
||||
CltvLimit: cltvLimit,
|
||||
DestFeatures: features,
|
||||
}
|
||||
|
||||
// Pass along an outgoing channel restriction if specified.
|
||||
if in.OutgoingChanId != 0 {
|
||||
restrictions.OutgoingChannelID = &in.OutgoingChanId
|
||||
}
|
||||
|
||||
// Pass along a last hop restriction if specified.
|
||||
if len(in.LastHopPubkey) > 0 {
|
||||
lastHop, err := route.NewVertexFromBytes(
|
||||
in.LastHopPubkey,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
restrictions.LastHop = &lastHop
|
||||
}
|
||||
|
||||
// If we have any TLV records destined for the final hop, then we'll
|
||||
@ -236,12 +260,24 @@ func (r *RouterBackend) QueryRoutes(ctx context.Context,
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Convert route hints to an edge map.
|
||||
routeHints, err := unmarshallRouteHints(in.RouteHints)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
routeHintEdges, err := routing.RouteHintsToEdges(
|
||||
routeHints, targetPubKey,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 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(
|
||||
sourcePubKey, targetPubKey, amt, restrictions,
|
||||
customRecords, finalCLTVDelta,
|
||||
customRecords, routeHintEdges, finalCLTVDelta,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
"github.com/lightningnetwork/lnd/record"
|
||||
"github.com/lightningnetwork/lnd/routing"
|
||||
@ -18,6 +19,7 @@ import (
|
||||
const (
|
||||
destKey = "0286098b97bc843372b4426d4b276cea9aa2f48f0428d6f5b66ae101befc14f8b4"
|
||||
ignoreNodeKey = "02f274f48f3c0d590449a6776e3ce8825076ac376e470e992246eebc565ef8bb2a"
|
||||
hintNodeKey = "0274e7fb33eafd74fe1acb6db7680bb4aa78e9c839a6e954e38abfad680f645ef7"
|
||||
|
||||
testMissionControlProb = 0.5
|
||||
)
|
||||
@ -58,6 +60,27 @@ func testQueryRoutes(t *testing.T, useMissionControl bool, useMsat bool) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var (
|
||||
lastHop = route.Vertex{64}
|
||||
outgoingChan = uint64(383322)
|
||||
)
|
||||
|
||||
hintNode, err := route.NewVertexFromStr(hintNodeKey)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
rpcRouteHints := []*lnrpc.RouteHint{
|
||||
{
|
||||
HopHints: []*lnrpc.HopHint{
|
||||
{
|
||||
ChanId: 38484,
|
||||
NodeId: hintNodeKey,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
request := &lnrpc.QueryRoutesRequest{
|
||||
PubKey: destKey,
|
||||
FinalCltvDelta: 100,
|
||||
@ -71,6 +94,10 @@ func testQueryRoutes(t *testing.T, useMissionControl bool, useMsat bool) {
|
||||
To: node2[:],
|
||||
}},
|
||||
UseMissionControl: useMissionControl,
|
||||
LastHopPubkey: lastHop[:],
|
||||
OutgoingChanId: outgoingChan,
|
||||
DestFeatures: []lnrpc.FeatureBit{lnrpc.FeatureBit_MPP_OPT},
|
||||
RouteHints: rpcRouteHints,
|
||||
}
|
||||
|
||||
amtSat := int64(100000)
|
||||
@ -93,6 +120,7 @@ func testQueryRoutes(t *testing.T, useMissionControl bool, useMsat bool) {
|
||||
findRoute := func(source, target route.Vertex,
|
||||
amt lnwire.MilliSatoshi, restrictions *routing.RestrictParams,
|
||||
_ record.CustomSet,
|
||||
routeHints map[route.Vertex][]*channeldb.ChannelEdgePolicy,
|
||||
finalExpiry ...uint16) (*route.Route, error) {
|
||||
|
||||
if int64(amt) != amtSat*1000 {
|
||||
@ -127,6 +155,22 @@ func testQueryRoutes(t *testing.T, useMissionControl bool, useMsat bool) {
|
||||
t.Fatal("expecting 0% probability for ignored pair")
|
||||
}
|
||||
|
||||
if *restrictions.LastHop != lastHop {
|
||||
t.Fatal("unexpected last hop")
|
||||
}
|
||||
|
||||
if *restrictions.OutgoingChannelID != outgoingChan {
|
||||
t.Fatal("unexpected outgoing channel id")
|
||||
}
|
||||
|
||||
if !restrictions.DestFeatures.HasFeature(lnwire.MPPOptional) {
|
||||
t.Fatal("unexpected dest features")
|
||||
}
|
||||
|
||||
if _, ok := routeHints[hintNode]; !ok {
|
||||
t.Fatal("expected route hint")
|
||||
}
|
||||
|
||||
expectedProb := 1.0
|
||||
if useMissionControl {
|
||||
expectedProb = testMissionControlProb
|
||||
|
@ -260,7 +260,7 @@ func (s *Server) EstimateRouteFee(ctx context.Context,
|
||||
&routing.RestrictParams{
|
||||
FeeLimit: feeLimit,
|
||||
CltvLimit: s.cfg.RouterBackend.MaxTotalTimelock,
|
||||
}, nil,
|
||||
}, nil, nil,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
1280
lnrpc/rpc.pb.go
1280
lnrpc/rpc.pb.go
File diff suppressed because it is too large
Load Diff
@ -2046,6 +2046,31 @@ message QueryRoutesRequest {
|
||||
REST, the values must be encoded as base64.
|
||||
*/
|
||||
map<uint64, bytes> dest_custom_records = 13;
|
||||
|
||||
/**
|
||||
The channel id of the channel that must be taken to the first hop. If zero,
|
||||
any channel may be used.
|
||||
*/
|
||||
uint64 outgoing_chan_id = 14 [jstype = JS_STRING];
|
||||
|
||||
/**
|
||||
The pubkey of the last hop of the route. If empty, any hop may be used.
|
||||
*/
|
||||
bytes last_hop_pubkey = 15;
|
||||
|
||||
/**
|
||||
Optional route hints to reach the destination through private channels.
|
||||
*/
|
||||
repeated lnrpc.RouteHint route_hints = 16;
|
||||
|
||||
/**
|
||||
Features assumed to be supported by the final node. All transitive feature
|
||||
depdencies must also be set properly. For a given feature bit pair, either
|
||||
optional or remote may be set, but not both. If this field is nil or empty,
|
||||
the router will try to load destination features from the graph as a
|
||||
fallback.
|
||||
*/
|
||||
repeated lnrpc.FeatureBit dest_features = 17;
|
||||
}
|
||||
|
||||
message NodePair {
|
||||
|
@ -812,6 +812,52 @@
|
||||
"required": false,
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
{
|
||||
"name": "outgoing_chan_id",
|
||||
"description": "*\nThe channel id of the channel that must be taken to the first hop. If zero,\nany channel may be used.",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string",
|
||||
"format": "uint64"
|
||||
},
|
||||
{
|
||||
"name": "last_hop_pubkey",
|
||||
"description": "*\nThe pubkey of the last hop of the route. If empty, any hop may be used.",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string",
|
||||
"format": "byte"
|
||||
},
|
||||
{
|
||||
"name": "dest_features",
|
||||
"description": "*\nFeatures assumed to be supported by the final node. All transitive feature\ndepdencies must also be set properly. For a given feature bit pair, either\noptional or remote may be set, but not both. If this field is nil or empty,\nthe router will try to load destination features from the graph as a\nfallback.",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"DATALOSS_PROTECT_REQ",
|
||||
"DATALOSS_PROTECT_OPT",
|
||||
"INITIAL_ROUING_SYNC",
|
||||
"UPFRONT_SHUTDOWN_SCRIPT_REQ",
|
||||
"UPFRONT_SHUTDOWN_SCRIPT_OPT",
|
||||
"GOSSIP_QUERIES_REQ",
|
||||
"GOSSIP_QUERIES_OPT",
|
||||
"TLV_ONION_REQ",
|
||||
"TLV_ONION_OPT",
|
||||
"EXT_GOSSIP_QUERIES_REQ",
|
||||
"EXT_GOSSIP_QUERIES_OPT",
|
||||
"STATIC_REMOTE_KEY_REQ",
|
||||
"STATIC_REMOTE_KEY_OPT",
|
||||
"PAYMENT_ADDR_REQ",
|
||||
"PAYMENT_ADDR_OPT",
|
||||
"MPP_REQ",
|
||||
"MPP_OPT"
|
||||
]
|
||||
},
|
||||
"collectionFormat": "multi"
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
|
@ -2109,7 +2109,7 @@ func TestPathFindSpecExample(t *testing.T) {
|
||||
carol := ctx.aliases["C"]
|
||||
const amt lnwire.MilliSatoshi = 4999999
|
||||
route, err := ctx.router.FindRoute(
|
||||
bobNode.PubKeyBytes, carol, amt, noRestrictions, nil,
|
||||
bobNode.PubKeyBytes, carol, amt, noRestrictions, nil, nil,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to find route: %v", err)
|
||||
@ -2164,7 +2164,7 @@ func TestPathFindSpecExample(t *testing.T) {
|
||||
|
||||
// We'll now request a route from A -> B -> C.
|
||||
route, err = ctx.router.FindRoute(
|
||||
source.PubKeyBytes, carol, amt, noRestrictions, nil,
|
||||
source.PubKeyBytes, carol, amt, noRestrictions, nil, nil,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to find routes: %v", err)
|
||||
|
@ -1402,6 +1402,7 @@ type routingMsg struct {
|
||||
func (r *ChannelRouter) FindRoute(source, target route.Vertex,
|
||||
amt lnwire.MilliSatoshi, restrictions *RestrictParams,
|
||||
destCustomRecords record.CustomSet,
|
||||
routeHints map[route.Vertex][]*channeldb.ChannelEdgePolicy,
|
||||
finalExpiry ...uint16) (*route.Route, error) {
|
||||
|
||||
var finalCLTVDelta uint16
|
||||
@ -1444,8 +1445,9 @@ func (r *ChannelRouter) FindRoute(source, target route.Vertex,
|
||||
|
||||
path, err := findPath(
|
||||
&graphParams{
|
||||
graph: r.cfg.Graph,
|
||||
bandwidthHints: bandwidthHints,
|
||||
graph: r.cfg.Graph,
|
||||
bandwidthHints: bandwidthHints,
|
||||
additionalEdges: routeHints,
|
||||
},
|
||||
restrictions, &r.cfg.PathFindingConfig,
|
||||
source, target, amt, finalHtlcExpiry,
|
||||
|
@ -227,7 +227,7 @@ func TestFindRoutesWithFeeLimit(t *testing.T) {
|
||||
|
||||
route, err := ctx.router.FindRoute(
|
||||
ctx.router.selfNode.PubKeyBytes,
|
||||
target, paymentAmt, restrictions, nil,
|
||||
target, paymentAmt, restrictions, nil, nil,
|
||||
zpay32.DefaultFinalCLTVDelta,
|
||||
)
|
||||
if err != nil {
|
||||
@ -1269,7 +1269,7 @@ func TestAddEdgeUnknownVertexes(t *testing.T) {
|
||||
copy(targetPubKeyBytes[:], targetNode.SerializeCompressed())
|
||||
_, err = ctx.router.FindRoute(
|
||||
ctx.router.selfNode.PubKeyBytes,
|
||||
targetPubKeyBytes, paymentAmt, noRestrictions, nil,
|
||||
targetPubKeyBytes, paymentAmt, noRestrictions, nil, nil,
|
||||
zpay32.DefaultFinalCLTVDelta,
|
||||
)
|
||||
if err != nil {
|
||||
@ -1312,7 +1312,7 @@ func TestAddEdgeUnknownVertexes(t *testing.T) {
|
||||
// updated.
|
||||
_, err = ctx.router.FindRoute(
|
||||
ctx.router.selfNode.PubKeyBytes,
|
||||
targetPubKeyBytes, paymentAmt, noRestrictions, nil,
|
||||
targetPubKeyBytes, paymentAmt, noRestrictions, nil, nil,
|
||||
zpay32.DefaultFinalCLTVDelta,
|
||||
)
|
||||
if err != nil {
|
||||
|
Loading…
x
Reference in New Issue
Block a user