lnd.xprv/routing/router_test.go
Olaoluwa Osuntokun 1df5bece85
routing: FindRoute is now FindRoutes, uses our KSP algo, ranks by fee
This commit modifies the existing FindRoute method on the ChannelRouter
to now use the KSP implementation added in a prior commit.

This new method FindRoutes, is able to find all the possible paths
between a source and destination. The method takes all paths reported
by findPaths, and attempt to turn each of them into a route. A route
differs from a path in that is has complete time-lock and fee
information. Some paths may not be able to be turned into routes as
once fees are accounted for the have an insufficient flow. We then take
the routes, sort them by total fee (with time-lock being a
time-breaker), then return them in sorted order.
2017-03-21 12:20:40 -07:00

149 lines
4.0 KiB
Go

package routing
import (
"bytes"
"errors"
"fmt"
"testing"
"github.com/davecgh/go-spew/spew"
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/roasbeef/btcd/btcec"
"github.com/roasbeef/btcutil"
)
type testCtx struct {
router *ChannelRouter
graph *channeldb.ChannelGraph
aliases map[string]*btcec.PublicKey
chain *mockChain
notifier *mockNotifier
}
func createTestCtx(startingHeight uint32, testGraph ...string) (*testCtx, func(), error) {
var (
graph *channeldb.ChannelGraph
sourceNode *channeldb.LightningNode
cleanup func()
err error
)
aliasMap := make(map[string]*btcec.PublicKey)
// If the testGraph isn't set, then we'll create an empty graph to
// start out with. Our usage of a variadic parameter allows caller to
// omit the testGraph argument all together if they wish to start with
// a blank graph.
if testGraph == nil {
// First we'll set up a test graph for usage within the test.
graph, cleanup, err = makeTestGraph()
if err != nil {
return nil, nil, fmt.Errorf("unable to create test graph: %v", err)
}
sourceNode, err = createGraphNode()
if err != nil {
return nil, nil, fmt.Errorf("unable to create source node: %v", err)
}
if err = graph.SetSourceNode(sourceNode); err != nil {
return nil, nil, fmt.Errorf("unable to set source node: %v", err)
}
} else {
// Otherwise, we'll attempt to locate and parse out the file
// that encodes the graph that our tests should be run against.
graph, cleanup, aliasMap, err = parseTestGraph(testGraph[0])
if err != nil {
return nil, nil, fmt.Errorf("unable to create test graph: %v", err)
}
sourceNode, err = graph.SourceNode()
if err != nil {
return nil, nil, fmt.Errorf("unable to fetch source node: %v", err)
}
}
// Next we'll initialize an instance of the channel router with mock
// versions of the chain and channel notifier. As we don't need to test
// any p2p functionality, the peer send and switch send messages won't
// be populated.
chain := newMockChain(startingHeight)
notifier := newMockNotifier()
router, err := New(Config{
Graph: graph,
Chain: chain,
Notifier: notifier,
Broadcast: func(_ *btcec.PublicKey, msg ...lnwire.Message) error {
return nil
},
SendMessages: func(_ *btcec.PublicKey, msg ...lnwire.Message) error {
return nil
},
SendToSwitch: func(_ *btcec.PublicKey,
_ *lnwire.UpdateAddHTLC) ([32]byte, error) {
return [32]byte{}, nil
},
})
if err != nil {
return nil, nil, fmt.Errorf("unable to create router %v", err)
}
if err := router.Start(); err != nil {
return nil, nil, fmt.Errorf("unable to start router: %v", err)
}
cleanUp := func() {
router.Stop()
cleanup()
}
return &testCtx{
router: router,
graph: graph,
aliases: aliasMap,
chain: chain,
notifier: notifier,
}, cleanUp, nil
}
// TestFindRoutesFeeSorting asserts that routes found by the FindRoutes method
// within the channel router are properly returned in a sorted order, with the
// lowest fee route coming first.
func TestFindRoutesFeeSorting(t *testing.T) {
const startingBlockHeight = 101
ctx, cleanUp, err := createTestCtx(startingBlockHeight, basicGraphFilePath)
defer cleanUp()
if err != nil {
t.Fatalf("unable to create router: %v", err)
}
// In this test we'd like to ensure proper integration of the various
// functions that are involved in path finding, and also route
// selection.
// Execute a query for all possible routes between roasbeef and luo ji.
const paymentAmt = btcutil.Amount(100)
target := ctx.aliases["luoji"]
routes, err := ctx.router.FindRoutes(target, paymentAmt)
if err != nil {
t.Fatalf("unable to find any routes: %v", err)
}
// Exactly, two such paths should be found.
if len(routes) != 2 {
t.Fatalf("2 routes shouldn't been selected, instead %v were: ",
len(routes))
}
// The paths should properly be ranked according to their total fee
// rate.
if routes[0].TotalFees > routes[1].TotalFees {
t.Fatalf("routes not ranked by total fee: %v",
spew.Sdump(routes))
}
}