Skip to content

Commit

Permalink
Impl addinvoice minroutinghints
Browse files Browse the repository at this point in the history
  • Loading branch information
djkazic authored and kaloudis committed Oct 3, 2023
1 parent 32de7d9 commit b5a2d15
Show file tree
Hide file tree
Showing 7 changed files with 1,189 additions and 1,118 deletions.
36 changes: 29 additions & 7 deletions lnrpc/invoicesrpc/addinvoice.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,10 @@ type AddInvoiceData struct {
// RouteHints are optional route hints that can each be individually
// used to assist in reaching the invoice's destination.
RouteHints [][]zpay32.HopHint

// The minimum number of routing hints that will be included in an
// invoice.
MinHopHints int32
}

// paymentHashAndPreimage returns the payment hash and preimage for this invoice
Expand Down Expand Up @@ -400,7 +404,11 @@ func AddInvoice(ctx context.Context, cfg *AddInvoiceConfig,
totalHopHints = maxHopHints
}

hopHintsCfg := newSelectHopHintsCfg(cfg, totalHopHints)
hopHintsCfg := newSelectHopHintsCfg(
cfg,
totalHopHints,
int(invoice.MinHopHints),
)
hopHints, err := PopulateHopHints(
hopHintsCfg, amtMSat, invoice.RouteHints,
)
Expand Down Expand Up @@ -645,10 +653,13 @@ type SelectHopHintsCfg struct {

// MaxHopHints is the maximum number of hop hints we are interested in.
MaxHopHints int

// MinHopHints is the minimum number of hop hints we are interested in.
MinHopHints int
}

func newSelectHopHintsCfg(invoicesCfg *AddInvoiceConfig,
maxHopHints int) *SelectHopHintsCfg {
maxHopHints int, minHopHints int) *SelectHopHintsCfg {

return &SelectHopHintsCfg{
FetchAllChannels: invoicesCfg.ChanDB.FetchAllChannels,
Expand All @@ -657,21 +668,27 @@ func newSelectHopHintsCfg(invoicesCfg *AddInvoiceConfig,
FetchChannelEdgesByID: invoicesCfg.Graph.FetchChannelEdgesByID,
GetAlias: invoicesCfg.GetAlias,
MaxHopHints: maxHopHints,
MinHopHints: minHopHints,
}
}

// sufficientHints checks whether we have sufficient hop hints, based on the
// any of the following criteria:
// - Min hop hints: the minimum of hints to include.
// - Hop hint count: the number of hints have reach our max target.
// - 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.
func sufficientHints(nHintsLeft int, currentAmount,
func sufficientHints(nCurrentHints, nHintsLeft, nMinHopHints int, currentAmount,
targetAmount lnwire.MilliSatoshi) bool {

if nCurrentHints < nMinHopHints {
return false
}

if nHintsLeft <= 0 {
log.Debugf("Reached targeted number of hop hints")
return true
Expand Down Expand Up @@ -765,16 +782,21 @@ func shouldIncludeChannel(cfg *SelectHopHintsCfg,
//
// NOTE: selectHopHints expects potentialHints to be already sorted in
// descending priority.
func selectHopHints(cfg *SelectHopHintsCfg, nHintsLeft int,
func selectHopHints(cfg *SelectHopHintsCfg, nHintsLeft, nMinHopHints int,
targetBandwidth lnwire.MilliSatoshi,
potentialHints []*channeldb.OpenChannel,
alreadyIncluded map[uint64]bool) [][]zpay32.HopHint {

currentBandwidth := lnwire.MilliSatoshi(0)
hopHints := make([][]zpay32.HopHint, 0, nHintsLeft)
nCurrentHints := len(hopHints)
for _, channel := range potentialHints {
enoughHopHints := sufficientHints(
nHintsLeft, currentBandwidth, targetBandwidth,
nCurrentHints,
nHintsLeft,
nMinHopHints,
currentBandwidth,
targetBandwidth,
)
if enoughHopHints {
return hopHints
Expand Down Expand Up @@ -832,8 +854,8 @@ func PopulateHopHints(cfg *SelectHopHintsCfg, amtMSat lnwire.MilliSatoshi,

targetBandwidth := amtMSat * hopHintFactor
selectedHints := selectHopHints(
cfg, nHintsLeft, targetBandwidth, potentialHints,
alreadyIncluded,
cfg, nHintsLeft, cfg.MinHopHints, targetBandwidth,
potentialHints, alreadyIncluded,
)

hopHints = append(hopHints, selectedHints...)
Expand Down
24 changes: 23 additions & 1 deletion lnrpc/invoicesrpc/addinvoice_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,9 @@ func TestShouldIncludeChannel(t *testing.T) {

var sufficientHintsTestCases = []struct {
name string
nCurrentHints int
nHintsLeft int
nMinHopHints int
currentAmount lnwire.MilliSatoshi
targetAmount lnwire.MilliSatoshi
done bool
Expand All @@ -472,6 +474,23 @@ var sufficientHintsTestCases = []struct {
name: "enough hints",
nHintsLeft: 0,
done: true,
}, {
name: "not enough hints (minimum)",
nCurrentHints: 1,
nHintsLeft: 0,
nMinHopHints: 2,
done: false,
}, {
name: "enough hints (minimum)",
nCurrentHints: 2,
nHintsLeft: 0,
nMinHopHints: 2,
done: true,
}, {
name: "current hints",
nCurrentHints: 20,
nHintsLeft: 0,
done: true,
}, {
name: "enough bandwidth",
nHintsLeft: 1,
Expand All @@ -494,7 +513,10 @@ func TestSufficientHints(t *testing.T) {
t.Parallel()

enoughHints := sufficientHints(
tc.nHintsLeft, tc.currentAmount,
tc.nCurrentHints,
tc.nHintsLeft,
tc.nMinHopHints,
tc.currentAmount,
tc.targetAmount,
)
require.Equal(t, tc.done, enoughHints)
Expand Down
5 changes: 5 additions & 0 deletions lnrpc/invoicesrpc/invoices.swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -578,6 +578,11 @@
},
"description": "Maps a 32-byte hex-encoded set ID to the sub-invoice AMP state for the\ngiven set ID. This field is always populated for AMP invoices, and can be\nused along side LookupInvoice to obtain the HTLC information related to a\ngiven sub-invoice.\nNote: Output only, don't specify for creating an invoice.",
"title": "[EXPERIMENTAL]:"
},
"min_hop_hints": {
"type": "integer",
"format": "int32",
"description": "The minimum number of hop hints to include in this invoice."
}
}
},
Expand Down
Loading

0 comments on commit b5a2d15

Please sign in to comment.