From 0cae501009c63b35eb42fb12a0503e7312a99ba7 Mon Sep 17 00:00:00 2001 From: alpeb-btc Date: Wed, 26 Oct 2022 12:57:52 -0500 Subject: [PATCH] lnrpc: provide hop hints when adding an invoice with no amount With this change we allow adding hop hints when adding an invoice, even if its amount is zero. A couple of new unit test case have been added, and the `testInvoiceRoutingHints` itest was expanded to account for this scenario. --- lnrpc/invoicesrpc/addinvoice.go | 8 +-- lnrpc/invoicesrpc/addinvoice_test.go | 93 ++++++++++++++++++++++++++++ lntest/itest/lnd_routing_test.go | 9 +++ 3 files changed, 106 insertions(+), 4 deletions(-) diff --git a/lnrpc/invoicesrpc/addinvoice.go b/lnrpc/invoicesrpc/addinvoice.go index c37ed001d..860290c97 100644 --- a/lnrpc/invoicesrpc/addinvoice.go +++ b/lnrpc/invoicesrpc/addinvoice.go @@ -655,9 +655,9 @@ func newSelectHopHintsCfg(invoicesCfg *AddInvoiceConfig, // sufficientHints checks whether we have sufficient hop hints, based on the // any of the following criteria: // - Hop hint count: the number of hints have reach our max target. -// - Total incoming capacity: the sum of the remote balance amount in the -// hints is bigger of equal than our target (currently twice the invoice -// amount) +// - Total incoming capacity (for non-zero invoice amounts): the sum of the +// remote balance amount in the hints is bigger of equal than our target +// (currently twice the invoice amount) // // We limit our number of hop hints like this to keep our invoice size down, // and to avoid leaking all our private channels when we don't need to. @@ -669,7 +669,7 @@ func sufficientHints(nHintsLeft int, currentAmount, return true } - if currentAmount >= targetAmount { + if targetAmount != 0 && currentAmount >= targetAmount { log.Debugf("Total hint amount: %v has reached target hint "+ "bandwidth: %v", currentAmount, targetAmount) return true diff --git a/lnrpc/invoicesrpc/addinvoice_test.go b/lnrpc/invoicesrpc/addinvoice_test.go index 7c2504b74..2dcb516a6 100644 --- a/lnrpc/invoicesrpc/addinvoice_test.go +++ b/lnrpc/invoicesrpc/addinvoice_test.go @@ -478,6 +478,12 @@ var sufficientHintsTestCases = []struct { currentAmount: 200, targetAmount: 200, done: true, +}, { + name: "no amount provided", + nHintsLeft: 1, + currentAmount: 100, + targetAmount: 0, + done: false, }} func TestSufficientHints(t *testing.T) { @@ -719,6 +725,93 @@ var populateHopHintsTestCases = []struct { }, }, }, +}, { + name: "consider all the open channels when amount is zero", + setupMock: func(h *hopHintsConfigMock) { + chanID1, chanID2 := setupMockTwoChannels(h) + + // Prepare the mock for the first channel. + h.Mock.On( + "IsChannelActive", chanID1, + ).Once().Return(true) + + h.Mock.On( + "IsPublicNode", mock.Anything, + ).Once().Return(true, nil) + + h.Mock.On( + "FetchChannelEdgesByID", mock.Anything, + ).Once().Return( + &channeldb.ChannelEdgeInfo{}, + &channeldb.ChannelEdgePolicy{}, + &channeldb.ChannelEdgePolicy{}, nil, + ) + + // Prepare the mock for the second channel. + h.Mock.On( + "IsChannelActive", chanID2, + ).Once().Return(true) + + h.Mock.On( + "IsPublicNode", mock.Anything, + ).Once().Return(true, nil) + + h.Mock.On( + "FetchChannelEdgesByID", mock.Anything, + ).Once().Return( + &channeldb.ChannelEdgeInfo{}, + &channeldb.ChannelEdgePolicy{}, + &channeldb.ChannelEdgePolicy{}, nil, + ) + }, + maxHopHints: 10, + amount: 0, + expectedHopHints: [][]zpay32.HopHint{ + { + { + NodeID: getTestPubKey(), + ChannelID: 9, + }, + }, { + { + NodeID: getTestPubKey(), + ChannelID: 2, + }, + }, + }, +}, { + name: "consider all the open channels when amount is zero" + + " up to maxHopHints", + setupMock: func(h *hopHintsConfigMock) { + chanID1, _ := setupMockTwoChannels(h) + + // Prepare the mock for the first channel. + h.Mock.On( + "IsChannelActive", chanID1, + ).Once().Return(true) + + h.Mock.On( + "IsPublicNode", mock.Anything, + ).Once().Return(true, nil) + + h.Mock.On( + "FetchChannelEdgesByID", mock.Anything, + ).Once().Return( + &channeldb.ChannelEdgeInfo{}, + &channeldb.ChannelEdgePolicy{}, + &channeldb.ChannelEdgePolicy{}, nil, + ) + }, + maxHopHints: 1, + amount: 0, + expectedHopHints: [][]zpay32.HopHint{ + { + { + NodeID: getTestPubKey(), + ChannelID: 9, + }, + }, + }, }} func setupMockTwoChannels(h *hopHintsConfigMock) (lnwire.ChannelID, diff --git a/lntest/itest/lnd_routing_test.go b/lntest/itest/lnd_routing_test.go index 0cd9d0251..caf5320af 100644 --- a/lntest/itest/lnd_routing_test.go +++ b/lntest/itest/lnd_routing_test.go @@ -1233,6 +1233,15 @@ func testInvoiceRoutingHints(net *lntest.NetworkHarness, t *harnessTest) { } checkInvoiceHints(invoice) + // Create another invoice for Alice with no value and ensure it still + // populates routing hints. + invoice = &lnrpc.Invoice{ + Memo: "routing hints with no amount", + Value: 0, + Private: true, + } + checkInvoiceHints(invoice) + // Now that we've confirmed the routing hints were added correctly, we // can close all the channels and shut down all the nodes created. closeChannelAndAssert(t, net, net.Alice, chanPointBob, false)