routing: don't treat bad features as an unexpected error

Previous behavior led to the payment loop being abandoned immediately,
resulting in a payment stuck in state in_flight.
This commit is contained in:
Joost Jager 2020-05-27 12:14:52 +02:00
parent 32b04b7ac3
commit 3ef68baf4a
No known key found for this signature in database
GPG Key ID: A61B9D4C393C59C7
3 changed files with 23 additions and 9 deletions

@ -420,13 +420,15 @@ func findPath(g *graphParams, r *RestrictParams, cfg *PathFindingConfig,
// required features. // required features.
err := feature.ValidateRequired(features) err := feature.ValidateRequired(features)
if err != nil { if err != nil {
return nil, err log.Warnf("Pathfinding destination node features: %v", err)
return nil, errUnknownRequiredFeature
} }
// Ensure that all transitive dependencies are set. // Ensure that all transitive dependencies are set.
err = feature.ValidateDeps(features) err = feature.ValidateDeps(features)
if err != nil { if err != nil {
return nil, err log.Warnf("Pathfinding destination node features: %v", err)
return nil, errMissingDependentFeature
} }
// Now that we know the feature vector is well formed, we'll proceed in // Now that we know the feature vector is well formed, we'll proceed in

@ -23,7 +23,6 @@ import (
"github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil" "github.com/btcsuite/btcutil"
"github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/feature"
"github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/record" "github.com/lightningnetwork/lnd/record"
"github.com/lightningnetwork/lnd/routing/route" "github.com/lightningnetwork/lnd/routing/route"
@ -1590,9 +1589,7 @@ func TestMissingFeatureDep(t *testing.T) {
joost := ctx.keyFromAlias("joost") joost := ctx.keyFromAlias("joost")
_, err := ctx.findPath(conner, 100) _, err := ctx.findPath(conner, 100)
if err != feature.NewErrMissingFeatureDep( if err != errMissingDependentFeature {
lnwire.TLVOnionPayloadOptional,
) {
t.Fatalf("path shouldn't have been found: %v", err) t.Fatalf("path shouldn't have been found: %v", err)
} }
@ -1667,9 +1664,8 @@ func TestUnknownRequiredFeatures(t *testing.T) {
// Conner's node in the graph has an unknown required feature (100). // Conner's node in the graph has an unknown required feature (100).
// Pathfinding should fail since we check the destination's features for // Pathfinding should fail since we check the destination's features for
// unknown required features before beginning pathfinding. // unknown required features before beginning pathfinding.
expErr := feature.NewErrUnknownRequired([]lnwire.FeatureBit{100})
_, err := ctx.findPath(conner, 100) _, err := ctx.findPath(conner, 100)
if !reflect.DeepEqual(err, expErr) { if !reflect.DeepEqual(err, errUnknownRequiredFeature) {
t.Fatalf("path shouldn't have been found: %v", err) t.Fatalf("path shouldn't have been found: %v", err)
} }

@ -37,6 +37,14 @@ const (
// errEmptyPaySession is returned when the empty payment session is // errEmptyPaySession is returned when the empty payment session is
// queried for a route. // queried for a route.
errEmptyPaySession errEmptyPaySession
// errUnknownRequiredFeature is returned when the destination node
// requires an unknown feature.
errUnknownRequiredFeature
// errMissingDependentFeature is returned when the destination node
// misses a feature that a feature that we require depends on.
errMissingDependentFeature
) )
var ( var (
@ -64,6 +72,12 @@ func (e noRouteError) Error() string {
case errInsufficientBalance: case errInsufficientBalance:
return "insufficient local balance" return "insufficient local balance"
case errUnknownRequiredFeature:
return "unknown required feature"
case errMissingDependentFeature:
return "missing dependent feature"
default: default:
return "unknown no-route error" return "unknown no-route error"
} }
@ -76,7 +90,9 @@ func (e noRouteError) FailureReason() channeldb.FailureReason {
errNoTlvPayload, errNoTlvPayload,
errNoPaymentAddr, errNoPaymentAddr,
errNoPathFound, errNoPathFound,
errEmptyPaySession: errEmptyPaySession,
errUnknownRequiredFeature,
errMissingDependentFeature:
return channeldb.FailureReasonNoRoute return channeldb.FailureReasonNoRoute