Skip to content

Commit 7f9fbbe

Browse files
authored
Merge pull request #8941 from bitromortac/fee-limit-inbound
routing: fix fee limit condition
2 parents a1af505 + 0358b3a commit 7f9fbbe

File tree

5 files changed

+104
-11
lines changed

5 files changed

+104
-11
lines changed

docs/release-notes/release-notes-0.18.3.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@
3636
* [Fixed a bug](https://github.com/lightningnetwork/lnd/pull/8896) that caused
3737
LND to use a default fee rate for the batch channel opening flow.
3838

39+
* The fee limit for payments [was made
40+
compatible](https://github.com/lightningnetwork/lnd/pull/8941) with inbound
41+
fees.
42+
3943
# New Features
4044
## Functional Enhancements
4145
## RPC Additions
@@ -150,6 +154,7 @@
150154
# Contributors (Alphabetical Order)
151155

152156
* Andras Banki-Horvath
157+
* bitromortac
153158
* Bufo
154159
* Elle Mouton
155160
* Matheus Degiovani

itest/list_on_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,10 @@ var allTestCases = []*lntest.TestCase{
354354
Name: "route fee cutoff",
355355
TestFunc: testRouteFeeCutoff,
356356
},
357+
{
358+
Name: "route fee limit after queryroutes",
359+
TestFunc: testFeeLimitAfterQueryRoutes,
360+
},
357361
{
358362
Name: "rpc middleware interceptor",
359363
TestFunc: testRPCMiddlewareInterceptor,

itest/lnd_routing_test.go

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1331,6 +1331,80 @@ func testRouteFeeCutoff(ht *lntest.HarnessTest) {
13311331
ht.CloseChannel(carol, chanPointCarolDave)
13321332
}
13331333

1334+
// testFeeLimitAfterQueryRoutes tests that a payment's fee limit is consistent
1335+
// with the fee of a queried route.
1336+
func testFeeLimitAfterQueryRoutes(ht *lntest.HarnessTest) {
1337+
// Create a three hop network: Alice -> Bob -> Carol.
1338+
chanAmt := btcutil.Amount(100000)
1339+
chanPoints, nodes := createSimpleNetwork(
1340+
ht, []string{}, 3, lntest.OpenChannelParams{Amt: chanAmt},
1341+
)
1342+
alice, bob, carol := nodes[0], nodes[1], nodes[2]
1343+
chanPointAliceBob, chanPointBobCarol := chanPoints[0], chanPoints[1]
1344+
1345+
// We set an inbound fee discount on Bob's channel to Alice to
1346+
// effectively set the outbound fees charged to Carol to zero.
1347+
expectedPolicy := &lnrpc.RoutingPolicy{
1348+
FeeBaseMsat: 1000,
1349+
FeeRateMilliMsat: 1,
1350+
InboundFeeBaseMsat: -1000,
1351+
InboundFeeRateMilliMsat: -1,
1352+
TimeLockDelta: uint32(
1353+
chainreg.DefaultBitcoinTimeLockDelta,
1354+
),
1355+
MinHtlc: 1000,
1356+
MaxHtlcMsat: lntest.CalculateMaxHtlc(chanAmt),
1357+
}
1358+
1359+
updateFeeReq := &lnrpc.PolicyUpdateRequest{
1360+
Scope: &lnrpc.PolicyUpdateRequest_ChanPoint{
1361+
ChanPoint: chanPointAliceBob,
1362+
},
1363+
BaseFeeMsat: expectedPolicy.FeeBaseMsat,
1364+
FeeRatePpm: uint32(expectedPolicy.FeeRateMilliMsat),
1365+
TimeLockDelta: expectedPolicy.TimeLockDelta,
1366+
MaxHtlcMsat: expectedPolicy.MaxHtlcMsat,
1367+
InboundFee: &lnrpc.InboundFee{
1368+
BaseFeeMsat: expectedPolicy.InboundFeeBaseMsat,
1369+
FeeRatePpm: expectedPolicy.InboundFeeRateMilliMsat,
1370+
},
1371+
}
1372+
bob.RPC.UpdateChannelPolicy(updateFeeReq)
1373+
1374+
// Wait for Alice to receive the channel update from Bob.
1375+
ht.AssertChannelPolicyUpdate(
1376+
alice, bob, expectedPolicy, chanPointAliceBob, false,
1377+
)
1378+
1379+
// We query the only route available to Carol.
1380+
queryRoutesReq := &lnrpc.QueryRoutesRequest{
1381+
PubKey: carol.PubKeyStr,
1382+
Amt: paymentAmt,
1383+
}
1384+
routesResp := alice.RPC.QueryRoutes(queryRoutesReq)
1385+
1386+
// Verify that the route has zero fees.
1387+
require.Len(ht, routesResp.Routes, 1)
1388+
require.Len(ht, routesResp.Routes[0].Hops, 2)
1389+
require.Zero(ht, routesResp.Routes[0].TotalFeesMsat)
1390+
1391+
// Attempt a payment with a fee limit of zero.
1392+
invoice := &lnrpc.Invoice{Value: paymentAmt}
1393+
invoiceResp := carol.RPC.AddInvoice(invoice)
1394+
sendReq := &routerrpc.SendPaymentRequest{
1395+
PaymentRequest: invoiceResp.PaymentRequest,
1396+
TimeoutSeconds: 60,
1397+
FeeLimitMsat: 0,
1398+
}
1399+
1400+
// We assert that a route compatible with the fee limit is available.
1401+
ht.SendPaymentAssertSettled(alice, sendReq)
1402+
1403+
// Once we're done, close the channels.
1404+
ht.CloseChannel(alice, chanPointAliceBob)
1405+
ht.CloseChannel(bob, chanPointBobCarol)
1406+
}
1407+
13341408
// computeFee calculates the payment fee as specified in BOLT07.
13351409
func computeFee(baseFee, feeRate, amt lnwire.MilliSatoshi) lnwire.MilliSatoshi {
13361410
return baseFee + amt*feeRate/1000000

lntest/node/watcher.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ func (nw *nodeWatcher) WaitForChannelPolicyUpdate(
221221
select {
222222
// Send a watch request every second.
223223
case <-ticker.C:
224-
// Did the event can close in the meantime? We want to
224+
// Did the event chan close in the meantime? We want to
225225
// avoid a "close of closed channel" panic since we're
226226
// re-using the same event chan for multiple requests.
227227
select {

routing/pathfind.go

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -697,7 +697,6 @@ func findPath(g *graphParams, r *RestrictParams, cfg *PathFindingConfig,
697697
// processEdge is a helper closure that will be used to make sure edges
698698
// satisfy our specific requirements.
699699
processEdge := func(fromVertex route.Vertex,
700-
fromFeatures *lnwire.FeatureVector,
701700
edge *unifiedEdge, toNodeDist *nodeWithDist) {
702701

703702
edgesExpanded++
@@ -724,6 +723,24 @@ func findPath(g *graphParams, r *RestrictParams, cfg *PathFindingConfig,
724723
amountToSend := toNodeDist.netAmountReceived +
725724
lnwire.MilliSatoshi(inboundFee)
726725

726+
// Check if accumulated fees would exceed fee limit when this
727+
// node would be added to the path.
728+
totalFee := int64(amountToSend) - int64(amt)
729+
730+
log.Trace(lnutils.NewLogClosure(func() string {
731+
return fmt.Sprintf(
732+
"Checking fromVertex (%v) with "+
733+
"minInboundFee=%v, inboundFee=%v, "+
734+
"amountToSend=%v, amt=%v, totalFee=%v",
735+
fromVertex, minInboundFee, inboundFee,
736+
amountToSend, amt, totalFee,
737+
)
738+
}))
739+
740+
if totalFee > 0 && lnwire.MilliSatoshi(totalFee) > r.FeeLimit {
741+
return
742+
}
743+
727744
// Request the success probability for this edge.
728745
edgeProbability := r.ProbabilitySource(
729746
fromVertex, toNodeDist.node, amountToSend,
@@ -780,13 +797,6 @@ func findPath(g *graphParams, r *RestrictParams, cfg *PathFindingConfig,
780797
netAmountToReceive := amountToSend +
781798
lnwire.MilliSatoshi(outboundFee)
782799

783-
// Check if accumulated fees would exceed fee limit when this
784-
// node would be added to the path.
785-
totalFee := int64(netAmountToReceive) - int64(amt)
786-
if totalFee > 0 && lnwire.MilliSatoshi(totalFee) > r.FeeLimit {
787-
return
788-
}
789-
790800
// Calculate total probability of successfully reaching target
791801
// by multiplying the probabilities. Both this edge and the rest
792802
// of the route must succeed.
@@ -813,7 +823,7 @@ func findPath(g *graphParams, r *RestrictParams, cfg *PathFindingConfig,
813823
// weight composed of the fee that this node will charge and
814824
// the amount that will be locked for timeLockDelta blocks in
815825
// the HTLC that is handed out to fromVertex.
816-
weight := edgeWeight(netAmountToReceive, fee, timeLockDelta)
826+
weight := edgeWeight(amountToSend, fee, timeLockDelta)
817827

818828
// Compute the tentative weight to this new channel/edge
819829
// which is the weight from our toNode to the target node
@@ -1035,7 +1045,7 @@ func findPath(g *graphParams, r *RestrictParams, cfg *PathFindingConfig,
10351045

10361046
// Check if this candidate node is better than what we
10371047
// already have.
1038-
processEdge(fromNode, fromFeatures, edge, partialPath)
1048+
processEdge(fromNode, edge, partialPath)
10391049
}
10401050

10411051
if nodeHeap.Len() == 0 {

0 commit comments

Comments
 (0)