lnrpc: add additional REST binding for QueryRoutes

Lists with non-primitive members aren't supported in the query string of
a GET request with the current version of the grpc-gateway library. To
allow route_hints to be set through REST, we also offer a POST endpoint
for that call where the encoding of the request parameter can be
specified as JSON.
This commit is contained in:
Oliver Gugger 2022-09-19 10:18:34 +02:00
parent 202fcd6672
commit 01cd1c991e
No known key found for this signature in database
GPG key ID: 8E4256593F177720
3 changed files with 273 additions and 0 deletions

View file

@ -1713,6 +1713,94 @@ func local_request_Lightning_QueryRoutes_0(ctx context.Context, marshaler runtim
}
func request_Lightning_QueryRoutes_1(ctx context.Context, marshaler runtime.Marshaler, client LightningClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq QueryRoutesRequest
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["pub_key"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "pub_key")
}
protoReq.PubKey, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "pub_key", err)
}
val, ok = pathParams["amt"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "amt")
}
protoReq.Amt, err = runtime.Int64(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "amt", err)
}
msg, err := client.QueryRoutes(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Lightning_QueryRoutes_1(ctx context.Context, marshaler runtime.Marshaler, server LightningServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq QueryRoutesRequest
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["pub_key"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "pub_key")
}
protoReq.PubKey, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "pub_key", err)
}
val, ok = pathParams["amt"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "amt")
}
protoReq.Amt, err = runtime.Int64(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "amt", err)
}
msg, err := server.QueryRoutes(ctx, &protoReq)
return msg, metadata, err
}
func request_Lightning_GetNetworkInfo_0(ctx context.Context, marshaler runtime.Marshaler, client LightningClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq NetworkInfoRequest
var metadata runtime.ServerMetadata
@ -3262,6 +3350,29 @@ func RegisterLightningHandlerServer(ctx context.Context, mux *runtime.ServeMux,
})
mux.Handle("POST", pattern_Lightning_QueryRoutes_1, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/lnrpc.Lightning/QueryRoutes", runtime.WithHTTPPathPattern("/v1/graph/routes/{pub_key}/{amt}"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Lightning_QueryRoutes_1(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Lightning_QueryRoutes_1(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Lightning_GetNetworkInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
@ -4602,6 +4713,26 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux,
})
mux.Handle("POST", pattern_Lightning_QueryRoutes_1, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req, "/lnrpc.Lightning/QueryRoutes", runtime.WithHTTPPathPattern("/v1/graph/routes/{pub_key}/{amt}"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Lightning_QueryRoutes_1(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Lightning_QueryRoutes_1(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Lightning_GetNetworkInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
@ -5114,6 +5245,8 @@ var (
pattern_Lightning_QueryRoutes_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 1, 0, 4, 1, 5, 4}, []string{"v1", "graph", "routes", "pub_key", "amt"}, ""))
pattern_Lightning_QueryRoutes_1 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 1, 0, 4, 1, 5, 4}, []string{"v1", "graph", "routes", "pub_key", "amt"}, ""))
pattern_Lightning_GetNetworkInfo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "graph", "info"}, ""))
pattern_Lightning_StopDaemon_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "stop"}, ""))
@ -5246,6 +5379,8 @@ var (
forward_Lightning_QueryRoutes_0 = runtime.ForwardResponseMessage
forward_Lightning_QueryRoutes_1 = runtime.ForwardResponseMessage
forward_Lightning_GetNetworkInfo_0 = runtime.ForwardResponseMessage
forward_Lightning_StopDaemon_0 = runtime.ForwardResponseMessage

View file

@ -1424,6 +1424,141 @@
"tags": [
"Lightning"
]
},
"post": {
"summary": "lncli: `queryroutes`\nQueryRoutes attempts to query the daemon's Channel Router for a possible\nroute to a target destination capable of carrying a specific amount of\nsatoshis. The returned route contains the full details required to craft and\nsend an HTLC, also including the necessary information that should be\npresent within the Sphinx packet encapsulated within the HTLC.",
"description": "When using REST, the `dest_custom_records` map type can be set by appending\n`\u0026dest_custom_records[\u003crecord_number\u003e]=\u003crecord_data_base64_url_encoded\u003e`\nto the URL. Unfortunately this map type doesn't appear in the REST API\ndocumentation because of a bug in the grpc-gateway library.",
"operationId": "Lightning_QueryRoutes2",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/lnrpcQueryRoutesResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/rpcStatus"
}
}
},
"parameters": [
{
"name": "pub_key",
"description": "The 33-byte hex-encoded public key for the payment destination",
"in": "path",
"required": true,
"type": "string"
},
{
"name": "amt",
"description": "The amount to send expressed in satoshis.\n\nThe fields amt and amt_msat are mutually exclusive.",
"in": "path",
"required": true,
"type": "string",
"format": "int64"
},
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"type": "object",
"properties": {
"amt_msat": {
"type": "string",
"format": "int64",
"description": "The amount to send expressed in millisatoshis.\n\nThe fields amt and amt_msat are mutually exclusive."
},
"final_cltv_delta": {
"type": "integer",
"format": "int32",
"description": "An optional CLTV delta from the current height that should be used for the\ntimelock of the final hop. Note that unlike SendPayment, QueryRoutes does\nnot add any additional block padding on top of final_ctlv_delta. This\npadding of a few blocks needs to be added manually or otherwise failures may\nhappen when a block comes in while the payment is in flight."
},
"fee_limit": {
"$ref": "#/definitions/lnrpcFeeLimit",
"description": "The maximum number of satoshis that will be paid as a fee of the payment.\nThis value can be represented either as a percentage of the amount being\nsent, or as a fixed amount of the maximum fee the user is willing the pay to\nsend the payment. If not specified, lnd will use a default value of 100%\nfees for small amounts (\u003c=1k sat) or 5% fees for larger amounts."
},
"ignored_nodes": {
"type": "array",
"items": {
"type": "string",
"format": "byte"
},
"description": "A list of nodes to ignore during path finding. When using REST, these fields\nmust be encoded as base64."
},
"ignored_edges": {
"type": "array",
"items": {
"$ref": "#/definitions/lnrpcEdgeLocator"
},
"description": "Deprecated. A list of edges to ignore during path finding."
},
"source_pub_key": {
"type": "string",
"description": "The source node where the request route should originated from. If empty,\nself is assumed."
},
"use_mission_control": {
"type": "boolean",
"description": "If set to true, edge probabilities from mission control will be used to get\nthe optimal route."
},
"ignored_pairs": {
"type": "array",
"items": {
"$ref": "#/definitions/lnrpcNodePair"
},
"description": "A list of directed node pairs that will be ignored during path finding."
},
"cltv_limit": {
"type": "integer",
"format": "int64",
"description": "An optional maximum total time lock for the route. If the source is empty or\nourselves, this should not exceed lnd's `--max-cltv-expiry` setting. If\nzero, then the value of `--max-cltv-expiry` is used as the limit."
},
"dest_custom_records": {
"type": "object",
"additionalProperties": {
"type": "string",
"format": "byte"
},
"description": "An optional field that can be used to pass an arbitrary set of TLV records\nto a peer which understands the new records. This can be used to pass\napplication specific data during the payment attempt. If the destination\ndoes not support the specified records, an error will be returned.\nRecord types are required to be in the custom range \u003e= 65536. When using\nREST, the values must be encoded as base64."
},
"outgoing_chan_id": {
"type": "string",
"format": "uint64",
"description": "The channel id of the channel that must be taken to the first hop. If zero,\nany channel may be used."
},
"last_hop_pubkey": {
"type": "string",
"format": "byte",
"description": "The pubkey of the last hop of the route. If empty, any hop may be used."
},
"route_hints": {
"type": "array",
"items": {
"$ref": "#/definitions/lnrpcRouteHint"
},
"description": "Optional route hints to reach the destination through private channels."
},
"dest_features": {
"type": "array",
"items": {
"$ref": "#/definitions/lnrpcFeatureBit"
},
"description": "Features assumed to be supported by the final node. All transitive feature\ndependencies 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."
},
"time_pref": {
"type": "number",
"format": "double",
"description": "The time preference for this payment. Set to -1 to optimize for fees\nonly, to 1 to optimize for reliability only or a value inbetween for a mix."
}
}
}
}
],
"tags": [
"Lightning"
]
}
},
"/v1/graph/subscribe": {

View file

@ -111,6 +111,9 @@ http:
get: "/v1/graph/node/{pub_key}"
- selector: lnrpc.Lightning.QueryRoutes
get: "/v1/graph/routes/{pub_key}/{amt}"
additional_bindings:
- post: "/v1/graph/routes/{pub_key}/{amt}"
body: "*"
- selector: lnrpc.Lightning.GetNetworkInfo
get: "/v1/graph/info"
- selector: lnrpc.Lightning.StopDaemon