mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-05-12 12:52:53 +02:00
Certain invoices may not have a deterministic payment hash. For such invoices we still store the payment hashes in our KV database, but we do not have a sufficient index to retrieve them. This PR adds such index to the SQL database that will be used during migration to retrieve payment hashes.
129 lines
4.1 KiB
Go
129 lines
4.1 KiB
Go
package invoices
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/binary"
|
|
"fmt"
|
|
|
|
"github.com/lightningnetwork/lnd/kvdb"
|
|
"github.com/lightningnetwork/lnd/lntypes"
|
|
"github.com/lightningnetwork/lnd/sqldb/sqlc"
|
|
)
|
|
|
|
var (
|
|
// invoiceBucket is the name of the bucket within the database that
|
|
// stores all data related to invoices no matter their final state.
|
|
// Within the invoice bucket, each invoice is keyed by its invoice ID
|
|
// which is a monotonically increasing uint32.
|
|
invoiceBucket = []byte("invoices")
|
|
|
|
// invoiceIndexBucket is the name of the sub-bucket within the
|
|
// invoiceBucket which indexes all invoices by their payment hash. The
|
|
// payment hash is the sha256 of the invoice's payment preimage. This
|
|
// index is used to detect duplicates, and also to provide a fast path
|
|
// for looking up incoming HTLCs to determine if we're able to settle
|
|
// them fully.
|
|
//
|
|
// maps: payHash => invoiceKey
|
|
invoiceIndexBucket = []byte("paymenthashes")
|
|
|
|
// numInvoicesKey is the name of key which houses the auto-incrementing
|
|
// invoice ID which is essentially used as a primary key. With each
|
|
// invoice inserted, the primary key is incremented by one. This key is
|
|
// stored within the invoiceIndexBucket. Within the invoiceBucket
|
|
// invoices are uniquely identified by the invoice ID.
|
|
numInvoicesKey = []byte("nik")
|
|
|
|
// addIndexBucket is an index bucket that we'll use to create a
|
|
// monotonically increasing set of add indexes. Each time we add a new
|
|
// invoice, this sequence number will be incremented and then populated
|
|
// within the new invoice.
|
|
//
|
|
// In addition to this sequence number, we map:
|
|
//
|
|
// addIndexNo => invoiceKey
|
|
addIndexBucket = []byte("invoice-add-index")
|
|
)
|
|
|
|
// createInvoiceHashIndex generates a hash index that contains payment hashes
|
|
// for each invoice in the database. Retrieving the payment hash for certain
|
|
// invoices, such as those created for spontaneous AMP payments, can be
|
|
// challenging because the hash is not directly derivable from the invoice's
|
|
// parameters and is stored separately in the `paymenthashes` bucket. This
|
|
// bucket maps payment hashes to invoice keys, but for migration purposes, we
|
|
// need the ability to query in the reverse direction. This function establishes
|
|
// a new index in the SQL database that maps each invoice key to its
|
|
// corresponding payment hash.
|
|
func createInvoiceHashIndex(ctx context.Context, db kvdb.Backend,
|
|
tx SQLInvoiceQueries) error {
|
|
|
|
return db.View(func(kvTx kvdb.RTx) error {
|
|
invoices := kvTx.ReadBucket(invoiceBucket)
|
|
if invoices == nil {
|
|
return ErrNoInvoicesCreated
|
|
}
|
|
|
|
invoiceIndex := invoices.NestedReadBucket(
|
|
invoiceIndexBucket,
|
|
)
|
|
if invoiceIndex == nil {
|
|
return ErrNoInvoicesCreated
|
|
}
|
|
|
|
addIndex := invoices.NestedReadBucket(addIndexBucket)
|
|
if addIndex == nil {
|
|
return ErrNoInvoicesCreated
|
|
}
|
|
|
|
// First, iterate over all elements in the add index bucket and
|
|
// insert the add index value for the corresponding invoice key
|
|
// in the payment_hashes table.
|
|
err := addIndex.ForEach(func(k, v []byte) error {
|
|
// The key is the add index, and the value is
|
|
// the invoice key.
|
|
addIndexNo := binary.BigEndian.Uint64(k)
|
|
invoiceKey := binary.BigEndian.Uint32(v)
|
|
|
|
return tx.InsertKVInvoiceKeyAndAddIndex(ctx,
|
|
sqlc.InsertKVInvoiceKeyAndAddIndexParams{
|
|
ID: int32(invoiceKey),
|
|
AddIndex: int64(addIndexNo),
|
|
},
|
|
)
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Next, iterate over all hashes in the invoice index bucket and
|
|
// set the hash to the corresponding the invoice key in the
|
|
// payment_hashes table.
|
|
return invoiceIndex.ForEach(func(k, v []byte) error {
|
|
// Skip the special numInvoicesKey as that does
|
|
// not point to a valid invoice.
|
|
if bytes.Equal(k, numInvoicesKey) {
|
|
return nil
|
|
}
|
|
|
|
// The key is the payment hash, and the value
|
|
// is the invoice key.
|
|
if len(k) != lntypes.HashSize {
|
|
return fmt.Errorf("invalid payment "+
|
|
"hash length: expected %v, "+
|
|
"got %v", lntypes.HashSize,
|
|
len(k))
|
|
}
|
|
|
|
invoiceKey := binary.BigEndian.Uint32(v)
|
|
|
|
return tx.SetKVInvoicePaymentHash(ctx,
|
|
sqlc.SetKVInvoicePaymentHashParams{
|
|
ID: int32(invoiceKey),
|
|
Hash: k,
|
|
},
|
|
)
|
|
})
|
|
}, func() {})
|
|
}
|