routing: consolidate final hop params for newRoute

This commit creates a wrapper struct, grouping all parameters that
influence the final hop during route construction. This is a preliminary
step for passing in the receiver's invoice feature bits, which will be
used to select an appropriate payment or payload type.
This commit is contained in:
Conner Fromknecht 2019-12-18 23:55:08 -08:00
parent 71e05e05bf
commit 495ae8ca42
No known key found for this signature in database
GPG Key ID: E7D737B67FA592C7
4 changed files with 79 additions and 32 deletions

@ -96,17 +96,29 @@ type edgePolicyWithSource struct {
edge *channeldb.ChannelEdgePolicy
}
// newRoute returns a fully valid route between the source and target that's
// capable of supporting a payment of `amtToSend` after fees are fully
// computed. If the route is too long, or the selected path cannot support the
// fully payment including fees, then a non-nil error is returned.
// finalHopParams encapsulates various parameters for route construction that
// apply to the final hop in a route. These features include basic payment data
// such as amounts and cltvs, as well as more complex features like destination
// custom records.
type finalHopParams struct {
amt lnwire.MilliSatoshi
cltvDelta uint16
records record.CustomSet
}
// newRoute constructs a route using the provided path and final hop constraints.
// Any destination specific fields from the final hop params will be attached
// assuming the destination's feature vector signals support, otherwise this
// method will fail. If the route is too long, or the selected path cannot
// support the fully payment including fees, then a non-nil error is returned.
//
// NOTE: The passed slice of ChannelHops MUST be sorted in forward order: from
// the source to the target node of the path finding attempt.
func newRoute(amtToSend lnwire.MilliSatoshi, sourceVertex route.Vertex,
// the source to the target node of the path finding attempt. It is assumed that
// any feature vectors on all hops have been validated for transitive
// dependencies.
func newRoute(sourceVertex route.Vertex,
pathEdges []*channeldb.ChannelEdgePolicy, currentHeight uint32,
finalCLTVDelta uint16,
destCustomRecords record.CustomSet) (*route.Route, error) {
finalHop finalHopParams) (*route.Route, error) {
var (
hops []*route.Hop
@ -132,7 +144,7 @@ func newRoute(amtToSend lnwire.MilliSatoshi, sourceVertex route.Vertex,
// If this is the last hop, then the hop payload will contain
// the exact amount. In BOLT #4: Onion Routing
// Protocol / "Payload for the Last Node", this is detailed.
amtToForward := amtToSend
amtToForward := finalHop.amt
// Fee is not part of the hop payload, but only used for
// reporting through RPC. Set to zero for the final hop.
@ -161,9 +173,9 @@ func newRoute(amtToSend lnwire.MilliSatoshi, sourceVertex route.Vertex,
// As this is the last hop, we'll use the specified
// final CLTV delta value instead of the value from the
// last link in the route.
totalTimeLock += uint32(finalCLTVDelta)
totalTimeLock += uint32(finalHop.cltvDelta)
outgoingTimeLock = currentHeight + uint32(finalCLTVDelta)
outgoingTimeLock = currentHeight + uint32(finalHop.cltvDelta)
} else {
// Next, increment the total timelock of the entire
// route such that each hops time lock increases as we
@ -204,8 +216,8 @@ func newRoute(amtToSend lnwire.MilliSatoshi, sourceVertex route.Vertex,
// If this is the last hop, then we'll populate any TLV records
// destined for it.
if i == len(pathEdges)-1 && len(destCustomRecords) != 0 {
currentHop.CustomRecords = destCustomRecords
if i == len(pathEdges)-1 && len(finalHop.records) != 0 {
currentHop.CustomRecords = finalHop.records
}
hops = append([]*route.Hop{currentHop}, hops...)

@ -680,8 +680,12 @@ func TestFindLowestFeePath(t *testing.T) {
t.Fatalf("unable to find path: %v", err)
}
route, err := newRoute(
paymentAmt, ctx.source, path, startingHeight,
finalHopCLTV, nil,
ctx.source, path, startingHeight,
finalHopParams{
amt: paymentAmt,
cltvDelta: finalHopCLTV,
records: nil,
},
)
if err != nil {
t.Fatalf("unable to create path: %v", err)
@ -830,8 +834,12 @@ func testBasicGraphPathFindingCase(t *testing.T, graphInstance *testGraphInstanc
}
route, err := newRoute(
paymentAmt, sourceVertex, path, startingHeight,
finalHopCLTV, nil,
sourceVertex, path, startingHeight,
finalHopParams{
amt: paymentAmt,
cltvDelta: finalHopCLTV,
records: nil,
},
)
if err != nil {
t.Fatalf("unable to create path: %v", err)
@ -1244,9 +1252,12 @@ func TestNewRoute(t *testing.T) {
t.Run(testCase.name, func(t *testing.T) {
route, err := newRoute(
testCase.paymentAmount, sourceVertex,
testCase.hops, startingHeight, finalHopCLTV,
nil,
sourceVertex, testCase.hops, startingHeight,
finalHopParams{
amt: testCase.paymentAmount,
cltvDelta: finalHopCLTV,
records: nil,
},
)
if testCase.expectError {
@ -2210,8 +2221,12 @@ func TestRestrictOutgoingChannel(t *testing.T) {
t.Fatalf("unable to find path: %v", err)
}
route, err := newRoute(
paymentAmt, ctx.source, path, startingHeight,
finalHopCLTV, nil,
ctx.source, path, startingHeight,
finalHopParams{
amt: paymentAmt,
cltvDelta: finalHopCLTV,
records: nil,
},
)
if err != nil {
t.Fatalf("unable to create path: %v", err)
@ -2336,8 +2351,12 @@ func testCltvLimit(t *testing.T, limit uint32, expectedChannel uint64) {
finalHopCLTV = 1
)
route, err := newRoute(
paymentAmt, ctx.source, path, startingHeight, finalHopCLTV,
nil,
ctx.source, path, startingHeight,
finalHopParams{
amt: paymentAmt,
cltvDelta: finalHopCLTV,
records: nil,
},
)
if err != nil {
t.Fatalf("unable to create path: %v", err)
@ -2623,8 +2642,12 @@ func TestNoCycle(t *testing.T) {
t.Fatalf("unable to find path: %v", err)
}
route, err := newRoute(
paymentAmt, ctx.source, path, startingHeight,
finalHopCLTV, nil,
ctx.source, path, startingHeight,
finalHopParams{
amt: paymentAmt,
cltvDelta: finalHopCLTV,
records: nil,
},
)
if err != nil {
t.Fatalf("unable to create path: %v", err)

@ -129,8 +129,12 @@ func (p *paymentSession) RequestRoute(payment *LightningPayment,
// a route by applying the time-lock and fee requirements.
sourceVertex := route.Vertex(ss.SelfNode.PubKeyBytes)
route, err := newRoute(
payment.Amount, sourceVertex, path, height, finalCltvDelta,
payment.DestCustomRecords,
sourceVertex, path, height,
finalHopParams{
amt: payment.Amount,
cltvDelta: finalCltvDelta,
records: payment.DestCustomRecords,
},
)
if err != nil {
// TODO(roasbeef): return which edge/vertex didn't work

@ -1454,8 +1454,12 @@ func (r *ChannelRouter) FindRoute(source, target route.Vertex,
// Create the route with absolute time lock values.
route, err := newRoute(
amt, source, path, uint32(currentHeight), finalCLTVDelta,
destCustomRecords,
source, path, uint32(currentHeight),
finalHopParams{
amt: amt,
cltvDelta: finalCLTVDelta,
records: destCustomRecords,
},
)
if err != nil {
return nil, err
@ -2403,7 +2407,11 @@ func (r *ChannelRouter) BuildRoute(amt *lnwire.MilliSatoshi,
}
return newRoute(
receiverAmt, source, pathEdges, uint32(height),
uint16(finalCltvDelta), nil,
source, pathEdges, uint32(height),
finalHopParams{
amt: receiverAmt,
cltvDelta: uint16(finalCltvDelta),
records: nil,
},
)
}