mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-08-02 09:42:31 +02:00
routing+routerrpc: add BuildRoute function
This commit is contained in:
@@ -3330,3 +3330,146 @@ func TestSendToRouteStructuredError(t *testing.T) {
|
||||
t.Fatalf("initPayment not called")
|
||||
}
|
||||
}
|
||||
|
||||
// TestBuildRoute tests whether correct routes are built.
|
||||
func TestBuildRoute(t *testing.T) {
|
||||
// Setup a three node network.
|
||||
chanCapSat := btcutil.Amount(100000)
|
||||
testChannels := []*testChannel{
|
||||
// Create two local channels from a. The bandwidth is estimated
|
||||
// in this test as the channel capacity. For building routes, we
|
||||
// expected the channel with the largest estimated bandwidth to
|
||||
// be selected.
|
||||
symmetricTestChannel("a", "b", chanCapSat, &testChannelPolicy{
|
||||
Expiry: 144,
|
||||
FeeRate: 20000,
|
||||
MinHTLC: lnwire.NewMSatFromSatoshis(5),
|
||||
MaxHTLC: lnwire.NewMSatFromSatoshis(chanCapSat),
|
||||
}, 1),
|
||||
symmetricTestChannel("a", "b", chanCapSat/2, &testChannelPolicy{
|
||||
Expiry: 144,
|
||||
FeeRate: 20000,
|
||||
MinHTLC: lnwire.NewMSatFromSatoshis(5),
|
||||
MaxHTLC: lnwire.NewMSatFromSatoshis(chanCapSat / 2),
|
||||
}, 6),
|
||||
|
||||
// Create two channels from b to c. For building routes, we
|
||||
// expect the lowest cost channel to be selected. Note that this
|
||||
// isn't a situation that we are expecting in reality. Routing
|
||||
// nodes are recommended to keep their channel policies towards
|
||||
// the same peer identical.
|
||||
symmetricTestChannel("b", "c", chanCapSat, &testChannelPolicy{
|
||||
Expiry: 144,
|
||||
FeeRate: 50000,
|
||||
MinHTLC: lnwire.NewMSatFromSatoshis(20),
|
||||
MaxHTLC: lnwire.NewMSatFromSatoshis(120),
|
||||
}, 2),
|
||||
symmetricTestChannel("b", "c", chanCapSat, &testChannelPolicy{
|
||||
Expiry: 144,
|
||||
FeeRate: 60000,
|
||||
MinHTLC: lnwire.NewMSatFromSatoshis(20),
|
||||
MaxHTLC: lnwire.NewMSatFromSatoshis(120),
|
||||
}, 7),
|
||||
|
||||
symmetricTestChannel("a", "e", chanCapSat, &testChannelPolicy{
|
||||
Expiry: 144,
|
||||
FeeRate: 80000,
|
||||
MinHTLC: lnwire.NewMSatFromSatoshis(5),
|
||||
MaxHTLC: lnwire.NewMSatFromSatoshis(10),
|
||||
}, 5),
|
||||
symmetricTestChannel("e", "c", chanCapSat, &testChannelPolicy{
|
||||
Expiry: 144,
|
||||
FeeRate: 100000,
|
||||
MinHTLC: lnwire.NewMSatFromSatoshis(20),
|
||||
MaxHTLC: lnwire.NewMSatFromSatoshis(chanCapSat),
|
||||
}, 4),
|
||||
}
|
||||
|
||||
testGraph, err := createTestGraphFromChannels(testChannels, "a")
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create graph: %v", err)
|
||||
}
|
||||
defer testGraph.cleanUp()
|
||||
|
||||
const startingBlockHeight = 101
|
||||
|
||||
ctx, cleanUp, err := createTestCtxFromGraphInstance(
|
||||
startingBlockHeight, testGraph,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create router: %v", err)
|
||||
}
|
||||
defer cleanUp()
|
||||
|
||||
checkHops := func(rt *route.Route, expected []uint64) {
|
||||
if len(rt.Hops) != len(expected) {
|
||||
t.Fatal("hop count mismatch")
|
||||
}
|
||||
for i, hop := range rt.Hops {
|
||||
if hop.ChannelID != expected[i] {
|
||||
t.Fatalf("expected channel %v at pos %v, but "+
|
||||
"got channel %v",
|
||||
expected[i], i, hop.ChannelID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create hop list from the route node pubkeys.
|
||||
hops := []route.Vertex{
|
||||
ctx.aliases["b"], ctx.aliases["c"],
|
||||
}
|
||||
amt := lnwire.NewMSatFromSatoshis(100)
|
||||
|
||||
// Build the route for the given amount.
|
||||
rt, err := ctx.router.BuildRoute(
|
||||
&amt, hops, nil, 40,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Check that we get the expected route back. The total amount should be
|
||||
// the amount to deliver to hop c (100 sats) plus the fee for hop b (5
|
||||
// sats).
|
||||
checkHops(rt, []uint64{1, 2})
|
||||
if rt.TotalAmount != 105000 {
|
||||
t.Fatalf("unexpected total amount %v", rt.TotalAmount)
|
||||
}
|
||||
|
||||
// Build the route for the minimum amount.
|
||||
rt, err = ctx.router.BuildRoute(
|
||||
nil, hops, nil, 40,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Check that we get the expected route back. The minimum that we can
|
||||
// send from b to c is 20 sats. Hop b charges 1 sat for the forwarding.
|
||||
// The channel between hop a and b can carry amounts in the range [5,
|
||||
// 100], so 21 sats is the minimum amount for this route.
|
||||
checkHops(rt, []uint64{1, 2})
|
||||
if rt.TotalAmount != 21000 {
|
||||
t.Fatalf("unexpected total amount %v", rt.TotalAmount)
|
||||
}
|
||||
|
||||
// Test a route that contains incompatible channel htlc constraints.
|
||||
// There is no amount that can pass through both channel 5 and 4.
|
||||
hops = []route.Vertex{
|
||||
ctx.aliases["e"], ctx.aliases["c"],
|
||||
}
|
||||
_, err = ctx.router.BuildRoute(
|
||||
nil, hops, nil, 40,
|
||||
)
|
||||
errNoChannel, ok := err.(ErrNoChannel)
|
||||
if !ok {
|
||||
t.Fatalf("expected incompatible policies error, but got %v",
|
||||
err)
|
||||
}
|
||||
if errNoChannel.position != 0 {
|
||||
t.Fatalf("unexpected no channel error position")
|
||||
}
|
||||
if errNoChannel.fromNode != ctx.aliases["a"] {
|
||||
t.Fatalf("unexpected no channel error node")
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user