Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

routing: fix route fee calculation and channel capacity check #1382

Merged
merged 3 commits into from
Jun 29, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 97 additions & 24 deletions lnd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ var (
harnessNetParams = &chaincfg.SimNetParams
)

const (
testFeeBase = 1e+6
)

// harnessTest wraps a regular testing.T providing enhanced error detection
// and propagation. All error will be augmented with a full stack-trace in
// order to aid in debugging. Additionally, any panics caused by active
Expand Down Expand Up @@ -876,14 +880,13 @@ func testUpdateChannelPolicy(net *lntest.NetworkHarness, t *harnessTest) {
// With our little cluster set up, we'll update the fees for the
// channel Bob side of the Alice->Bob channel, and make sure all nodes
// learn about it.
const feeBase = 1000000
baseFee := int64(1500)
feeRate := int64(12)
timeLockDelta := uint32(66)

expectedPolicy := &lnrpc.RoutingPolicy{
FeeBaseMsat: baseFee,
FeeRateMilliMsat: feeBase * feeRate,
FeeRateMilliMsat: testFeeBase * feeRate,
TimeLockDelta: timeLockDelta,
}

Expand Down Expand Up @@ -971,7 +974,7 @@ func testUpdateChannelPolicy(net *lntest.NetworkHarness, t *harnessTest) {
timeLockDelta = uint32(22)

expectedPolicy.FeeBaseMsat = baseFee
expectedPolicy.FeeRateMilliMsat = feeBase * feeRate
expectedPolicy.FeeRateMilliMsat = testFeeBase * feeRate
expectedPolicy.TimeLockDelta = timeLockDelta

req = &lnrpc.PolicyUpdateRequest{
Expand Down Expand Up @@ -2773,6 +2776,48 @@ func assertAmountPaid(t *harnessTest, ctxb context.Context, channelName string,
}
}

// updateChannelPolicy updates the channel policy of node to the
// given fees and timelock delta. This function blocks until
// listenerNode has received the policy update.
func updateChannelPolicy(t *harnessTest, node *lntest.HarnessNode,
chanPoint *lnrpc.ChannelPoint, baseFee int64, feeRate int64,
timeLockDelta uint32, listenerNode *lntest.HarnessNode) {

ctxb := context.Background()
timeout := time.Duration(time.Second * 15)

expectedPolicy := &lnrpc.RoutingPolicy{
FeeBaseMsat: baseFee,
FeeRateMilliMsat: feeRate,
TimeLockDelta: timeLockDelta,
}

updateFeeReq := &lnrpc.PolicyUpdateRequest{
BaseFeeMsat: baseFee,
FeeRate: float64(feeRate) / testFeeBase,
TimeLockDelta: timeLockDelta,
Scope: &lnrpc.PolicyUpdateRequest_ChanPoint{
ChanPoint: chanPoint,
},
}

ctxt, _ := context.WithTimeout(ctxb, timeout)
if _, err := node.UpdateChannelPolicy(ctxt, updateFeeReq); err != nil {
t.Fatalf("unable to update chan policy: %v", err)
}

// Wait for listener node to receive the channel update from node.
ctxt, _ = context.WithTimeout(ctxb, timeout)
listenerUpdates, aQuit := subscribeGraphNotifications(t, ctxt,
listenerNode)
defer close(aQuit)

waitForChannelUpdate(
t, listenerUpdates, node.PubKeyStr, expectedPolicy,
chanPoint,
)
}

func testMultiHopPayments(net *lntest.NetworkHarness, t *harnessTest) {
const chanAmt = btcutil.Amount(100000)
ctxb := context.Background()
Expand Down Expand Up @@ -2934,6 +2979,15 @@ func testMultiHopPayments(net *lntest.NetworkHarness, t *harnessTest) {

time.Sleep(time.Millisecond * 50)

// Set the fee policies of the Alice -> Bob and the Dave -> Alice
// channel edges to relatively large non default values. This makes it
// possible to pick up more subtle fee calculation errors.
updateChannelPolicy(t, net.Alice, chanPointAlice, 1000, 100000,
144, carol)

updateChannelPolicy(t, dave, chanPointDave, 5000, 150000,
144, carol)

// Using Carol as the source, pay to the 5 invoices from Bob created
// above.
ctxt, _ = context.WithTimeout(ctxb, timeout)
Expand All @@ -2953,42 +3007,61 @@ func testMultiHopPayments(net *lntest.NetworkHarness, t *harnessTest) {
// increasing of time is needed to embed the HTLC in commitment
// transaction, in channel Carol->David->Alice->Bob, order is Bob,
// Alice, David, Carol.
const amountPaid = int64(5000)

// The final node bob expects to get paid five times 1000 sat.
expectedAmountPaidAtoB := int64(5 * 1000)

assertAmountPaid(t, ctxb, "Alice(local) => Bob(remote)", net.Bob,
aliceFundPoint, int64(0), amountPaid)
aliceFundPoint, int64(0), expectedAmountPaidAtoB)
assertAmountPaid(t, ctxb, "Alice(local) => Bob(remote)", net.Alice,
aliceFundPoint, amountPaid, int64(0))
aliceFundPoint, expectedAmountPaidAtoB, int64(0))

// To forward a payment of 1000 sat, Alice is charging a fee of
// 1 sat + 10% = 101 sat.
const expectedFeeAlice = 5 * 101

// Dave needs to pay what Alice pays plus Alice's fee.
expectedAmountPaidDtoA := expectedAmountPaidAtoB + expectedFeeAlice

assertAmountPaid(t, ctxb, "Dave(local) => Alice(remote)", net.Alice,
daveFundPoint, int64(0), amountPaid+(baseFee*numPayments))
daveFundPoint, int64(0), expectedAmountPaidDtoA)
assertAmountPaid(t, ctxb, "Dave(local) => Alice(remote)", dave,
daveFundPoint, amountPaid+(baseFee*numPayments), int64(0))
daveFundPoint, expectedAmountPaidDtoA, int64(0))

// To forward a payment of 1101 sat, Dave is charging a fee of
// 5 sat + 15% = 170.15 sat. This is rounded down in rpcserver to 170.
const expectedFeeDave = 5 * 170

// Carol needs to pay what Dave pays plus Dave's fee.
expectedAmountPaidCtoD := expectedAmountPaidDtoA + expectedFeeDave

assertAmountPaid(t, ctxb, "Carol(local) => Dave(remote)", dave,
carolFundPoint, int64(0), amountPaid+((baseFee*numPayments)*2))
carolFundPoint, int64(0), expectedAmountPaidCtoD)
assertAmountPaid(t, ctxb, "Carol(local) => Dave(remote)", carol,
carolFundPoint, amountPaid+(baseFee*numPayments)*2, int64(0))
carolFundPoint, expectedAmountPaidCtoD, int64(0))

