Skip to content

Commit 4f40e43

Browse files
authored
Merge pull request #9061 from Roasbeef/0-18-3-branch
release: create branch for v0.18.3 rc3
2 parents 3bb4d6d + d85ce84 commit 4f40e43

16 files changed

+429
-135
lines changed

.golangci.yml

+2
Original file line numberDiff line numberDiff line change
@@ -104,11 +104,13 @@ linters-settings:
104104
- 'errors.Wrap'
105105

106106
gomoddirectives:
107+
replace-local: true
107108
replace-allow-list:
108109
# See go.mod for the explanation why these are needed.
109110
- github.com/ulikunitz/xz
110111
- github.com/gogo/protobuf
111112
- google.golang.org/protobuf
113+
- github.com/lightningnetwork/lnd/sqldb
112114

113115

114116
linters:

build/version.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ const (
4747

4848
// AppPreRelease MUST only contain characters from semanticAlphabet per
4949
// the semantic versioning spec.
50-
AppPreRelease = "beta.rc2"
50+
AppPreRelease = "beta.rc3"
5151
)
5252

5353
func init() {

channeldb/invoices.go

+50-9
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,9 @@ func (d *DB) InvoicesAddedSince(_ context.Context, sinceAddIndex uint64) (
269269

270270
// For each key found, we'll look up the actual
271271
// invoice, then accumulate it into our return value.
272-
invoice, err := fetchInvoice(invoiceKey, invoices)
272+
invoice, err := fetchInvoice(
273+
invoiceKey, invoices, nil, false,
274+
)
273275
if err != nil {
274276
return err
275277
}
@@ -341,7 +343,9 @@ func (d *DB) LookupInvoice(_ context.Context, ref invpkg.InvoiceRef) (
341343

342344
// An invoice was found, retrieve the remainder of the invoice
343345
// body.
344-
i, err := fetchInvoice(invoiceNum, invoices, setID)
346+
i, err := fetchInvoice(
347+
invoiceNum, invoices, []*invpkg.SetID{setID}, true,
348+
)
345349
if err != nil {
346350
return err
347351
}
@@ -468,7 +472,7 @@ func (d *DB) FetchPendingInvoices(_ context.Context) (
468472
return nil
469473
}
470474

471-
invoice, err := fetchInvoice(v, invoices)
475+
invoice, err := fetchInvoice(v, invoices, nil, false)
472476
if err != nil {
473477
return err
474478
}
@@ -526,7 +530,9 @@ func (d *DB) QueryInvoices(_ context.Context, q invpkg.InvoiceQuery) (
526530
// characteristics for our query and returns the number of items
527531
// we have added to our set of invoices.
528532
accumulateInvoices := func(_, indexValue []byte) (bool, error) {
529-
invoice, err := fetchInvoice(indexValue, invoices)
533+
invoice, err := fetchInvoice(
534+
indexValue, invoices, nil, false,
535+
)
530536
if err != nil {
531537
return false, err
532538
}
@@ -654,7 +660,9 @@ func (d *DB) UpdateInvoice(_ context.Context, ref invpkg.InvoiceRef,
654660
if setIDHint != nil {
655661
invSetID = *setIDHint
656662
}
657-
invoice, err := fetchInvoice(invoiceNum, invoices, &invSetID)
663+
invoice, err := fetchInvoice(
664+
invoiceNum, invoices, []*invpkg.SetID{&invSetID}, false,
665+
)
658666
if err != nil {
659667
return err
660668
}
@@ -676,15 +684,43 @@ func (d *DB) UpdateInvoice(_ context.Context, ref invpkg.InvoiceRef,
676684
updatedInvoice, err = invpkg.UpdateInvoice(
677685
payHash, updater.invoice, now, callback, updater,
678686
)
687+
if err != nil {
688+
return err
689+
}
679690

680-
return err
691+
// If this is an AMP update, then limit the returned AMP state
692+
// to only the requested set ID.
693+
if setIDHint != nil {
694+
filterInvoiceAMPState(updatedInvoice, &invSetID)
695+
}
696+
697+
return nil
681698
}, func() {
682699
updatedInvoice = nil
683700
})
684701

685702
return updatedInvoice, err
686703
}
687704

705+
// filterInvoiceAMPState filters the AMP state of the invoice to only include
706+
// state for the specified set IDs.
707+
func filterInvoiceAMPState(invoice *invpkg.Invoice, setIDs ...*invpkg.SetID) {
708+
filteredAMPState := make(invpkg.AMPInvoiceState)
709+
710+
for _, setID := range setIDs {
711+
if setID == nil {
712+
return
713+
}
714+
715+
ampState, ok := invoice.AMPState[*setID]
716+
if ok {
717+
filteredAMPState[*setID] = ampState
718+
}
719+
}
720+
721+
invoice.AMPState = filteredAMPState
722+
}
723+
688724
// ampHTLCsMap is a map of AMP HTLCs affected by an invoice update.
689725
type ampHTLCsMap map[invpkg.SetID]map[models.CircuitKey]*invpkg.InvoiceHTLC
690726

@@ -1056,7 +1092,8 @@ func (d *DB) InvoicesSettledSince(_ context.Context, sinceSettleIndex uint64) (
10561092
// For each key found, we'll look up the actual
10571093
// invoice, then accumulate it into our return value.
10581094
invoice, err := fetchInvoice(
1059-
invoiceKey[:], invoices, setID,
1095+
invoiceKey[:], invoices, []*invpkg.SetID{setID},
1096+
true,
10601097
)
10611098
if err != nil {
10621099
return err
@@ -1485,7 +1522,7 @@ func fetchAmpSubInvoices(invoiceBucket kvdb.RBucket, invoiceNum []byte,
14851522
// specified by the invoice number. If the setID fields are set, then only the
14861523
// HTLC information pertaining to those set IDs is returned.
14871524
func fetchInvoice(invoiceNum []byte, invoices kvdb.RBucket,
1488-
setIDs ...*invpkg.SetID) (invpkg.Invoice, error) {
1525+
setIDs []*invpkg.SetID, filterAMPState bool) (invpkg.Invoice, error) {
14891526

14901527
invoiceBytes := invoices.Get(invoiceNum)
14911528
if invoiceBytes == nil {
@@ -1518,6 +1555,10 @@ func fetchInvoice(invoiceNum []byte, invoices kvdb.RBucket,
15181555
log.Errorf("unable to fetch amp htlcs for inv "+
15191556
"%v and setIDs %v: %w", invoiceNum, setIDs, err)
15201557
}
1558+
1559+
if filterAMPState {
1560+
filterInvoiceAMPState(&invoice, setIDs...)
1561+
}
15211562
}
15221563

15231564
return invoice, nil
@@ -2163,7 +2204,7 @@ func (d *DB) DeleteCanceledInvoices(_ context.Context) error {
21632204
return nil
21642205
}
21652206

2166-
invoice, err := fetchInvoice(v, invoices)
2207+
invoice, err := fetchInvoice(v, invoices, nil, false)
21672208
if err != nil {
21682209
return err
21692210
}

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

+6
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,11 @@ that validate `ChannelAnnouncement` messages.
253253
our health checker to correctly shut down LND if network partitioning occurs
254254
towards the etcd cluster.
255255

256+
* [Fix](https://github.com/lightningnetwork/lnd/pull/9050) some inconsistencies
257+
to make the native SQL invoice DB compatible with the KV implementation.
258+
Furthermore fix a native SQL invoice issue where AMP subinvoice HTLCs are
259+
sometimes updated incorrectly on settlement.
260+
256261
## Code Health
257262

258263
* [Move graph building and
@@ -269,6 +274,7 @@ that validate `ChannelAnnouncement` messages.
269274

270275
# Contributors (Alphabetical Order)
271276

277+
* Alex Akselrod
272278
* Andras Banki-Horvath
273279
* bitromortac
274280
* Bufo

go.mod

+3
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,9 @@ replace github.com/gogo/protobuf => github.com/gogo/protobuf v1.3.2
204204
// allows us to specify that as an option.
205205
replace google.golang.org/protobuf => github.com/lightninglabs/protobuf-go-hex-display v1.30.0-hex-display
206206

207+
// Temporary replace until the next version of sqldb is taged.
208+
replace github.com/lightningnetwork/lnd/sqldb => ./sqldb
209+
207210
// If you change this please also update .github/pull_request_template.md,
208211
// docs/INSTALL.md and GO_IMAGE in lnrpc/gen_protos_docker.sh.
209212
go 1.21.4

go.sum

-2
Original file line numberDiff line numberDiff line change
@@ -458,8 +458,6 @@ github.com/lightningnetwork/lnd/kvdb v1.4.10 h1:vK89IVv1oVH9ubQWU+EmoCQFeVRaC8kf
458458
github.com/lightningnetwork/lnd/kvdb v1.4.10/go.mod h1:J2diNABOoII9UrMnxXS5w7vZwP7CA1CStrl8MnIrb3A=
459459
github.com/lightningnetwork/lnd/queue v1.1.1 h1:99ovBlpM9B0FRCGYJo6RSFDlt8/vOkQQZznVb18iNMI=
460460
github.com/lightningnetwork/lnd/queue v1.1.1/go.mod h1:7A6nC1Qrm32FHuhx/mi1cieAiBZo5O6l8IBIoQxvkz4=
461-
github.com/lightningnetwork/lnd/sqldb v1.0.3 h1:zLfAwOvM+6+3+hahYO9Q3h8pVV0TghAR7iJ5YMLCd3I=
462-
github.com/lightningnetwork/lnd/sqldb v1.0.3/go.mod h1:4cQOkdymlZ1znnjuRNvMoatQGJkRneTj2CoPSPaQhWo=
463461
github.com/lightningnetwork/lnd/ticker v1.1.1 h1:J/b6N2hibFtC7JLV77ULQp++QLtCwT6ijJlbdiZFbSM=
464462
github.com/lightningnetwork/lnd/ticker v1.1.1/go.mod h1:waPTRAAcwtu7Ji3+3k+u/xH5GHovTsCoSVpho0KDvdA=
465463
github.com/lightningnetwork/lnd/tlv v1.2.3 h1:If5ibokA/UoCBGuCKaY6Vn2SJU0l9uAbehCnhTZjEP8=

invoices/sql_store.go

+47-5
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"strconv"
1111
"time"
1212

13+
"github.com/davecgh/go-spew/spew"
1314
"github.com/lightningnetwork/lnd/channeldb/models"
1415
"github.com/lightningnetwork/lnd/clock"
1516
"github.com/lightningnetwork/lnd/lntypes"
@@ -46,6 +47,9 @@ type SQLInvoiceQueries interface { //nolint:interfacebloat
4647
GetInvoice(ctx context.Context,
4748
arg sqlc.GetInvoiceParams) ([]sqlc.Invoice, error)
4849

50+
GetInvoiceBySetID(ctx context.Context, setID []byte) ([]sqlc.Invoice,
51+
error)
52+
4953
GetInvoiceFeatures(ctx context.Context,
5054
invoiceID int64) ([]sqlc.InvoiceFeature, error)
5155

@@ -343,16 +347,31 @@ func (i *SQLStore) fetchInvoice(ctx context.Context,
343347
params.SetID = ref.SetID()[:]
344348
}
345349

346-
rows, err := db.GetInvoice(ctx, params)
350+
var (
351+
rows []sqlc.Invoice
352+
err error
353+
)
354+
355+
// We need to split the query based on how we intend to look up the
356+
// invoice. If only the set ID is given then we want to have an exact
357+
// match on the set ID. If other fields are given, we want to match on
358+
// those fields and the set ID but with a less strict join condition.
359+
if params.Hash == nil && params.PaymentAddr == nil &&
360+
params.SetID != nil {
361+
362+
rows, err = db.GetInvoiceBySetID(ctx, params.SetID)
363+
} else {
364+
rows, err = db.GetInvoice(ctx, params)
365+
}
347366
switch {
348367
case len(rows) == 0:
349368
return nil, ErrInvoiceNotFound
350369

351370
case len(rows) > 1:
352371
// In case the reference is ambiguous, meaning it matches more
353372
// than one invoice, we'll return an error.
354-
return nil, fmt.Errorf("ambiguous invoice ref: %s",
355-
ref.String())
373+
return nil, fmt.Errorf("ambiguous invoice ref: %s: %s",
374+
ref.String(), spew.Sdump(rows))
356375

357376
case err != nil:
358377
return nil, fmt.Errorf("unable to fetch invoice: %w", err)
@@ -906,8 +925,10 @@ func (i *SQLStore) QueryInvoices(ctx context.Context,
906925
}
907926

908927
if q.CreationDateEnd != 0 {
928+
// We need to add 1 to the end date as we're
929+
// checking less than the end date in SQL.
909930
params.CreatedBefore = sqldb.SQLTime(
910-
time.Unix(q.CreationDateEnd, 0).UTC(),
931+
time.Unix(q.CreationDateEnd+1, 0).UTC(),
911932
)
912933
}
913934

@@ -1116,6 +1137,9 @@ func (s *sqlInvoiceUpdater) AddAmpHtlcPreimage(setID [32]byte,
11161137
SetID: setID[:],
11171138
HtlcID: int64(circuitKey.HtlcID),
11181139
Preimage: preimage[:],
1140+
ChanID: strconv.FormatUint(
1141+
circuitKey.ChanID.ToUint64(), 10,
1142+
),
11191143
},
11201144
)
11211145
if err != nil {
@@ -1280,6 +1304,13 @@ func (s *sqlInvoiceUpdater) UpdateAmpState(setID [32]byte,
12801304
return err
12811305
}
12821306

1307+
if settleIndex.Valid {
1308+
updatedState := s.invoice.AMPState[setID]
1309+
updatedState.SettleIndex = uint64(settleIndex.Int64)
1310+
updatedState.SettleDate = s.updateTime.UTC()
1311+
s.invoice.AMPState[setID] = updatedState
1312+
}
1313+
12831314
return nil
12841315
}
12851316

@@ -1298,13 +1329,24 @@ func (s *sqlInvoiceUpdater) Finalize(_ UpdateType) error {
12981329
// invoice and is therefore atomic. The fields to update are controlled by the
12991330
// supplied callback.
13001331
func (i *SQLStore) UpdateInvoice(ctx context.Context, ref InvoiceRef,
1301-
_ *SetID, callback InvoiceUpdateCallback) (
1332+
setID *SetID, callback InvoiceUpdateCallback) (
13021333
*Invoice, error) {
13031334

13041335
var updatedInvoice *Invoice
13051336

13061337
txOpt := SQLInvoiceQueriesTxOptions{readOnly: false}
13071338
txErr := i.db.ExecTx(ctx, &txOpt, func(db SQLInvoiceQueries) error {
1339+
if setID != nil {
1340+
// Make sure to use the set ID if this is an AMP update.
1341+
var setIDBytes [32]byte
1342+
copy(setIDBytes[:], setID[:])
1343+
ref.setID = &setIDBytes
1344+
1345+
// If we're updating an AMP invoice, we'll also only
1346+
// need to fetch the HTLCs for the given set ID.
1347+
ref.refModifier = HtlcSetOnlyModifier
1348+
}
1349+
13081350
invoice, err := i.fetchInvoice(ctx, db, ref)
13091351
if err != nil {
13101352
return err

itest/lnd_amp_test.go

+9-5
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,8 @@ func testSendPaymentAMPInvoiceRepeat(ht *lntest.HarnessTest) {
260260
invoiceNtfn := ht.ReceiveInvoiceUpdate(invSubscription)
261261

262262
// The notification should signal that the invoice is now settled, and
263-
// should also include the set ID, and show the proper amount paid.
263+
// should also include the set ID, show the proper amount paid, and have
264+
// the correct settle index and time.
264265
require.True(ht, invoiceNtfn.Settled)
265266
require.Equal(ht, lnrpc.Invoice_SETTLED, invoiceNtfn.State)
266267
require.Equal(ht, paymentAmt, int(invoiceNtfn.AmtPaidSat))
@@ -270,6 +271,9 @@ func testSendPaymentAMPInvoiceRepeat(ht *lntest.HarnessTest) {
270271
firstSetID, _ = hex.DecodeString(setIDStr)
271272
require.Equal(ht, lnrpc.InvoiceHTLCState_SETTLED,
272273
ampState.State)
274+
require.GreaterOrEqual(ht, ampState.SettleTime,
275+
rpcInvoice.CreationDate)
276+
require.Equal(ht, uint64(1), ampState.SettleIndex)
273277
}
274278

275279
// Pay the invoice again, we should get another notification that Dave
@@ -299,9 +303,9 @@ func testSendPaymentAMPInvoiceRepeat(ht *lntest.HarnessTest) {
299303
// return the "projected" sub-invoice for a given setID.
300304
require.Equal(ht, 1, len(invoiceNtfn.Htlcs))
301305

302-
// However the AMP state index should show that there've been two
303-
// repeated payments to this invoice so far.
304-
require.Equal(ht, 2, len(invoiceNtfn.AmpInvoiceState))
306+
// The AMP state should also be restricted to a single entry for the
307+
// "projected" sub-invoice.
308+
require.Equal(ht, 1, len(invoiceNtfn.AmpInvoiceState))
305309

306310
// Now we'll look up the invoice using the new LookupInvoice2 RPC call
307311
// by the set ID of each of the invoices.
@@ -360,7 +364,7 @@ func testSendPaymentAMPInvoiceRepeat(ht *lntest.HarnessTest) {
360364
// through.
361365
backlogInv := ht.ReceiveInvoiceUpdate(invSub2)
362366
require.Equal(ht, 1, len(backlogInv.Htlcs))
363-
require.Equal(ht, 2, len(backlogInv.AmpInvoiceState))
367+
require.Equal(ht, 1, len(backlogInv.AmpInvoiceState))
364368
require.True(ht, backlogInv.Settled)
365369
require.Equal(ht, paymentAmt*2, int(backlogInv.AmtPaidSat))
366370
}

0 commit comments

Comments
 (0)