diff --git a/routing/router.go b/routing/router.go index d32305f4..dcef3a28 100644 --- a/routing/router.go +++ b/routing/router.go @@ -38,6 +38,13 @@ const ( defaultPayAttemptTimeout = time.Duration(time.Second * 60) ) +var ( + // ErrNoRouteHopsProvided is returned when a caller attempts to + // construct a new sphinx packet, but provides an empty set of hops for + // each route. + ErrNoRouteHopsProvided = fmt.Errorf("empty route hops provided") +) + // ChannelGraphSource represents the source of information about the topology // of the lightning network. It's responsible for the addition of nodes, edges, // applying edge updates, and returning the current block height with which the @@ -1412,6 +1419,14 @@ func (r *ChannelRouter) FindRoutes(target *btcec.PublicKey, // be sent to the first hop within the route. func generateSphinxPacket(route *Route, paymentHash []byte) ([]byte, *sphinx.Circuit, error) { + + // As a sanity check, we'll ensure that the set of hops has been + // properly filled in, otherwise, we won't actually be able to + // construct a route. + if len(route.Hops) == 0 { + return nil, nil, ErrNoRouteHopsProvided + } + // First obtain all the public keys along the route which are contained // in each hop. nodes := make([]*btcec.PublicKey, len(route.Hops)) diff --git a/routing/router_test.go b/routing/router_test.go index 1ceb0a90..7d7312fb 100644 --- a/routing/router_test.go +++ b/routing/router_test.go @@ -9,14 +9,14 @@ import ( "testing" "time" + "github.com/btcsuite/btcd/wire" "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/htlcswitch" - "github.com/btcsuite/btcd/wire" + "github.com/btcsuite/btcd/btcec" "github.com/davecgh/go-spew/spew" "github.com/lightningnetwork/lightning-onion" "github.com/lightningnetwork/lnd/lnwire" - "github.com/btcsuite/btcd/btcec" ) // defaultNumRoutes is the default value for the maximum number of routes to @@ -1941,3 +1941,16 @@ func TestIsStaleEdgePolicy(t *testing.T) { t.Fatalf("router failed to detect fresh edge policy") } } + +// TestEmptyRoutesGenerateSphinxPacket tests that the generateSphinxPacket +// function is able to gracefully handle being passed a nil set of hops for the +// route by the caller. +func TestEmptyRoutesGenerateSphinxPacket(t *testing.T) { + t.Parallel() + + emptyRoute := &Route{} + _, _, err := generateSphinxPacket(emptyRoute, testHash[:]) + if err != ErrNoRouteHopsProvided { + t.Fatalf("expected empty hops error: instead got: %v", err) + } +}