// Now that we know all the balances have been settled out properly,
// we'll ensure that our internal record keeping for completed circuits
// was properly updated.

// First, check that the FeeReport response shows the proper fees
// accrued over each time range. Dave should've earned 1 satoshi for
// accrued over each time range. Dave should've earned 170 satoshi for
// each of the forwarded payments.
feeReport, err := dave.FeeReport(ctxb, &lnrpc.FeeReportRequest{})
if err != nil {
t.Fatalf("unable to query for fee report: %v", err)
}
const exectedFees = 5
if feeReport.DayFeeSum != exectedFees {
t.Fatalf("fee mismatch: expected %v, got %v", 5,

if feeReport.DayFeeSum != uint64(expectedFeeDave) {
t.Fatalf("fee mismatch: expected %v, got %v", expectedFeeDave,
feeReport.DayFeeSum)
}
if feeReport.WeekFeeSum != exectedFees {
t.Fatalf("fee mismatch: expected %v, got %v", 5,
if feeReport.WeekFeeSum != uint64(expectedFeeDave) {
t.Fatalf("fee mismatch: expected %v, got %v", expectedFeeDave,
feeReport.WeekFeeSum)
}
if feeReport.MonthFeeSum != exectedFees {
t.Fatalf("fee mismatch: expected %v, got %v", 5,
if feeReport.MonthFeeSum != uint64(expectedFeeDave) {
t.Fatalf("fee mismatch: expected %v, got %v", expectedFeeDave,
feeReport.MonthFeeSum)
}

Expand All @@ -3004,11 +3077,12 @@ func testMultiHopPayments(net *lntest.NetworkHarness, t *harnessTest) {
t.Fatalf("wrong number of forwarding event: expected %v, "+
"got %v", 5, len(fwdingHistory.ForwardingEvents))
}
expectedForwardingFee := uint64(expectedFeeDave / numPayments)
for _, event := range fwdingHistory.ForwardingEvents {
// Each event should show a fee of 1 satoshi.
if event.Fee != 1 {
t.Fatalf("fee mismatch: expected %v, got %v", 1,
event.Fee)
// Each event should show a fee of 170 satoshi.
if event.Fee != expectedForwardingFee {
t.Fatalf("fee mismatch: expected %v, got %v",
expectedForwardingFee, event.Fee)
}
}

Expand Down Expand Up @@ -9775,14 +9849,13 @@ func testRouteFeeCutoff(net *lntest.NetworkHarness, t *harnessTest) {
// Therefore, we'll update the fee policy on Carol's side for the
// channel between her and Dave to invalidate the route:
// Alice -> Carol -> Dave
const feeBase = 1e+6
baseFee := int64(10000)
feeRate := int64(5)
timeLockDelta := uint32(144)

expectedPolicy := &lnrpc.RoutingPolicy{
FeeBaseMsat: baseFee,
FeeRateMilliMsat: feeBase * feeRate,
FeeRateMilliMsat: testFeeBase * feeRate,
TimeLockDelta: timeLockDelta,
}

Expand Down
Loading