lnrpc+routing: fix issues with missing data in unmarshallRoute

In this commit the dependency of unmarshallRoute on edge policies being
available is removed. Edge policies may be unknown and reported as nil.
SendToRoute does not need the policies, but it does need pubkeys of the
route hops. In this commit, unmarshallRoute is modified so that it
takes the pubkeys from edgeInfo instead of channelEdgePolicy.

In addition to this, the route structure is simplified. No more connection
to the database at that point. Fees are determined based on incoming and
outgoing amounts.
This commit is contained in:
Joost Jager
2018-08-09 15:36:28 +02:00
parent e5b84cfada
commit a779004a18
6 changed files with 269 additions and 276 deletions

View File

@@ -592,14 +592,26 @@ func TestFindLowestFeePath(t *testing.T) {
}
// Assert that the lowest fee route is returned.
if !bytes.Equal(route.Hops[1].Channel.Node.PubKeyBytes[:],
if !bytes.Equal(route.Hops[1].PubKeyBytes[:],
testGraphInstance.aliasMap["b"].SerializeCompressed()) {
t.Fatalf("expected route to pass through b, "+
"but got a route through %v",
route.Hops[1].Channel.Node.Alias)
getAliasFromPubKey(route.Hops[1].PubKeyBytes[:],
testGraphInstance.aliasMap))
}
}
func getAliasFromPubKey(pubKey []byte,
aliases map[string]*btcec.PublicKey) string {
for alias, key := range aliases {
if bytes.Equal(key.SerializeCompressed(), pubKey) {
return alias
}
}
return ""
}
type expectedHop struct {
alias string
fee lnwire.MilliSatoshi
@@ -733,11 +745,13 @@ func testBasicGraphPathFindingCase(t *testing.T, graphInstance *testGraphInstanc
// Check hop nodes
for i := 0; i < len(expectedHops); i++ {
if !bytes.Equal(route.Hops[i].Channel.Node.PubKeyBytes[:],
if !bytes.Equal(route.Hops[i].PubKeyBytes[:],
aliases[expectedHops[i].alias].SerializeCompressed()) {
t.Fatalf("%v-th hop should be %v, is instead: %v",
i, expectedHops[i], route.Hops[i].Channel.Node.Alias)
i, expectedHops[i],
getAliasFromPubKey(route.Hops[i].PubKeyBytes[:],
aliases))
}
}
@@ -753,7 +767,7 @@ func testBasicGraphPathFindingCase(t *testing.T, graphInstance *testGraphInstanc
// Hops should point to the next hop
for i := 0; i < len(expectedHops)-1; i++ {
var expectedHop [8]byte
binary.BigEndian.PutUint64(expectedHop[:], route.Hops[i+1].Channel.ChannelID)
binary.BigEndian.PutUint64(expectedHop[:], route.Hops[i+1].ChannelID)
if !bytes.Equal(hopPayloads[i].NextAddress[:], expectedHop[:]) {
t.Fatalf("first hop has incorrect next hop: expected %x, got %x",
expectedHop[:], hopPayloads[i].NextAddress)
@@ -774,9 +788,10 @@ func testBasicGraphPathFindingCase(t *testing.T, graphInstance *testGraphInstanc
// We'll ensure that the amount to forward, and fees
// computed for each hop are correct.
if route.Hops[i].Fee != expectedHops[i].fee {
fee := route.HopFee(i)
if fee != expectedHops[i].fee {
t.Fatalf("fee incorrect for hop %v: expected %v, got %v",
i, expectedHops[i].fee, route.Hops[i].Fee)
i, expectedHops[i].fee, fee)
}
if route.Hops[i].AmtToForward != expectedHops[i].fwdAmount {
@@ -815,9 +830,9 @@ func testBasicGraphPathFindingCase(t *testing.T, graphInstance *testGraphInstanc
if !ok {
t.Fatalf("hop didn't have prev chan but should have")
}
if prevChan.ChannelID != route.Hops[i].Channel.ChannelID {
if prevChan.ChannelID != route.Hops[i].ChannelID {
t.Fatalf("incorrect prev chan: expected %v, got %v",
prevChan.ChannelID, route.Hops[i].Channel.ChannelID)
prevChan.ChannelID, route.Hops[i].ChannelID)
}
}
@@ -826,9 +841,9 @@ func testBasicGraphPathFindingCase(t *testing.T, graphInstance *testGraphInstanc
if !ok {
t.Fatalf("hop didn't have prev chan but should have")
}
if nextChan.ChannelID != route.Hops[i+1].Channel.ChannelID {
if nextChan.ChannelID != route.Hops[i+1].ChannelID {
t.Fatalf("incorrect prev chan: expected %v, got %v",
nextChan.ChannelID, route.Hops[i+1].Channel.ChannelID)
nextChan.ChannelID, route.Hops[i+1].ChannelID)
}
}
@@ -969,16 +984,13 @@ func TestNewRoute(t *testing.T) {
createHop := func(baseFee lnwire.MilliSatoshi,
feeRate lnwire.MilliSatoshi,
bandwidth lnwire.MilliSatoshi,
timeLockDelta uint16) *ChannelHop {
timeLockDelta uint16) *channeldb.ChannelEdgePolicy {
return &ChannelHop{
ChannelEdgePolicy: &channeldb.ChannelEdgePolicy{
Node: &channeldb.LightningNode{},
FeeProportionalMillionths: feeRate,
FeeBaseMSat: baseFee,
TimeLockDelta: timeLockDelta,
},
Bandwidth: bandwidth,
return &channeldb.ChannelEdgePolicy{
Node: &channeldb.LightningNode{},
FeeProportionalMillionths: feeRate,
FeeBaseMSat: baseFee,
TimeLockDelta: timeLockDelta,
}
}
@@ -988,7 +1000,7 @@ func TestNewRoute(t *testing.T) {
// hops is the list of hops (the route) that gets passed into
// the call to newRoute.
hops []*ChannelHop
hops []*channeldb.ChannelEdgePolicy
// paymentAmount is the amount that is send into the route
// indicated by hops.
@@ -1029,7 +1041,7 @@ func TestNewRoute(t *testing.T) {
// For a single hop payment, no fees are expected to be paid.
name: "single hop",
paymentAmount: 100000,
hops: []*ChannelHop{
hops: []*channeldb.ChannelEdgePolicy{
createHop(100, 1000, 1000000, 10),
},
expectedFees: []lnwire.MilliSatoshi{0},
@@ -1043,7 +1055,7 @@ func TestNewRoute(t *testing.T) {
// a fee to receive the payment.
name: "two hop",
paymentAmount: 100000,
hops: []*ChannelHop{
hops: []*channeldb.ChannelEdgePolicy{
createHop(0, 1000, 1000000, 10),
createHop(30, 1000, 1000000, 5),
},
@@ -1052,17 +1064,6 @@ func TestNewRoute(t *testing.T) {
expectedTotalAmount: 100130,
expectedTotalTimeLock: 6,
feeLimit: noFeeLimit,
}, {
// Insufficient capacity in first channel when fees are added.
name: "two hop insufficient",
paymentAmount: 100000,
hops: []*ChannelHop{
createHop(0, 1000, 100000, 10),
createHop(0, 1000, 1000000, 5),
},
feeLimit: noFeeLimit,
expectError: true,
expectedErrorCode: ErrInsufficientCapacity,
}, {
// A three hop payment where the first and second hop
// will both charge 1 msat. The fee for the first hop
@@ -1071,7 +1072,7 @@ func TestNewRoute(t *testing.T) {
// gets rounded down to 1.
name: "three hop",
paymentAmount: 100000,
hops: []*ChannelHop{
hops: []*channeldb.ChannelEdgePolicy{
createHop(0, 10, 1000000, 10),
createHop(0, 10, 1000000, 5),
createHop(0, 10, 1000000, 3),
@@ -1087,7 +1088,7 @@ func TestNewRoute(t *testing.T) {
// because of the increase amount to forward.
name: "three hop with fee carry over",
paymentAmount: 100000,
hops: []*ChannelHop{
hops: []*channeldb.ChannelEdgePolicy{
createHop(0, 10000, 1000000, 10),
createHop(0, 10000, 1000000, 5),
createHop(0, 10000, 1000000, 3),
@@ -1103,7 +1104,7 @@ func TestNewRoute(t *testing.T) {
// effect.
name: "three hop with minimal fees for carry over",
paymentAmount: 100000,
hops: []*ChannelHop{
hops: []*channeldb.ChannelEdgePolicy{
createHop(0, 10000, 1000000, 10),
// First hop charges 0.1% so the second hop fee
@@ -1124,7 +1125,7 @@ func TestNewRoute(t *testing.T) {
{
name: "two hop success with fee limit (greater)",
paymentAmount: 100000,
hops: []*ChannelHop{
hops: []*channeldb.ChannelEdgePolicy{
createHop(0, 1000, 1000000, 144),
createHop(0, 1000, 1000000, 144),
},
@@ -1136,7 +1137,7 @@ func TestNewRoute(t *testing.T) {
}, {
name: "two hop success with fee limit (equal)",
paymentAmount: 100000,
hops: []*ChannelHop{
hops: []*channeldb.ChannelEdgePolicy{
createHop(0, 1000, 1000000, 144),
createHop(0, 1000, 1000000, 144),
},
@@ -1148,7 +1149,7 @@ func TestNewRoute(t *testing.T) {
}, {
name: "two hop failure with fee limit (smaller)",
paymentAmount: 100000,
hops: []*ChannelHop{
hops: []*channeldb.ChannelEdgePolicy{
createHop(0, 1000, 1000000, 144),
createHop(0, 1000, 1000000, 144),
},
@@ -1158,7 +1159,7 @@ func TestNewRoute(t *testing.T) {
}, {
name: "two hop failure with fee limit (zero)",
paymentAmount: 100000,
hops: []*ChannelHop{
hops: []*channeldb.ChannelEdgePolicy{
createHop(0, 1000, 1000000, 144),
createHop(0, 1000, 1000000, 144),
},
@@ -1177,13 +1178,13 @@ func TestNewRoute(t *testing.T) {
}
for i := 0; i < len(testCase.expectedFees); i++ {
if testCase.expectedFees[i] !=
route.Hops[i].Fee {
fee := route.HopFee(i)
if testCase.expectedFees[i] != fee {
t.Errorf("Expected fee for hop %v to "+
"be %v, but got %v instead",
i, testCase.expectedFees[i],
route.Hops[i].Fee)
fee)
}
}
@@ -1515,9 +1516,10 @@ func TestPathFindSpecExample(t *testing.T) {
t.Fatalf("wrong forward amount: got %v, expected %v",
firstRoute.Hops[0].AmtToForward, amt)
}
if firstRoute.Hops[0].Fee != 0 {
t.Fatalf("wrong hop fee: got %v, expected %v",
firstRoute.Hops[0].Fee, 0)
fee := firstRoute.HopFee(0)
if fee != 0 {
t.Fatalf("wrong hop fee: got %v, expected %v", fee, 0)
}
// The CLTV expiry should be the current height plus 9 (the expiry for
@@ -1600,16 +1602,17 @@ func TestPathFindSpecExample(t *testing.T) {
// hop, so we should get a fee of exactly:
//
// * 200 + 4999999 * 2000 / 1000000 = 10199
if routes[0].Hops[0].Fee != 10199 {
t.Fatalf("wrong hop fee: got %v, expected %v",
routes[0].Hops[0].Fee, 10199)
fee = routes[0].HopFee(0)
if fee != 10199 {
t.Fatalf("wrong hop fee: got %v, expected %v", fee, 10199)
}
// While for the final hop, as there's no additional hop afterwards, we
// pay no fee.
if routes[0].Hops[1].Fee != 0 {
t.Fatalf("wrong hop fee: got %v, expected %v",
routes[0].Hops[0].Fee, 0)
fee = routes[0].HopFee(1)
if fee != 0 {
t.Fatalf("wrong hop fee: got %v, expected %v", fee, 0)
}
// The outgoing CLTV value itself should be the current height plus 30
@@ -1677,7 +1680,9 @@ func TestPathFindSpecExample(t *testing.T) {
}
}
func assertExpectedPath(t *testing.T, path []*ChannelHop, nodeAliases ...string) {
func assertExpectedPath(t *testing.T, path []*channeldb.ChannelEdgePolicy,
nodeAliases ...string) {
if len(path) != len(nodeAliases) {
t.Fatal("number of hops and number of aliases do not match")
}