routing/pathfind: evaluate TLV support sooner

We move up the check for TLV support, since we will later use it to
determine if we can use dependent features, e.g. TLV records and payment
addresses.
This commit is contained in:
Conner Fromknecht 2019-12-18 23:56:05 -08:00
parent e3a9603846
commit cddb71ee53
No known key found for this signature in database
GPG Key ID: E7D737B67FA592C7
2 changed files with 57 additions and 13 deletions

@ -150,7 +150,22 @@ func newRoute(sourceVertex route.Vertex,
amtToForward lnwire.MilliSatoshi amtToForward lnwire.MilliSatoshi
fee lnwire.MilliSatoshi fee lnwire.MilliSatoshi
outgoingTimeLock uint32 outgoingTimeLock uint32
tlvPayload bool
) )
// Define a helper function that checks this edge's feature
// vector for support for a given feature. We assume at this
// point that the feature vectors transitive dependencies have
// been validated.
supports := edge.Node.Features.HasFeature
// We start by assuming the node doesn't support TLV. We'll now
// inspect the node's feature vector to see if we can promote
// the hop. We assume already that the feature vector's
// transitive dependencies have already been validated by path
// finding or some other means.
tlvPayload = supports(lnwire.TLVOnionPayloadOptional)
if i == len(pathEdges)-1 { if i == len(pathEdges)-1 {
// If this is the last hop, then the hop payload will // If this is the last hop, then the hop payload will
// contain the exact amount. In BOLT #4: Onion Routing // contain the exact amount. In BOLT #4: Onion Routing
@ -194,19 +209,7 @@ func newRoute(sourceVertex route.Vertex,
ChannelID: edge.ChannelID, ChannelID: edge.ChannelID,
AmtToForward: amtToForward, AmtToForward: amtToForward,
OutgoingTimeLock: outgoingTimeLock, OutgoingTimeLock: outgoingTimeLock,
LegacyPayload: true, LegacyPayload: !tlvPayload,
}
// We start out above by assuming that this node needs the
// legacy payload, as if we don't have the full
// NodeAnnouncement information for this node, then we can't
// assume it knows the latest features. If we do have a feature
// vector for this node, then we'll update the info now.
if edge.Node.Features != nil {
features := edge.Node.Features
currentHop.LegacyPayload = !features.HasFeature(
lnwire.TLVOnionPayloadOptional,
)
} }
// If this is the last hop, then we'll populate any TLV records // If this is the last hop, then we'll populate any TLV records

@ -1095,6 +1095,10 @@ func TestNewRoute(t *testing.T) {
// indicated by hops. // indicated by hops.
paymentAmount lnwire.MilliSatoshi paymentAmount lnwire.MilliSatoshi
// destFeatures is a feature vector, that if non-nil, will
// overwrite the final hop's feature vector in the graph.
destFeatures *lnwire.FeatureVector
// expectedFees is a list of fees that every hop is expected // expectedFees is a list of fees that every hop is expected
// to charge for forwarding. // to charge for forwarding.
expectedFees []lnwire.MilliSatoshi expectedFees []lnwire.MilliSatoshi
@ -1123,6 +1127,8 @@ func TestNewRoute(t *testing.T) {
// expectedErrorCode indicates the expected error code when // expectedErrorCode indicates the expected error code when
// expectError is true. // expectError is true.
expectedErrorCode errorCode expectedErrorCode errorCode
expectedTLVPayload bool
}{ }{
{ {
// For a single hop payment, no fees are expected to be paid. // For a single hop payment, no fees are expected to be paid.
@ -1149,6 +1155,22 @@ func TestNewRoute(t *testing.T) {
expectedTimeLocks: []uint32{1, 1}, expectedTimeLocks: []uint32{1, 1},
expectedTotalAmount: 100130, expectedTotalAmount: 100130,
expectedTotalTimeLock: 6, expectedTotalTimeLock: 6,
}, {
// For a two hop payment, only the fee for the first hop
// needs to be paid. The destination hop does not require
// a fee to receive the payment.
name: "two hop tlv onion feature",
destFeatures: tlvFeatures,
paymentAmount: 100000,
hops: []*channeldb.ChannelEdgePolicy{
createHop(0, 1000, 1000000, 10),
createHop(30, 1000, 1000000, 5),
},
expectedFees: []lnwire.MilliSatoshi{130, 0},
expectedTimeLocks: []uint32{1, 1},
expectedTotalAmount: 100130,
expectedTotalTimeLock: 6,
expectedTLVPayload: true,
}, { }, {
// A three hop payment where the first and second hop // A three hop payment where the first and second hop
// will both charge 1 msat. The fee for the first hop // will both charge 1 msat. The fee for the first hop
@ -1205,6 +1227,15 @@ func TestNewRoute(t *testing.T) {
}} }}
for _, testCase := range testCases { for _, testCase := range testCases {
testCase := testCase
// Overwrite the final hop's features if the test requires a
// custom feature vector.
if testCase.destFeatures != nil {
finalHop := testCase.hops[len(testCase.hops)-1]
finalHop.Node.Features = testCase.destFeatures
}
assertRoute := func(t *testing.T, route *route.Route) { assertRoute := func(t *testing.T, route *route.Route) {
if route.TotalAmount != testCase.expectedTotalAmount { if route.TotalAmount != testCase.expectedTotalAmount {
t.Errorf("Expected total amount is be %v"+ t.Errorf("Expected total amount is be %v"+
@ -1248,6 +1279,16 @@ func TestNewRoute(t *testing.T) {
route.Hops[i].OutgoingTimeLock) route.Hops[i].OutgoingTimeLock)
} }
} }
finalHop := route.Hops[len(route.Hops)-1]
if !finalHop.LegacyPayload !=
testCase.expectedTLVPayload {
t.Errorf("Expected tlv payload: %t, "+
"but got: %t instead",
testCase.expectedTLVPayload,
!finalHop.LegacyPayload)
}
} }
t.Run(testCase.name, func(t *testing.T) { t.Run(testCase.name, func(t *testing.T) {