mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-06-15 19:31:35 +02:00
routing: run path finding tests against cache and DB
To make sure we don't hit any edge cases we refactor the path finding tests to run both with and without the cache enabled.
This commit is contained in:
parent
0a2ccfc52b
commit
01015aced4
@ -150,7 +150,9 @@ type testChan struct {
|
|||||||
// makeTestGraph creates a new instance of a channeldb.ChannelGraph for testing
|
// makeTestGraph creates a new instance of a channeldb.ChannelGraph for testing
|
||||||
// purposes. A callback which cleans up the created temporary directories is
|
// purposes. A callback which cleans up the created temporary directories is
|
||||||
// also returned and intended to be executed after the test completes.
|
// also returned and intended to be executed after the test completes.
|
||||||
func makeTestGraph() (*channeldb.ChannelGraph, kvdb.Backend, func(), error) {
|
func makeTestGraph(useCache bool) (*channeldb.ChannelGraph, kvdb.Backend,
|
||||||
|
func(), error) {
|
||||||
|
|
||||||
// First, create a temporary directory to be used for the duration of
|
// First, create a temporary directory to be used for the duration of
|
||||||
// this test.
|
// this test.
|
||||||
tempDirName, err := ioutil.TempDir("", "channeldb")
|
tempDirName, err := ioutil.TempDir("", "channeldb")
|
||||||
@ -173,7 +175,7 @@ func makeTestGraph() (*channeldb.ChannelGraph, kvdb.Backend, func(), error) {
|
|||||||
graph, err := channeldb.NewChannelGraph(
|
graph, err := channeldb.NewChannelGraph(
|
||||||
backend, opts.RejectCacheSize, opts.ChannelCacheSize,
|
backend, opts.RejectCacheSize, opts.ChannelCacheSize,
|
||||||
opts.BatchCommitInterval, opts.PreAllocCacheNumNodes,
|
opts.BatchCommitInterval, opts.PreAllocCacheNumNodes,
|
||||||
true,
|
useCache,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cleanUp()
|
cleanUp()
|
||||||
@ -185,7 +187,7 @@ func makeTestGraph() (*channeldb.ChannelGraph, kvdb.Backend, func(), error) {
|
|||||||
|
|
||||||
// parseTestGraph returns a fully populated ChannelGraph given a path to a JSON
|
// parseTestGraph returns a fully populated ChannelGraph given a path to a JSON
|
||||||
// file which encodes a test graph.
|
// file which encodes a test graph.
|
||||||
func parseTestGraph(path string) (*testGraphInstance, error) {
|
func parseTestGraph(useCache bool, path string) (*testGraphInstance, error) {
|
||||||
graphJSON, err := ioutil.ReadFile(path)
|
graphJSON, err := ioutil.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -210,7 +212,7 @@ func parseTestGraph(path string) (*testGraphInstance, error) {
|
|||||||
testAddrs = append(testAddrs, testAddr)
|
testAddrs = append(testAddrs, testAddr)
|
||||||
|
|
||||||
// Next, create a temporary graph database for usage within the test.
|
// Next, create a temporary graph database for usage within the test.
|
||||||
graph, graphBackend, cleanUp, err := makeTestGraph()
|
graph, graphBackend, cleanUp, err := makeTestGraph(useCache)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -529,8 +531,8 @@ func (g *testGraphInstance) getLink(chanID lnwire.ShortChannelID) (
|
|||||||
// a deterministical way and added to the channel graph. A list of nodes is
|
// a deterministical way and added to the channel graph. A list of nodes is
|
||||||
// not required and derived from the channel data. The goal is to keep
|
// not required and derived from the channel data. The goal is to keep
|
||||||
// instantiating a test channel graph as light weight as possible.
|
// instantiating a test channel graph as light weight as possible.
|
||||||
func createTestGraphFromChannels(testChannels []*testChannel, source string) (
|
func createTestGraphFromChannels(useCache bool, testChannels []*testChannel,
|
||||||
*testGraphInstance, error) {
|
source string) (*testGraphInstance, error) {
|
||||||
|
|
||||||
// We'll use this fake address for the IP address of all the nodes in
|
// We'll use this fake address for the IP address of all the nodes in
|
||||||
// our tests. This value isn't needed for path finding so it doesn't
|
// our tests. This value isn't needed for path finding so it doesn't
|
||||||
@ -543,7 +545,7 @@ func createTestGraphFromChannels(testChannels []*testChannel, source string) (
|
|||||||
testAddrs = append(testAddrs, testAddr)
|
testAddrs = append(testAddrs, testAddr)
|
||||||
|
|
||||||
// Next, create a temporary graph database for usage within the test.
|
// Next, create a temporary graph database for usage within the test.
|
||||||
graph, graphBackend, cleanUp, err := makeTestGraph()
|
graph, graphBackend, cleanUp, err := makeTestGraph(useCache)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -769,13 +771,106 @@ func createTestGraphFromChannels(testChannels []*testChannel, source string) (
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestFindLowestFeePath tests that out of two routes with identical total
|
// TestPathFinding tests all path finding related cases both with the in-memory
|
||||||
|
// graph cached turned on and off.
|
||||||
|
func TestPathFinding(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
fn func(t *testing.T, useCache bool)
|
||||||
|
}{{
|
||||||
|
name: "lowest fee path",
|
||||||
|
fn: runFindLowestFeePath,
|
||||||
|
}, {
|
||||||
|
name: "basic graph path finding",
|
||||||
|
fn: runBasicGraphPathFinding,
|
||||||
|
}, {
|
||||||
|
name: "path finding with additional edges",
|
||||||
|
fn: runPathFindingWithAdditionalEdges,
|
||||||
|
}, {
|
||||||
|
name: "new route path too long",
|
||||||
|
fn: runNewRoutePathTooLong,
|
||||||
|
}, {
|
||||||
|
name: "path not available",
|
||||||
|
fn: runPathNotAvailable,
|
||||||
|
}, {
|
||||||
|
name: "destination tlv graph fallback",
|
||||||
|
fn: runDestTLVGraphFallback,
|
||||||
|
}, {
|
||||||
|
name: "missing feature dependency",
|
||||||
|
fn: runMissingFeatureDep,
|
||||||
|
}, {
|
||||||
|
name: "unknown required features",
|
||||||
|
fn: runUnknownRequiredFeatures,
|
||||||
|
}, {
|
||||||
|
name: "destination payment address",
|
||||||
|
fn: runDestPaymentAddr,
|
||||||
|
}, {
|
||||||
|
name: "path insufficient capacity",
|
||||||
|
fn: runPathInsufficientCapacity,
|
||||||
|
}, {
|
||||||
|
name: "route fail min HTLC",
|
||||||
|
fn: runRouteFailMinHTLC,
|
||||||
|
}, {
|
||||||
|
name: "route fail max HTLC",
|
||||||
|
fn: runRouteFailMaxHTLC,
|
||||||
|
}, {
|
||||||
|
name: "route fail disabled edge",
|
||||||
|
fn: runRouteFailDisabledEdge,
|
||||||
|
}, {
|
||||||
|
name: "path source edges bandwidth",
|
||||||
|
fn: runPathSourceEdgesBandwidth,
|
||||||
|
}, {
|
||||||
|
name: "restrict outgoing channel",
|
||||||
|
fn: runRestrictOutgoingChannel,
|
||||||
|
}, {
|
||||||
|
name: "restrict last hop",
|
||||||
|
fn: runRestrictLastHop,
|
||||||
|
}, {
|
||||||
|
name: "CLTV limit",
|
||||||
|
fn: runCltvLimit,
|
||||||
|
}, {
|
||||||
|
name: "probability routing",
|
||||||
|
fn: runProbabilityRouting,
|
||||||
|
}, {
|
||||||
|
name: "equal cost route selection",
|
||||||
|
fn: runEqualCostRouteSelection,
|
||||||
|
}, {
|
||||||
|
name: "no cycle",
|
||||||
|
fn: runNoCycle,
|
||||||
|
}, {
|
||||||
|
name: "route to self",
|
||||||
|
fn: runRouteToSelf,
|
||||||
|
}}
|
||||||
|
|
||||||
|
// Run with graph cache enabled.
|
||||||
|
for _, tc := range testCases {
|
||||||
|
tc := tc
|
||||||
|
|
||||||
|
t.Run("cache=true/"+tc.name, func(tt *testing.T) {
|
||||||
|
tt.Parallel()
|
||||||
|
|
||||||
|
tc.fn(tt, true)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// And with the DB fallback to make sure everything works the same
|
||||||
|
// still.
|
||||||
|
for _, tc := range testCases {
|
||||||
|
tc := tc
|
||||||
|
|
||||||
|
t.Run("cache=false/"+tc.name, func(tt *testing.T) {
|
||||||
|
tt.Parallel()
|
||||||
|
|
||||||
|
tc.fn(tt, false)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// runFindLowestFeePath tests that out of two routes with identical total
|
||||||
// time lock values, the route with the lowest total fee should be returned.
|
// time lock values, the route with the lowest total fee should be returned.
|
||||||
// The fee rates are chosen such that the test failed on the previous edge
|
// The fee rates are chosen such that the test failed on the previous edge
|
||||||
// weight function where one of the terms was fee squared.
|
// weight function where one of the terms was fee squared.
|
||||||
func TestFindLowestFeePath(t *testing.T) {
|
func runFindLowestFeePath(t *testing.T, useCache bool) {
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
// Set up a test graph with two paths from roasbeef to target. Both
|
// Set up a test graph with two paths from roasbeef to target. Both
|
||||||
// paths have equal total time locks, but the path through b has lower
|
// paths have equal total time locks, but the path through b has lower
|
||||||
// fees (700 compared to 800 for the path through a).
|
// fees (700 compared to 800 for the path through a).
|
||||||
@ -812,7 +907,7 @@ func TestFindLowestFeePath(t *testing.T) {
|
|||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := newPathFindingTestContext(t, testChannels, "roasbeef")
|
ctx := newPathFindingTestContext(t, useCache, testChannels, "roasbeef")
|
||||||
defer ctx.cleanup()
|
defer ctx.cleanup()
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -917,10 +1012,8 @@ var basicGraphPathFindingTests = []basicGraphPathFindingTestCase{
|
|||||||
expectFailureNoPath: true,
|
expectFailureNoPath: true,
|
||||||
}}
|
}}
|
||||||
|
|
||||||
func TestBasicGraphPathFinding(t *testing.T) {
|
func runBasicGraphPathFinding(t *testing.T, useCache bool) {
|
||||||
t.Parallel()
|
testGraphInstance, err := parseTestGraph(useCache, basicGraphFilePath)
|
||||||
|
|
||||||
testGraphInstance, err := parseTestGraph(basicGraphFilePath)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to create graph: %v", err)
|
t.Fatalf("unable to create graph: %v", err)
|
||||||
}
|
}
|
||||||
@ -1092,14 +1185,12 @@ func testBasicGraphPathFindingCase(t *testing.T, graphInstance *testGraphInstanc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestPathFindingWithAdditionalEdges asserts that we are able to find paths to
|
// runPathFindingWithAdditionalEdges asserts that we are able to find paths to
|
||||||
// nodes that do not exist in the graph by way of hop hints. We also test that
|
// nodes that do not exist in the graph by way of hop hints. We also test that
|
||||||
// the path can support custom TLV records for the receiver under the
|
// the path can support custom TLV records for the receiver under the
|
||||||
// appropriate circumstances.
|
// appropriate circumstances.
|
||||||
func TestPathFindingWithAdditionalEdges(t *testing.T) {
|
func runPathFindingWithAdditionalEdges(t *testing.T, useCache bool) {
|
||||||
t.Parallel()
|
graph, err := parseTestGraph(useCache, basicGraphFilePath)
|
||||||
|
|
||||||
graph, err := parseTestGraph(basicGraphFilePath)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to create graph: %v", err)
|
t.Fatalf("unable to create graph: %v", err)
|
||||||
}
|
}
|
||||||
@ -1503,9 +1594,7 @@ func TestNewRoute(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewRoutePathTooLong(t *testing.T) {
|
func runNewRoutePathTooLong(t *testing.T, useCache bool) {
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
var testChannels []*testChannel
|
var testChannels []*testChannel
|
||||||
|
|
||||||
// Setup a linear network of 21 hops.
|
// Setup a linear network of 21 hops.
|
||||||
@ -1523,7 +1612,7 @@ func TestNewRoutePathTooLong(t *testing.T) {
|
|||||||
fromNode = toNode
|
fromNode = toNode
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := newPathFindingTestContext(t, testChannels, "start")
|
ctx := newPathFindingTestContext(t, useCache, testChannels, "start")
|
||||||
defer ctx.cleanup()
|
defer ctx.cleanup()
|
||||||
|
|
||||||
// Assert that we can find 20 hop routes.
|
// Assert that we can find 20 hop routes.
|
||||||
@ -1553,10 +1642,8 @@ func TestNewRoutePathTooLong(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPathNotAvailable(t *testing.T) {
|
func runPathNotAvailable(t *testing.T, useCache bool) {
|
||||||
t.Parallel()
|
graph, err := parseTestGraph(useCache, basicGraphFilePath)
|
||||||
|
|
||||||
graph, err := parseTestGraph(basicGraphFilePath)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to create graph: %v", err)
|
t.Fatalf("unable to create graph: %v", err)
|
||||||
}
|
}
|
||||||
@ -1588,12 +1675,10 @@ func TestPathNotAvailable(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestDestTLVGraphFallback asserts that we properly detect when we can send TLV
|
// runDestTLVGraphFallback asserts that we properly detect when we can send TLV
|
||||||
// records to a receiver, and also that we fallback to the receiver's node
|
// records to a receiver, and also that we fallback to the receiver's node
|
||||||
// announcement if we don't have an invoice features.
|
// announcement if we don't have an invoice features.
|
||||||
func TestDestTLVGraphFallback(t *testing.T) {
|
func runDestTLVGraphFallback(t *testing.T, useCache bool) {
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
testChannels := []*testChannel{
|
testChannels := []*testChannel{
|
||||||
asymmetricTestChannel("roasbeef", "luoji", 100000,
|
asymmetricTestChannel("roasbeef", "luoji", 100000,
|
||||||
&testChannelPolicy{
|
&testChannelPolicy{
|
||||||
@ -1622,7 +1707,7 @@ func TestDestTLVGraphFallback(t *testing.T) {
|
|||||||
}, 0),
|
}, 0),
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := newPathFindingTestContext(t, testChannels, "roasbeef")
|
ctx := newPathFindingTestContext(t, useCache, testChannels, "roasbeef")
|
||||||
defer ctx.cleanup()
|
defer ctx.cleanup()
|
||||||
|
|
||||||
sourceNode, err := ctx.graph.SourceNode()
|
sourceNode, err := ctx.graph.SourceNode()
|
||||||
@ -1690,12 +1775,10 @@ func TestDestTLVGraphFallback(t *testing.T) {
|
|||||||
assertExpectedPath(t, ctx.testGraphInstance.aliasMap, path, "luoji")
|
assertExpectedPath(t, ctx.testGraphInstance.aliasMap, path, "luoji")
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestMissingFeatureDep asserts that we fail path finding when the
|
// runMissingFeatureDep asserts that we fail path finding when the
|
||||||
// destination's features are broken, in that the feature vector doesn't signal
|
// destination's features are broken, in that the feature vector doesn't signal
|
||||||
// all transitive dependencies.
|
// all transitive dependencies.
|
||||||
func TestMissingFeatureDep(t *testing.T) {
|
func runMissingFeatureDep(t *testing.T, useCache bool) {
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
testChannels := []*testChannel{
|
testChannels := []*testChannel{
|
||||||
asymmetricTestChannel("roasbeef", "conner", 100000,
|
asymmetricTestChannel("roasbeef", "conner", 100000,
|
||||||
&testChannelPolicy{
|
&testChannelPolicy{
|
||||||
@ -1729,7 +1812,7 @@ func TestMissingFeatureDep(t *testing.T) {
|
|||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := newPathFindingTestContext(t, testChannels, "roasbeef")
|
ctx := newPathFindingTestContext(t, useCache, testChannels, "roasbeef")
|
||||||
defer ctx.cleanup()
|
defer ctx.cleanup()
|
||||||
|
|
||||||
// Conner's node in the graph has a broken feature vector, since it
|
// Conner's node in the graph has a broken feature vector, since it
|
||||||
@ -1767,12 +1850,10 @@ func TestMissingFeatureDep(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestUnknownRequiredFeatures asserts that we fail path finding when the
|
// runUnknownRequiredFeatures asserts that we fail path finding when the
|
||||||
// destination requires an unknown required feature, and that we skip
|
// destination requires an unknown required feature, and that we skip
|
||||||
// intermediaries that signal unknown required features.
|
// intermediaries that signal unknown required features.
|
||||||
func TestUnknownRequiredFeatures(t *testing.T) {
|
func runUnknownRequiredFeatures(t *testing.T, useCache bool) {
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
testChannels := []*testChannel{
|
testChannels := []*testChannel{
|
||||||
asymmetricTestChannel("roasbeef", "conner", 100000,
|
asymmetricTestChannel("roasbeef", "conner", 100000,
|
||||||
&testChannelPolicy{
|
&testChannelPolicy{
|
||||||
@ -1806,7 +1887,7 @@ func TestUnknownRequiredFeatures(t *testing.T) {
|
|||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := newPathFindingTestContext(t, testChannels, "roasbeef")
|
ctx := newPathFindingTestContext(t, useCache, testChannels, "roasbeef")
|
||||||
defer ctx.cleanup()
|
defer ctx.cleanup()
|
||||||
|
|
||||||
conner := ctx.keyFromAlias("conner")
|
conner := ctx.keyFromAlias("conner")
|
||||||
@ -1833,12 +1914,10 @@ func TestUnknownRequiredFeatures(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestDestPaymentAddr asserts that we properly detect when we can send a
|
// runDestPaymentAddr asserts that we properly detect when we can send a
|
||||||
// payment address to a receiver, and also that we fallback to the receiver's
|
// payment address to a receiver, and also that we fallback to the receiver's
|
||||||
// node announcement if we don't have an invoice features.
|
// node announcement if we don't have an invoice features.
|
||||||
func TestDestPaymentAddr(t *testing.T) {
|
func runDestPaymentAddr(t *testing.T, useCache bool) {
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
testChannels := []*testChannel{
|
testChannels := []*testChannel{
|
||||||
symmetricTestChannel("roasbeef", "luoji", 100000,
|
symmetricTestChannel("roasbeef", "luoji", 100000,
|
||||||
&testChannelPolicy{
|
&testChannelPolicy{
|
||||||
@ -1850,7 +1929,7 @@ func TestDestPaymentAddr(t *testing.T) {
|
|||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := newPathFindingTestContext(t, testChannels, "roasbeef")
|
ctx := newPathFindingTestContext(t, useCache, testChannels, "roasbeef")
|
||||||
defer ctx.cleanup()
|
defer ctx.cleanup()
|
||||||
|
|
||||||
luoji := ctx.keyFromAlias("luoji")
|
luoji := ctx.keyFromAlias("luoji")
|
||||||
@ -1878,10 +1957,8 @@ func TestDestPaymentAddr(t *testing.T) {
|
|||||||
assertExpectedPath(t, ctx.testGraphInstance.aliasMap, path, "luoji")
|
assertExpectedPath(t, ctx.testGraphInstance.aliasMap, path, "luoji")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPathInsufficientCapacity(t *testing.T) {
|
func runPathInsufficientCapacity(t *testing.T, useCache bool) {
|
||||||
t.Parallel()
|
graph, err := parseTestGraph(useCache, basicGraphFilePath)
|
||||||
|
|
||||||
graph, err := parseTestGraph(basicGraphFilePath)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to create graph: %v", err)
|
t.Fatalf("unable to create graph: %v", err)
|
||||||
}
|
}
|
||||||
@ -1913,12 +1990,10 @@ func TestPathInsufficientCapacity(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestRouteFailMinHTLC tests that if we attempt to route an HTLC which is
|
// runRouteFailMinHTLC tests that if we attempt to route an HTLC which is
|
||||||
// smaller than the advertised minHTLC of an edge, then path finding fails.
|
// smaller than the advertised minHTLC of an edge, then path finding fails.
|
||||||
func TestRouteFailMinHTLC(t *testing.T) {
|
func runRouteFailMinHTLC(t *testing.T, useCache bool) {
|
||||||
t.Parallel()
|
graph, err := parseTestGraph(useCache, basicGraphFilePath)
|
||||||
|
|
||||||
graph, err := parseTestGraph(basicGraphFilePath)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to create graph: %v", err)
|
t.Fatalf("unable to create graph: %v", err)
|
||||||
}
|
}
|
||||||
@ -1944,11 +2019,9 @@ func TestRouteFailMinHTLC(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestRouteFailMaxHTLC tests that if we attempt to route an HTLC which is
|
// runRouteFailMaxHTLC tests that if we attempt to route an HTLC which is
|
||||||
// larger than the advertised max HTLC of an edge, then path finding fails.
|
// larger than the advertised max HTLC of an edge, then path finding fails.
|
||||||
func TestRouteFailMaxHTLC(t *testing.T) {
|
func runRouteFailMaxHTLC(t *testing.T, useCache bool) {
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
// Set up a test graph:
|
// Set up a test graph:
|
||||||
// roasbeef <--> firstHop <--> secondHop <--> target
|
// roasbeef <--> firstHop <--> secondHop <--> target
|
||||||
// We will be adjusting the max HTLC of the edge between the first and
|
// We will be adjusting the max HTLC of the edge between the first and
|
||||||
@ -1975,7 +2048,7 @@ func TestRouteFailMaxHTLC(t *testing.T) {
|
|||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := newPathFindingTestContext(t, testChannels, "roasbeef")
|
ctx := newPathFindingTestContext(t, useCache, testChannels, "roasbeef")
|
||||||
defer ctx.cleanup()
|
defer ctx.cleanup()
|
||||||
|
|
||||||
// First, attempt to send a payment greater than the max HTLC we are
|
// First, attempt to send a payment greater than the max HTLC we are
|
||||||
@ -2008,15 +2081,13 @@ func TestRouteFailMaxHTLC(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestRouteFailDisabledEdge tests that if we attempt to route to an edge
|
// runRouteFailDisabledEdge tests that if we attempt to route to an edge
|
||||||
// that's disabled, then that edge is disqualified, and the routing attempt
|
// that's disabled, then that edge is disqualified, and the routing attempt
|
||||||
// will fail. We also test that this is true only for non-local edges, as we'll
|
// will fail. We also test that this is true only for non-local edges, as we'll
|
||||||
// ignore the disable flags, with the assumption that the correct bandwidth is
|
// ignore the disable flags, with the assumption that the correct bandwidth is
|
||||||
// found among the bandwidth hints.
|
// found among the bandwidth hints.
|
||||||
func TestRouteFailDisabledEdge(t *testing.T) {
|
func runRouteFailDisabledEdge(t *testing.T, useCache bool) {
|
||||||
t.Parallel()
|
graph, err := parseTestGraph(useCache, basicGraphFilePath)
|
||||||
|
|
||||||
graph, err := parseTestGraph(basicGraphFilePath)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to create graph: %v", err)
|
t.Fatalf("unable to create graph: %v", err)
|
||||||
}
|
}
|
||||||
@ -2090,13 +2161,11 @@ func TestRouteFailDisabledEdge(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestPathSourceEdgesBandwidth tests that explicitly passing in a set of
|
// runPathSourceEdgesBandwidth tests that explicitly passing in a set of
|
||||||
// bandwidth hints is used by the path finding algorithm to consider whether to
|
// bandwidth hints is used by the path finding algorithm to consider whether to
|
||||||
// use a local channel.
|
// use a local channel.
|
||||||
func TestPathSourceEdgesBandwidth(t *testing.T) {
|
func runPathSourceEdgesBandwidth(t *testing.T, useCache bool) {
|
||||||
t.Parallel()
|
graph, err := parseTestGraph(useCache, basicGraphFilePath)
|
||||||
|
|
||||||
graph, err := parseTestGraph(basicGraphFilePath)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to create graph: %v", err)
|
t.Fatalf("unable to create graph: %v", err)
|
||||||
}
|
}
|
||||||
@ -2391,11 +2460,9 @@ func TestNewRouteFromEmptyHops(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestRestrictOutgoingChannel asserts that a outgoing channel restriction is
|
// runRestrictOutgoingChannel asserts that a outgoing channel restriction is
|
||||||
// obeyed by the path finding algorithm.
|
// obeyed by the path finding algorithm.
|
||||||
func TestRestrictOutgoingChannel(t *testing.T) {
|
func runRestrictOutgoingChannel(t *testing.T, useCache bool) {
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
// Define channel id constants
|
// Define channel id constants
|
||||||
const (
|
const (
|
||||||
chanSourceA = 1
|
chanSourceA = 1
|
||||||
@ -2431,7 +2498,7 @@ func TestRestrictOutgoingChannel(t *testing.T) {
|
|||||||
}, chanSourceTarget),
|
}, chanSourceTarget),
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := newPathFindingTestContext(t, testChannels, "roasbeef")
|
ctx := newPathFindingTestContext(t, useCache, testChannels, "roasbeef")
|
||||||
defer ctx.cleanup()
|
defer ctx.cleanup()
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -2474,11 +2541,9 @@ func TestRestrictOutgoingChannel(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestRestrictLastHop asserts that a last hop restriction is obeyed by the path
|
// runRestrictLastHop asserts that a last hop restriction is obeyed by the path
|
||||||
// finding algorithm.
|
// finding algorithm.
|
||||||
func TestRestrictLastHop(t *testing.T) {
|
func runRestrictLastHop(t *testing.T, useCache bool) {
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
// Set up a test graph with three possible paths from roasbeef to
|
// Set up a test graph with three possible paths from roasbeef to
|
||||||
// target. The path via channel 1 and 2 is the lowest cost path.
|
// target. The path via channel 1 and 2 is the lowest cost path.
|
||||||
testChannels := []*testChannel{
|
testChannels := []*testChannel{
|
||||||
@ -2498,7 +2563,7 @@ func TestRestrictLastHop(t *testing.T) {
|
|||||||
}, 4),
|
}, 4),
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := newPathFindingTestContext(t, testChannels, "source")
|
ctx := newPathFindingTestContext(t, useCache, testChannels, "source")
|
||||||
defer ctx.cleanup()
|
defer ctx.cleanup()
|
||||||
|
|
||||||
paymentAmt := lnwire.NewMSatFromSatoshis(100)
|
paymentAmt := lnwire.NewMSatFromSatoshis(100)
|
||||||
@ -2519,15 +2584,23 @@ func TestRestrictLastHop(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestCltvLimit asserts that a cltv limit is obeyed by the path finding
|
// runCltvLimit asserts that a cltv limit is obeyed by the path finding
|
||||||
// algorithm.
|
// algorithm.
|
||||||
func TestCltvLimit(t *testing.T) {
|
func runCltvLimit(t *testing.T, useCache bool) {
|
||||||
t.Run("no limit", func(t *testing.T) { testCltvLimit(t, 2016, 1) })
|
t.Run("no limit", func(t *testing.T) {
|
||||||
t.Run("no path", func(t *testing.T) { testCltvLimit(t, 50, 0) })
|
testCltvLimit(t, useCache, 2016, 1)
|
||||||
t.Run("force high cost", func(t *testing.T) { testCltvLimit(t, 80, 3) })
|
})
|
||||||
|
t.Run("no path", func(t *testing.T) {
|
||||||
|
testCltvLimit(t, useCache, 50, 0)
|
||||||
|
})
|
||||||
|
t.Run("force high cost", func(t *testing.T) {
|
||||||
|
testCltvLimit(t, useCache, 80, 3)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func testCltvLimit(t *testing.T, limit uint32, expectedChannel uint64) {
|
func testCltvLimit(t *testing.T, useCache bool, limit uint32,
|
||||||
|
expectedChannel uint64) {
|
||||||
|
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
// Set up a test graph with three possible paths to the target. The path
|
// Set up a test graph with three possible paths to the target. The path
|
||||||
@ -2561,7 +2634,7 @@ func testCltvLimit(t *testing.T, limit uint32, expectedChannel uint64) {
|
|||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := newPathFindingTestContext(t, testChannels, "roasbeef")
|
ctx := newPathFindingTestContext(t, useCache, testChannels, "roasbeef")
|
||||||
defer ctx.cleanup()
|
defer ctx.cleanup()
|
||||||
|
|
||||||
paymentAmt := lnwire.NewMSatFromSatoshis(100)
|
paymentAmt := lnwire.NewMSatFromSatoshis(100)
|
||||||
@ -2604,11 +2677,9 @@ func testCltvLimit(t *testing.T, limit uint32, expectedChannel uint64) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestProbabilityRouting asserts that path finding not only takes into account
|
// runProbabilityRouting asserts that path finding not only takes into account
|
||||||
// fees but also success probability.
|
// fees but also success probability.
|
||||||
func TestProbabilityRouting(t *testing.T) {
|
func runProbabilityRouting(t *testing.T, useCache bool) {
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
p10, p11, p20 float64
|
p10, p11, p20 float64
|
||||||
@ -2694,15 +2765,16 @@ func TestProbabilityRouting(t *testing.T) {
|
|||||||
|
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
testProbabilityRouting(
|
testProbabilityRouting(
|
||||||
t, tc.amount, tc.p10, tc.p11, tc.p20,
|
t, useCache, tc.amount, tc.p10, tc.p11, tc.p20,
|
||||||
tc.minProbability, tc.expectedChan,
|
tc.minProbability, tc.expectedChan,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testProbabilityRouting(t *testing.T, paymentAmt btcutil.Amount,
|
func testProbabilityRouting(t *testing.T, useCache bool,
|
||||||
p10, p11, p20, minProbability float64, expectedChan uint64) {
|
paymentAmt btcutil.Amount, p10, p11, p20, minProbability float64,
|
||||||
|
expectedChan uint64) {
|
||||||
|
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
@ -2729,7 +2801,7 @@ func testProbabilityRouting(t *testing.T, paymentAmt btcutil.Amount,
|
|||||||
}, 20),
|
}, 20),
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := newPathFindingTestContext(t, testChannels, "roasbeef")
|
ctx := newPathFindingTestContext(t, useCache, testChannels, "roasbeef")
|
||||||
defer ctx.cleanup()
|
defer ctx.cleanup()
|
||||||
|
|
||||||
alias := ctx.testGraphInstance.aliasMap
|
alias := ctx.testGraphInstance.aliasMap
|
||||||
@ -2783,11 +2855,9 @@ func testProbabilityRouting(t *testing.T, paymentAmt btcutil.Amount,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestEqualCostRouteSelection asserts that route probability will be used as a
|
// runEqualCostRouteSelection asserts that route probability will be used as a
|
||||||
// tie breaker in case the path finding probabilities are equal.
|
// tie breaker in case the path finding probabilities are equal.
|
||||||
func TestEqualCostRouteSelection(t *testing.T) {
|
func runEqualCostRouteSelection(t *testing.T, useCache bool) {
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
// Set up a test graph with two possible paths to the target: via a and
|
// Set up a test graph with two possible paths to the target: via a and
|
||||||
// via b. The routing fees and probabilities are chosen such that the
|
// via b. The routing fees and probabilities are chosen such that the
|
||||||
// algorithm will first explore target->a->source (backwards search).
|
// algorithm will first explore target->a->source (backwards search).
|
||||||
@ -2812,7 +2882,7 @@ func TestEqualCostRouteSelection(t *testing.T) {
|
|||||||
}, 2),
|
}, 2),
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := newPathFindingTestContext(t, testChannels, "source")
|
ctx := newPathFindingTestContext(t, useCache, testChannels, "source")
|
||||||
defer ctx.cleanup()
|
defer ctx.cleanup()
|
||||||
|
|
||||||
alias := ctx.testGraphInstance.aliasMap
|
alias := ctx.testGraphInstance.aliasMap
|
||||||
@ -2849,11 +2919,9 @@ func TestEqualCostRouteSelection(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestNoCycle tries to guide the path finding algorithm into reconstructing an
|
// runNoCycle tries to guide the path finding algorithm into reconstructing an
|
||||||
// endless route. It asserts that the algorithm is able to handle this properly.
|
// endless route. It asserts that the algorithm is able to handle this properly.
|
||||||
func TestNoCycle(t *testing.T) {
|
func runNoCycle(t *testing.T, useCache bool) {
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
// Set up a test graph with two paths: source->a->target and
|
// Set up a test graph with two paths: source->a->target and
|
||||||
// source->b->c->target. The fees are setup such that, searching
|
// source->b->c->target. The fees are setup such that, searching
|
||||||
// backwards, the algorithm will evaluate the following end of the route
|
// backwards, the algorithm will evaluate the following end of the route
|
||||||
@ -2883,7 +2951,7 @@ func TestNoCycle(t *testing.T) {
|
|||||||
}, 5),
|
}, 5),
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := newPathFindingTestContext(t, testChannels, "source")
|
ctx := newPathFindingTestContext(t, useCache, testChannels, "source")
|
||||||
defer ctx.cleanup()
|
defer ctx.cleanup()
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -2923,10 +2991,8 @@ func TestNoCycle(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestRouteToSelf tests that it is possible to find a route to the self node.
|
// runRouteToSelf tests that it is possible to find a route to the self node.
|
||||||
func TestRouteToSelf(t *testing.T) {
|
func runRouteToSelf(t *testing.T, useCache bool) {
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
testChannels := []*testChannel{
|
testChannels := []*testChannel{
|
||||||
symmetricTestChannel("source", "a", 100000, &testChannelPolicy{
|
symmetricTestChannel("source", "a", 100000, &testChannelPolicy{
|
||||||
Expiry: 144,
|
Expiry: 144,
|
||||||
@ -2942,7 +3008,7 @@ func TestRouteToSelf(t *testing.T) {
|
|||||||
}, 3),
|
}, 3),
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := newPathFindingTestContext(t, testChannels, "source")
|
ctx := newPathFindingTestContext(t, useCache, testChannels, "source")
|
||||||
defer ctx.cleanup()
|
defer ctx.cleanup()
|
||||||
|
|
||||||
paymentAmt := lnwire.NewMSatFromSatoshis(100)
|
paymentAmt := lnwire.NewMSatFromSatoshis(100)
|
||||||
@ -2980,11 +3046,11 @@ type pathFindingTestContext struct {
|
|||||||
source route.Vertex
|
source route.Vertex
|
||||||
}
|
}
|
||||||
|
|
||||||
func newPathFindingTestContext(t *testing.T, testChannels []*testChannel,
|
func newPathFindingTestContext(t *testing.T, useCache bool,
|
||||||
source string) *pathFindingTestContext {
|
testChannels []*testChannel, source string) *pathFindingTestContext {
|
||||||
|
|
||||||
testGraphInstance, err := createTestGraphFromChannels(
|
testGraphInstance, err := createTestGraphFromChannels(
|
||||||
testChannels, source,
|
useCache, testChannels, source,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to create graph: %v", err)
|
t.Fatalf("unable to create graph: %v", err)
|
||||||
|
@ -180,7 +180,7 @@ func TestRouterPaymentStateMachine(t *testing.T) {
|
|||||||
}, 2),
|
}, 2),
|
||||||
}
|
}
|
||||||
|
|
||||||
testGraph, err := createTestGraphFromChannels(testChannels, "a")
|
testGraph, err := createTestGraphFromChannels(true, testChannels, "a")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to create graph: %v", err)
|
t.Fatalf("unable to create graph: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -190,7 +190,7 @@ func createTestCtxFromGraphInstanceAssumeValid(t *testing.T,
|
|||||||
func createTestCtxSingleNode(t *testing.T,
|
func createTestCtxSingleNode(t *testing.T,
|
||||||
startingHeight uint32) (*testCtx, func()) {
|
startingHeight uint32) (*testCtx, func()) {
|
||||||
|
|
||||||
graph, graphBackend, cleanup, err := makeTestGraph()
|
graph, graphBackend, cleanup, err := makeTestGraph(true)
|
||||||
require.NoError(t, err, "failed to make test graph")
|
require.NoError(t, err, "failed to make test graph")
|
||||||
|
|
||||||
sourceNode, err := createTestNode()
|
sourceNode, err := createTestNode()
|
||||||
@ -216,7 +216,7 @@ func createTestCtxFromFile(t *testing.T,
|
|||||||
|
|
||||||
// We'll attempt to locate and parse out the file
|
// We'll attempt to locate and parse out the file
|
||||||
// that encodes the graph that our tests should be run against.
|
// that encodes the graph that our tests should be run against.
|
||||||
graphInstance, err := parseTestGraph(testGraph)
|
graphInstance, err := parseTestGraph(true, testGraph)
|
||||||
require.NoError(t, err, "unable to create test graph")
|
require.NoError(t, err, "unable to create test graph")
|
||||||
|
|
||||||
return createTestCtxFromGraphInstance(
|
return createTestCtxFromGraphInstance(
|
||||||
@ -387,7 +387,7 @@ func TestChannelUpdateValidation(t *testing.T) {
|
|||||||
}, 2),
|
}, 2),
|
||||||
}
|
}
|
||||||
|
|
||||||
testGraph, err := createTestGraphFromChannels(testChannels, "a")
|
testGraph, err := createTestGraphFromChannels(true, testChannels, "a")
|
||||||
require.NoError(t, err, "unable to create graph")
|
require.NoError(t, err, "unable to create graph")
|
||||||
defer testGraph.cleanUp()
|
defer testGraph.cleanUp()
|
||||||
|
|
||||||
@ -1246,7 +1246,7 @@ func TestIgnoreChannelEdgePolicyForUnknownChannel(t *testing.T) {
|
|||||||
// Setup an initially empty network.
|
// Setup an initially empty network.
|
||||||
testChannels := []*testChannel{}
|
testChannels := []*testChannel{}
|
||||||
testGraph, err := createTestGraphFromChannels(
|
testGraph, err := createTestGraphFromChannels(
|
||||||
testChannels, "roasbeef",
|
true, testChannels, "roasbeef",
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to create graph: %v", err)
|
t.Fatalf("unable to create graph: %v", err)
|
||||||
@ -2260,7 +2260,9 @@ func TestPruneChannelGraphStaleEdges(t *testing.T) {
|
|||||||
for _, strictPruning := range []bool{true, false} {
|
for _, strictPruning := range []bool{true, false} {
|
||||||
// We'll create our test graph and router backed with these test
|
// We'll create our test graph and router backed with these test
|
||||||
// channels we've created.
|
// channels we've created.
|
||||||
testGraph, err := createTestGraphFromChannels(testChannels, "a")
|
testGraph, err := createTestGraphFromChannels(
|
||||||
|
true, testChannels, "a",
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to create test graph: %v", err)
|
t.Fatalf("unable to create test graph: %v", err)
|
||||||
}
|
}
|
||||||
@ -2390,7 +2392,9 @@ func testPruneChannelGraphDoubleDisabled(t *testing.T, assumeValid bool) {
|
|||||||
|
|
||||||
// We'll create our test graph and router backed with these test
|
// We'll create our test graph and router backed with these test
|
||||||
// channels we've created.
|
// channels we've created.
|
||||||
testGraph, err := createTestGraphFromChannels(testChannels, "self")
|
testGraph, err := createTestGraphFromChannels(
|
||||||
|
true, testChannels, "self",
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to create test graph: %v", err)
|
t.Fatalf("unable to create test graph: %v", err)
|
||||||
}
|
}
|
||||||
@ -2760,7 +2764,7 @@ func TestUnknownErrorSource(t *testing.T) {
|
|||||||
}, 4),
|
}, 4),
|
||||||
}
|
}
|
||||||
|
|
||||||
testGraph, err := createTestGraphFromChannels(testChannels, "a")
|
testGraph, err := createTestGraphFromChannels(true, testChannels, "a")
|
||||||
defer testGraph.cleanUp()
|
defer testGraph.cleanUp()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to create graph: %v", err)
|
t.Fatalf("unable to create graph: %v", err)
|
||||||
@ -2896,7 +2900,7 @@ func TestSendToRouteStructuredError(t *testing.T) {
|
|||||||
}, 2),
|
}, 2),
|
||||||
}
|
}
|
||||||
|
|
||||||
testGraph, err := createTestGraphFromChannels(testChannels, "a")
|
testGraph, err := createTestGraphFromChannels(true, testChannels, "a")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to create graph: %v", err)
|
t.Fatalf("unable to create graph: %v", err)
|
||||||
}
|
}
|
||||||
@ -3145,7 +3149,7 @@ func TestSendToRouteMaxHops(t *testing.T) {
|
|||||||
}, 1),
|
}, 1),
|
||||||
}
|
}
|
||||||
|
|
||||||
testGraph, err := createTestGraphFromChannels(testChannels, "a")
|
testGraph, err := createTestGraphFromChannels(true, testChannels, "a")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to create graph: %v", err)
|
t.Fatalf("unable to create graph: %v", err)
|
||||||
}
|
}
|
||||||
@ -3256,7 +3260,7 @@ func TestBuildRoute(t *testing.T) {
|
|||||||
}, 4),
|
}, 4),
|
||||||
}
|
}
|
||||||
|
|
||||||
testGraph, err := createTestGraphFromChannels(testChannels, "a")
|
testGraph, err := createTestGraphFromChannels(true, testChannels, "a")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to create graph: %v", err)
|
t.Fatalf("unable to create graph: %v", err)
|
||||||
}
|
}
|
||||||
@ -3496,7 +3500,7 @@ func createDummyTestGraph(t *testing.T) *testGraphInstance {
|
|||||||
}, 2),
|
}, 2),
|
||||||
}
|
}
|
||||||
|
|
||||||
testGraph, err := createTestGraphFromChannels(testChannels, "a")
|
testGraph, err := createTestGraphFromChannels(true, testChannels, "a")
|
||||||
require.NoError(t, err, "failed to create graph")
|
require.NoError(t, err, "failed to create graph")
|
||||||
return testGraph
|
return testGraph
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user