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:
Joost Jager committed 2018-10-13 22:59:23 +02:00
1 parent e5b84cfada
commit a779004a18
6 files changed
+269 -276

No files matched your search

+54 -39
View File
@@ -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
}