lnrpc+routing: fix issues with missing data in unmarshallRoute
In this commit the dependency of unmarshallRoute on edge policies being available is removed. Edge policies may be unknown and reported as nil. SendToRoute does not need the policies, but it does need pubkeys of the route hops. In this commit, unmarshallRoute is modified so that it takes the pubkeys from edgeInfo instead of channelEdgePolicy. In addition to this, the route structure is simplified. No more connection to the database at that point. Fees are determined based on incoming and outgoing amounts.
This commit is contained in:
6 files changed
+269
-276
No files matched your search
+54
-39
@@ -1904,7 +1904,7 @@ func (r *rpcServer) savePayment(route *routing.Route,
|
||||
|
||||
paymentPath := make([][33]byte, len(route.Hops))
|
||||
for i, hop := range route.Hops {
|
||||
hopPub := hop.Channel.Node.PubKeyBytes
|
||||
hopPub := hop.PubKeyBytes
|
||||
copy(paymentPath[i][:], hopPub[:])
|
||||
}
|
||||
|
||||
@@ -2014,7 +2014,7 @@ func (r *rpcServer) SendToRoute(stream lnrpc.Lightning_SendToRouteServer) error
|
||||
|
||||
routes := make([]*routing.Route, len(req.Routes))
|
||||
for i, rpcroute := range req.Routes {
|
||||
route, err := unmarshallRoute(rpcroute, graph)
|
||||
route, err := r.unmarshallRoute(rpcroute, graph)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -2419,7 +2419,7 @@ func (r *rpcServer) sendPayment(stream *paymentStream) error {
|
||||
return
|
||||
}
|
||||
|
||||
marshalledRouted := marshallRoute(resp.Route)
|
||||
marshalledRouted := r.marshallRoute(resp.Route)
|
||||
err := stream.send(&lnrpc.SendResponse{
|
||||
PaymentPreimage: resp.Preimage[:],
|
||||
PaymentRoute: marshalledRouted,
|
||||
@@ -2460,7 +2460,7 @@ func (r *rpcServer) SendToRouteSync(ctx context.Context,
|
||||
|
||||
routes := make([]*routing.Route, len(req.Routes))
|
||||
for i, route := range req.Routes {
|
||||
route, err := unmarshallRoute(route, graph)
|
||||
route, err := r.unmarshallRoute(route, graph)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -2510,7 +2510,7 @@ func (r *rpcServer) sendPaymentSync(ctx context.Context,
|
||||
|
||||
return &lnrpc.SendResponse{
|
||||
PaymentPreimage: resp.Preimage[:],
|
||||
PaymentRoute: marshallRoute(resp.Route),
|
||||
PaymentRoute: r.marshallRoute(resp.Route),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -3378,14 +3378,14 @@ func (r *rpcServer) QueryRoutes(ctx context.Context,
|
||||
}
|
||||
for i := int32(0); i < numRoutes; i++ {
|
||||
routeResp.Routes = append(
|
||||
routeResp.Routes, marshallRoute(routes[i]),
|
||||
routeResp.Routes, r.marshallRoute(routes[i]),
|
||||
)
|
||||
}
|
||||
|
||||
return routeResp, nil
|
||||
}
|
||||
|
||||
func marshallRoute(route *routing.Route) *lnrpc.Route {
|
||||
func (r *rpcServer) marshallRoute(route *routing.Route) *lnrpc.Route {
|
||||
resp := &lnrpc.Route{
|
||||
TotalTimeLock: route.TotalTimeLock,
|
||||
TotalFees: int64(route.TotalFees.ToSatoshis()),
|
||||
@@ -3394,72 +3394,87 @@ func marshallRoute(route *routing.Route) *lnrpc.Route {
|
||||
TotalAmtMsat: int64(route.TotalAmount),
|
||||
Hops: make([]*lnrpc.Hop, len(route.Hops)),
|
||||
}
|
||||
graph := r.server.chanDB.ChannelGraph()
|
||||
incomingAmt := route.TotalAmount
|
||||
for i, hop := range route.Hops {
|
||||
fee := route.HopFee(i)
|
||||
|
||||
// Channel capacity is not a defining property of a route. For
|
||||
// backwards RPC compatibility, we retrieve it here from the
|
||||
// graph.
|
||||
var chanCapacity btcutil.Amount
|
||||
info, _, _, err := graph.FetchChannelEdgesByID(hop.ChannelID)
|
||||
if err == nil {
|
||||
chanCapacity = info.Capacity
|
||||
} else {
|
||||
// If capacity cannot be retrieved, this may be a
|
||||
// not-yet-received or private channel. Then report
|
||||
// amount that is sent through the channel as capacity.
|
||||
chanCapacity = incomingAmt.ToSatoshis()
|
||||
}
|
||||
|
||||
resp.Hops[i] = &lnrpc.Hop{
|
||||
ChanId: hop.Channel.ChannelID,
|
||||
ChanCapacity: int64(hop.Channel.Bandwidth.ToSatoshis()),
|
||||
ChanId: hop.ChannelID,
|
||||
ChanCapacity: int64(chanCapacity),
|
||||
AmtToForward: int64(hop.AmtToForward.ToSatoshis()),
|
||||
AmtToForwardMsat: int64(hop.AmtToForward),
|
||||
Fee: int64(hop.Fee.ToSatoshis()),
|
||||
FeeMsat: int64(hop.Fee),
|
||||
Fee: int64(fee.ToSatoshis()),
|
||||
FeeMsat: int64(fee),
|
||||
Expiry: uint32(hop.OutgoingTimeLock),
|
||||
}
|
||||
incomingAmt = hop.AmtToForward
|
||||
}
|
||||
|
||||
return resp
|
||||
}
|
||||
|
||||
func unmarshallRoute(rpcroute *lnrpc.Route,
|
||||
func (r *rpcServer) unmarshallRoute(rpcroute *lnrpc.Route,
|
||||
graph *channeldb.ChannelGraph) (*routing.Route, error) {
|
||||
|
||||
route := &routing.Route{
|
||||
TotalTimeLock: rpcroute.TotalTimeLock,
|
||||
TotalFees: lnwire.MilliSatoshi(rpcroute.TotalFeesMsat),
|
||||
TotalAmount: lnwire.MilliSatoshi(rpcroute.TotalAmtMsat),
|
||||
Hops: make([]*routing.Hop, len(rpcroute.Hops)),
|
||||
}
|
||||
|
||||
node, err := graph.SourceNode()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to fetch source node from graph "+
|
||||
"while unmarshaling route. %v", err)
|
||||
}
|
||||
|
||||
nodePubKeyBytes := node.PubKeyBytes[:]
|
||||
|
||||
hops := make([]*routing.Hop, len(rpcroute.Hops))
|
||||
for i, hop := range rpcroute.Hops {
|
||||
edgeInfo, c1, c2, err := graph.FetchChannelEdgesByID(hop.ChanId)
|
||||
// Discard edge policies, because they may be nil.
|
||||
edgeInfo, _, _, err := graph.FetchChannelEdgesByID(hop.ChanId)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to fetch channel edges by "+
|
||||
"channel ID for hop (%d): %v", i, err)
|
||||
}
|
||||
|
||||
var channelEdgePolicy *channeldb.ChannelEdgePolicy
|
||||
|
||||
var pubKeyBytes [33]byte
|
||||
switch {
|
||||
case bytes.Equal(node.PubKeyBytes[:], c1.Node.PubKeyBytes[:]):
|
||||
channelEdgePolicy = c2
|
||||
node = c2.Node
|
||||
case bytes.Equal(node.PubKeyBytes[:], c2.Node.PubKeyBytes[:]):
|
||||
channelEdgePolicy = c1
|
||||
node = c1.Node
|
||||
case bytes.Equal(nodePubKeyBytes[:], edgeInfo.NodeKey1Bytes[:]):
|
||||
pubKeyBytes = edgeInfo.NodeKey2Bytes
|
||||
case bytes.Equal(nodePubKeyBytes[:], edgeInfo.NodeKey2Bytes[:]):
|
||||
pubKeyBytes = edgeInfo.NodeKey1Bytes
|
||||
default:
|
||||
return nil, fmt.Errorf("could not find channel edge for hop=%d", i)
|
||||
return nil, fmt.Errorf("channel edge does not match expected node")
|
||||
}
|
||||
|
||||
routingHop := &routing.ChannelHop{
|
||||
ChannelEdgePolicy: channelEdgePolicy,
|
||||
Bandwidth: lnwire.NewMSatFromSatoshis(
|
||||
btcutil.Amount(hop.ChanCapacity)),
|
||||
Chain: edgeInfo.ChainHash,
|
||||
}
|
||||
|
||||
route.Hops[i] = &routing.Hop{
|
||||
Channel: routingHop,
|
||||
hops[i] = &routing.Hop{
|
||||
OutgoingTimeLock: hop.Expiry,
|
||||
AmtToForward: lnwire.MilliSatoshi(hop.AmtToForwardMsat),
|
||||
Fee: lnwire.MilliSatoshi(hop.FeeMsat),
|
||||
PubKeyBytes: pubKeyBytes,
|
||||
ChannelID: edgeInfo.ChannelID,
|
||||
}
|
||||
|
||||
nodePubKeyBytes = pubKeyBytes[:]
|
||||
}
|
||||
|
||||
route := routing.NewRouteFromHops(
|
||||
lnwire.MilliSatoshi(rpcroute.TotalAmtMsat),
|
||||
rpcroute.TotalTimeLock,
|
||||
node.PubKeyBytes,
|
||||
hops,
|
||||
)
|
||||
|
||||
return route, nil
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user