mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-09-07 19:30:46 +02:00
channeldb/migration_01_to_11: remove unused code
This commit is contained in:
@@ -3,7 +3,6 @@ package migration_01_to_11
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"time"
|
||||
@@ -16,9 +15,6 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
// UnknownPreimage is an all-zeroes preimage that indicates that the
|
||||
// preimage for this invoice is not yet known.
|
||||
UnknownPreimage lntypes.Preimage
|
||||
|
||||
// invoiceBucket is the name of the bucket within the database that
|
||||
// stores all data related to invoices no matter their final state.
|
||||
@@ -26,23 +22,6 @@ var (
|
||||
// which is a monotonically increasing uint32.
|
||||
invoiceBucket = []byte("invoices")
|
||||
|
||||
// paymentHashIndexBucket 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
|
||||
@@ -62,21 +41,6 @@ var (
|
||||
//
|
||||
// settleIndexNo => invoiceKey
|
||||
settleIndexBucket = []byte("invoice-settle-index")
|
||||
|
||||
// ErrInvoiceAlreadySettled is returned when the invoice is already
|
||||
// settled.
|
||||
ErrInvoiceAlreadySettled = errors.New("invoice already settled")
|
||||
|
||||
// ErrInvoiceAlreadyCanceled is returned when the invoice is already
|
||||
// canceled.
|
||||
ErrInvoiceAlreadyCanceled = errors.New("invoice already canceled")
|
||||
|
||||
// ErrInvoiceAlreadyAccepted is returned when the invoice is already
|
||||
// accepted.
|
||||
ErrInvoiceAlreadyAccepted = errors.New("invoice already accepted")
|
||||
|
||||
// ErrInvoiceStillOpen is returned when the invoice is still open.
|
||||
ErrInvoiceStillOpen = errors.New("invoice still open")
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -237,18 +201,6 @@ type Invoice struct {
|
||||
// HtlcState defines the states an htlc paying to an invoice can be in.
|
||||
type HtlcState uint8
|
||||
|
||||
const (
|
||||
// HtlcStateAccepted indicates the htlc is locked-in, but not resolved.
|
||||
HtlcStateAccepted HtlcState = iota
|
||||
|
||||
// HtlcStateCanceled indicates the htlc is canceled back to the
|
||||
// sender.
|
||||
HtlcStateCanceled
|
||||
|
||||
// HtlcStateSettled indicates the htlc is settled.
|
||||
HtlcStateSettled
|
||||
)
|
||||
|
||||
// InvoiceHTLC contains details about an htlc paying to this invoice.
|
||||
type InvoiceHTLC struct {
|
||||
// Amt is the amount that is carried by this htlc.
|
||||
@@ -276,37 +228,6 @@ type InvoiceHTLC struct {
|
||||
State HtlcState
|
||||
}
|
||||
|
||||
// HtlcAcceptDesc describes the details of a newly accepted htlc.
|
||||
type HtlcAcceptDesc struct {
|
||||
// AcceptHeight is the block height at which this htlc was accepted.
|
||||
AcceptHeight int32
|
||||
|
||||
// Amt is the amount that is carried by this htlc.
|
||||
Amt lnwire.MilliSatoshi
|
||||
|
||||
// Expiry is the expiry height of this htlc.
|
||||
Expiry uint32
|
||||
}
|
||||
|
||||
// InvoiceUpdateDesc describes the changes that should be applied to the
|
||||
// invoice.
|
||||
type InvoiceUpdateDesc struct {
|
||||
// State is the new state that this invoice should progress to.
|
||||
State ContractState
|
||||
|
||||
// Htlcs describes the changes that need to be made to the invoice htlcs
|
||||
// in the database. Htlc map entries with their value set should be
|
||||
// added. If the map value is nil, the htlc should be canceled.
|
||||
Htlcs map[CircuitKey]*HtlcAcceptDesc
|
||||
|
||||
// Preimage must be set to the preimage when state is settled.
|
||||
Preimage lntypes.Preimage
|
||||
}
|
||||
|
||||
// InvoiceUpdateCallback is a callback used in the db transaction to update the
|
||||
// invoice.
|
||||
type InvoiceUpdateCallback = func(invoice *Invoice) (*InvoiceUpdateDesc, error)
|
||||
|
||||
func validateInvoice(i *Invoice) error {
|
||||
if len(i.Memo) > MaxMemoSize {
|
||||
return fmt.Errorf("max length a memo is %v, and invoice "+
|
||||
@@ -325,186 +246,6 @@ func validateInvoice(i *Invoice) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddInvoice inserts the targeted invoice into the database. If the invoice has
|
||||
// *any* payment hashes which already exists within the database, then the
|
||||
// insertion will be aborted and rejected due to the strict policy banning any
|
||||
// duplicate payment hashes. A side effect of this function is that it sets
|
||||
// AddIndex on newInvoice.
|
||||
func (d *DB) AddInvoice(newInvoice *Invoice, paymentHash lntypes.Hash) (
|
||||
uint64, error) {
|
||||
|
||||
if err := validateInvoice(newInvoice); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
var invoiceAddIndex uint64
|
||||
err := d.Update(func(tx *bbolt.Tx) error {
|
||||
invoices, err := tx.CreateBucketIfNotExists(invoiceBucket)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
invoiceIndex, err := invoices.CreateBucketIfNotExists(
|
||||
invoiceIndexBucket,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
addIndex, err := invoices.CreateBucketIfNotExists(
|
||||
addIndexBucket,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Ensure that an invoice an identical payment hash doesn't
|
||||
// already exist within the index.
|
||||
if invoiceIndex.Get(paymentHash[:]) != nil {
|
||||
return ErrDuplicateInvoice
|
||||
}
|
||||
|
||||
// If the current running payment ID counter hasn't yet been
|
||||
// created, then create it now.
|
||||
var invoiceNum uint32
|
||||
invoiceCounter := invoiceIndex.Get(numInvoicesKey)
|
||||
if invoiceCounter == nil {
|
||||
var scratch [4]byte
|
||||
byteOrder.PutUint32(scratch[:], invoiceNum)
|
||||
err := invoiceIndex.Put(numInvoicesKey, scratch[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
invoiceNum = byteOrder.Uint32(invoiceCounter)
|
||||
}
|
||||
|
||||
newIndex, err := putInvoice(
|
||||
invoices, invoiceIndex, addIndex, newInvoice, invoiceNum,
|
||||
paymentHash,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
invoiceAddIndex = newIndex
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return invoiceAddIndex, err
|
||||
}
|
||||
|
||||
// InvoicesAddedSince can be used by callers to seek into the event time series
|
||||
// of all the invoices added in the database. The specified sinceAddIndex
|
||||
// should be the highest add index that the caller knows of. This method will
|
||||
// return all invoices with an add index greater than the specified
|
||||
// sinceAddIndex.
|
||||
//
|
||||
// NOTE: The index starts from 1, as a result. We enforce that specifying a
|
||||
// value below the starting index value is a noop.
|
||||
func (d *DB) InvoicesAddedSince(sinceAddIndex uint64) ([]Invoice, error) {
|
||||
var newInvoices []Invoice
|
||||
|
||||
// If an index of zero was specified, then in order to maintain
|
||||
// backwards compat, we won't send out any new invoices.
|
||||
if sinceAddIndex == 0 {
|
||||
return newInvoices, nil
|
||||
}
|
||||
|
||||
var startIndex [8]byte
|
||||
byteOrder.PutUint64(startIndex[:], sinceAddIndex)
|
||||
|
||||
err := d.DB.View(func(tx *bbolt.Tx) error {
|
||||
invoices := tx.Bucket(invoiceBucket)
|
||||
if invoices == nil {
|
||||
return ErrNoInvoicesCreated
|
||||
}
|
||||
|
||||
addIndex := invoices.Bucket(addIndexBucket)
|
||||
if addIndex == nil {
|
||||
return ErrNoInvoicesCreated
|
||||
}
|
||||
|
||||
// We'll now run through each entry in the add index starting
|
||||
// at our starting index. We'll continue until we reach the
|
||||
// very end of the current key space.
|
||||
invoiceCursor := addIndex.Cursor()
|
||||
|
||||
// We'll seek to the starting index, then manually advance the
|
||||
// cursor in order to skip the entry with the since add index.
|
||||
invoiceCursor.Seek(startIndex[:])
|
||||
addSeqNo, invoiceKey := invoiceCursor.Next()
|
||||
|
||||
for ; addSeqNo != nil && bytes.Compare(addSeqNo, startIndex[:]) > 0; addSeqNo, invoiceKey = invoiceCursor.Next() {
|
||||
|
||||
// For each key found, we'll look up the actual
|
||||
// invoice, then accumulate it into our return value.
|
||||
invoice, err := fetchInvoice(invoiceKey, invoices)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newInvoices = append(newInvoices, invoice)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
switch {
|
||||
// If no invoices have been created, then we'll return the empty set of
|
||||
// invoices.
|
||||
case err == ErrNoInvoicesCreated:
|
||||
|
||||
case err != nil:
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return newInvoices, nil
|
||||
}
|
||||
|
||||
// LookupInvoice attempts to look up an invoice according to its 32 byte
|
||||
// payment hash. If an invoice which can settle the HTLC identified by the
|
||||
// passed payment hash isn't found, then an error is returned. Otherwise, the
|
||||
// full invoice is returned. Before setting the incoming HTLC, the values
|
||||
// SHOULD be checked to ensure the payer meets the agreed upon contractual
|
||||
// terms of the payment.
|
||||
func (d *DB) LookupInvoice(paymentHash [32]byte) (Invoice, error) {
|
||||
var invoice Invoice
|
||||
err := d.View(func(tx *bbolt.Tx) error {
|
||||
invoices := tx.Bucket(invoiceBucket)
|
||||
if invoices == nil {
|
||||
return ErrNoInvoicesCreated
|
||||
}
|
||||
invoiceIndex := invoices.Bucket(invoiceIndexBucket)
|
||||
if invoiceIndex == nil {
|
||||
return ErrNoInvoicesCreated
|
||||
}
|
||||
|
||||
// Check the invoice index to see if an invoice paying to this
|
||||
// hash exists within the DB.
|
||||
invoiceNum := invoiceIndex.Get(paymentHash[:])
|
||||
if invoiceNum == nil {
|
||||
return ErrInvoiceNotFound
|
||||
}
|
||||
|
||||
// An invoice matching the payment hash has been found, so
|
||||
// retrieve the record of the invoice itself.
|
||||
i, err := fetchInvoice(invoiceNum, invoices)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
invoice = i
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return invoice, err
|
||||
}
|
||||
|
||||
return invoice, nil
|
||||
}
|
||||
|
||||
// FetchAllInvoices returns all invoices currently stored within the database.
|
||||
// If the pendingOnly param is true, then only unsettled invoices will be
|
||||
// returned, skipping all invoices that are fully settled.
|
||||
@@ -549,343 +290,6 @@ func (d *DB) FetchAllInvoices(pendingOnly bool) ([]Invoice, error) {
|
||||
return invoices, nil
|
||||
}
|
||||
|
||||
// InvoiceQuery represents a query to the invoice database. The query allows a
|
||||
// caller to retrieve all invoices starting from a particular add index and
|
||||
// limit the number of results returned.
|
||||
type InvoiceQuery struct {
|
||||
// IndexOffset is the offset within the add indices to start at. This
|
||||
// can be used to start the response at a particular invoice.
|
||||
IndexOffset uint64
|
||||
|
||||
// NumMaxInvoices is the maximum number of invoices that should be
|
||||
// starting from the add index.
|
||||
NumMaxInvoices uint64
|
||||
|
||||
// PendingOnly, if set, returns unsettled invoices starting from the
|
||||
// add index.
|
||||
PendingOnly bool
|
||||
|
||||
// Reversed, if set, indicates that the invoices returned should start
|
||||
// from the IndexOffset and go backwards.
|
||||
Reversed bool
|
||||
}
|
||||
|
||||
// InvoiceSlice is the response to a invoice query. It includes the original
|
||||
// query, the set of invoices that match the query, and an integer which
|
||||
// represents the offset index of the last item in the set of returned invoices.
|
||||
// This integer allows callers to resume their query using this offset in the
|
||||
// event that the query's response exceeds the maximum number of returnable
|
||||
// invoices.
|
||||
type InvoiceSlice struct {
|
||||
InvoiceQuery
|
||||
|
||||
// Invoices is the set of invoices that matched the query above.
|
||||
Invoices []Invoice
|
||||
|
||||
// FirstIndexOffset is the index of the first element in the set of
|
||||
// returned Invoices above. Callers can use this to resume their query
|
||||
// in the event that the slice has too many events to fit into a single
|
||||
// response.
|
||||
FirstIndexOffset uint64
|
||||
|
||||
// LastIndexOffset is the index of the last element in the set of
|
||||
// returned Invoices above. Callers can use this to resume their query
|
||||
// in the event that the slice has too many events to fit into a single
|
||||
// response.
|
||||
LastIndexOffset uint64
|
||||
}
|
||||
|
||||
// QueryInvoices allows a caller to query the invoice database for invoices
|
||||
// within the specified add index range.
|
||||
func (d *DB) QueryInvoices(q InvoiceQuery) (InvoiceSlice, error) {
|
||||
resp := InvoiceSlice{
|
||||
InvoiceQuery: q,
|
||||
}
|
||||
|
||||
err := d.View(func(tx *bbolt.Tx) error {
|
||||
// If the bucket wasn't found, then there aren't any invoices
|
||||
// within the database yet, so we can simply exit.
|
||||
invoices := tx.Bucket(invoiceBucket)
|
||||
if invoices == nil {
|
||||
return ErrNoInvoicesCreated
|
||||
}
|
||||
invoiceAddIndex := invoices.Bucket(addIndexBucket)
|
||||
if invoiceAddIndex == nil {
|
||||
return ErrNoInvoicesCreated
|
||||
}
|
||||
|
||||
// keyForIndex is a helper closure that retrieves the invoice
|
||||
// key for the given add index of an invoice.
|
||||
keyForIndex := func(c *bbolt.Cursor, index uint64) []byte {
|
||||
var keyIndex [8]byte
|
||||
byteOrder.PutUint64(keyIndex[:], index)
|
||||
_, invoiceKey := c.Seek(keyIndex[:])
|
||||
return invoiceKey
|
||||
}
|
||||
|
||||
// nextKey is a helper closure to determine what the next
|
||||
// invoice key is when iterating over the invoice add index.
|
||||
nextKey := func(c *bbolt.Cursor) ([]byte, []byte) {
|
||||
if q.Reversed {
|
||||
return c.Prev()
|
||||
}
|
||||
return c.Next()
|
||||
}
|
||||
|
||||
// We'll be using a cursor to seek into the database and return
|
||||
// a slice of invoices. We'll need to determine where to start
|
||||
// our cursor depending on the parameters set within the query.
|
||||
c := invoiceAddIndex.Cursor()
|
||||
invoiceKey := keyForIndex(c, q.IndexOffset+1)
|
||||
|
||||
// If the query is specifying reverse iteration, then we must
|
||||
// handle a few offset cases.
|
||||
if q.Reversed {
|
||||
switch q.IndexOffset {
|
||||
|
||||
// This indicates the default case, where no offset was
|
||||
// specified. In that case we just start from the last
|
||||
// invoice.
|
||||
case 0:
|
||||
_, invoiceKey = c.Last()
|
||||
|
||||
// This indicates the offset being set to the very
|
||||
// first invoice. Since there are no invoices before
|
||||
// this offset, and the direction is reversed, we can
|
||||
// return without adding any invoices to the response.
|
||||
case 1:
|
||||
return nil
|
||||
|
||||
// Otherwise we start iteration at the invoice prior to
|
||||
// the offset.
|
||||
default:
|
||||
invoiceKey = keyForIndex(c, q.IndexOffset-1)
|
||||
}
|
||||
}
|
||||
|
||||
// If we know that a set of invoices exists, then we'll begin
|
||||
// our seek through the bucket in order to satisfy the query.
|
||||
// We'll continue until either we reach the end of the range, or
|
||||
// reach our max number of invoices.
|
||||
for ; invoiceKey != nil; _, invoiceKey = nextKey(c) {
|
||||
// If our current return payload exceeds the max number
|
||||
// of invoices, then we'll exit now.
|
||||
if uint64(len(resp.Invoices)) >= q.NumMaxInvoices {
|
||||
break
|
||||
}
|
||||
|
||||
invoice, err := fetchInvoice(invoiceKey, invoices)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Skip any settled invoices if the caller is only
|
||||
// interested in unsettled.
|
||||
if q.PendingOnly &&
|
||||
invoice.Terms.State == ContractSettled {
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// At this point, we've exhausted the offset, so we'll
|
||||
// begin collecting invoices found within the range.
|
||||
resp.Invoices = append(resp.Invoices, invoice)
|
||||
}
|
||||
|
||||
// If we iterated through the add index in reverse order, then
|
||||
// we'll need to reverse the slice of invoices to return them in
|
||||
// forward order.
|
||||
if q.Reversed {
|
||||
numInvoices := len(resp.Invoices)
|
||||
for i := 0; i < numInvoices/2; i++ {
|
||||
opposite := numInvoices - i - 1
|
||||
resp.Invoices[i], resp.Invoices[opposite] =
|
||||
resp.Invoices[opposite], resp.Invoices[i]
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil && err != ErrNoInvoicesCreated {
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// Finally, record the indexes of the first and last invoices returned
|
||||
// so that the caller can resume from this point later on.
|
||||
if len(resp.Invoices) > 0 {
|
||||
resp.FirstIndexOffset = resp.Invoices[0].AddIndex
|
||||
resp.LastIndexOffset = resp.Invoices[len(resp.Invoices)-1].AddIndex
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// UpdateInvoice attempts to update an invoice corresponding to the passed
|
||||
// payment hash. If an invoice matching the passed payment hash doesn't exist
|
||||
// within the database, then the action will fail with a "not found" error.
|
||||
//
|
||||
// The update is performed inside the same database transaction that fetches the
|
||||
// invoice and is therefore atomic. The fields to update are controlled by the
|
||||
// supplied callback.
|
||||
func (d *DB) UpdateInvoice(paymentHash lntypes.Hash,
|
||||
callback InvoiceUpdateCallback) (*Invoice, error) {
|
||||
|
||||
var updatedInvoice *Invoice
|
||||
err := d.Update(func(tx *bbolt.Tx) error {
|
||||
invoices, err := tx.CreateBucketIfNotExists(invoiceBucket)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
invoiceIndex, err := invoices.CreateBucketIfNotExists(
|
||||
invoiceIndexBucket,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
settleIndex, err := invoices.CreateBucketIfNotExists(
|
||||
settleIndexBucket,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Check the invoice index to see if an invoice paying to this
|
||||
// hash exists within the DB.
|
||||
invoiceNum := invoiceIndex.Get(paymentHash[:])
|
||||
if invoiceNum == nil {
|
||||
return ErrInvoiceNotFound
|
||||
}
|
||||
|
||||
updatedInvoice, err = d.updateInvoice(
|
||||
paymentHash, invoices, settleIndex, invoiceNum,
|
||||
callback,
|
||||
)
|
||||
|
||||
return err
|
||||
})
|
||||
|
||||
return updatedInvoice, err
|
||||
}
|
||||
|
||||
// InvoicesSettledSince can be used by callers to catch up any settled invoices
|
||||
// they missed within the settled invoice time series. We'll return all known
|
||||
// settled invoice that have a settle index higher than the passed
|
||||
// sinceSettleIndex.
|
||||
//
|
||||
// NOTE: The index starts from 1, as a result. We enforce that specifying a
|
||||
// value below the starting index value is a noop.
|
||||
func (d *DB) InvoicesSettledSince(sinceSettleIndex uint64) ([]Invoice, error) {
|
||||
var settledInvoices []Invoice
|
||||
|
||||
// If an index of zero was specified, then in order to maintain
|
||||
// backwards compat, we won't send out any new invoices.
|
||||
if sinceSettleIndex == 0 {
|
||||
return settledInvoices, nil
|
||||
}
|
||||
|
||||
var startIndex [8]byte
|
||||
byteOrder.PutUint64(startIndex[:], sinceSettleIndex)
|
||||
|
||||
err := d.DB.View(func(tx *bbolt.Tx) error {
|
||||
invoices := tx.Bucket(invoiceBucket)
|
||||
if invoices == nil {
|
||||
return ErrNoInvoicesCreated
|
||||
}
|
||||
|
||||
settleIndex := invoices.Bucket(settleIndexBucket)
|
||||
if settleIndex == nil {
|
||||
return ErrNoInvoicesCreated
|
||||
}
|
||||
|
||||
// We'll now run through each entry in the add index starting
|
||||
// at our starting index. We'll continue until we reach the
|
||||
// very end of the current key space.
|
||||
invoiceCursor := settleIndex.Cursor()
|
||||
|
||||
// We'll seek to the starting index, then manually advance the
|
||||
// cursor in order to skip the entry with the since add index.
|
||||
invoiceCursor.Seek(startIndex[:])
|
||||
seqNo, invoiceKey := invoiceCursor.Next()
|
||||
|
||||
for ; seqNo != nil && bytes.Compare(seqNo, startIndex[:]) > 0; seqNo, invoiceKey = invoiceCursor.Next() {
|
||||
|
||||
// For each key found, we'll look up the actual
|
||||
// invoice, then accumulate it into our return value.
|
||||
invoice, err := fetchInvoice(invoiceKey, invoices)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
settledInvoices = append(settledInvoices, invoice)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return settledInvoices, nil
|
||||
}
|
||||
|
||||
func putInvoice(invoices, invoiceIndex, addIndex *bbolt.Bucket,
|
||||
i *Invoice, invoiceNum uint32, paymentHash lntypes.Hash) (
|
||||
uint64, error) {
|
||||
|
||||
// Create the invoice key which is just the big-endian representation
|
||||
// of the invoice number.
|
||||
var invoiceKey [4]byte
|
||||
byteOrder.PutUint32(invoiceKey[:], invoiceNum)
|
||||
|
||||
// Increment the num invoice counter index so the next invoice bares
|
||||
// the proper ID.
|
||||
var scratch [4]byte
|
||||
invoiceCounter := invoiceNum + 1
|
||||
byteOrder.PutUint32(scratch[:], invoiceCounter)
|
||||
if err := invoiceIndex.Put(numInvoicesKey, scratch[:]); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Add the payment hash to the invoice index. This will let us quickly
|
||||
// identify if we can settle an incoming payment, and also to possibly
|
||||
// allow a single invoice to have multiple payment installations.
|
||||
err := invoiceIndex.Put(paymentHash[:], invoiceKey[:])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Next, we'll obtain the next add invoice index (sequence
|
||||
// number), so we can properly place this invoice within this
|
||||
// event stream.
|
||||
nextAddSeqNo, err := addIndex.NextSequence()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// With the next sequence obtained, we'll updating the event series in
|
||||
// the add index bucket to map this current add counter to the index of
|
||||
// this new invoice.
|
||||
var seqNoBytes [8]byte
|
||||
byteOrder.PutUint64(seqNoBytes[:], nextAddSeqNo)
|
||||
if err := addIndex.Put(seqNoBytes[:], invoiceKey[:]); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
i.AddIndex = nextAddSeqNo
|
||||
|
||||
// Finally, serialize the invoice itself to be written to the disk.
|
||||
var buf bytes.Buffer
|
||||
if err := serializeInvoice(&buf, i); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if err := invoices.Put(invoiceKey[:], buf.Bytes()); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return nextAddSeqNo, nil
|
||||
}
|
||||
|
||||
// serializeInvoice serializes an invoice to a writer.
|
||||
//
|
||||
// Note: this function is in use for a migration. Before making changes that
|
||||
@@ -1006,17 +410,6 @@ func serializeHtlcs(w io.Writer, htlcs map[CircuitKey]*InvoiceHTLC) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func fetchInvoice(invoiceNum []byte, invoices *bbolt.Bucket) (Invoice, error) {
|
||||
invoiceBytes := invoices.Get(invoiceNum)
|
||||
if invoiceBytes == nil {
|
||||
return Invoice{}, ErrInvoiceNotFound
|
||||
}
|
||||
|
||||
invoiceReader := bytes.NewReader(invoiceBytes)
|
||||
|
||||
return deserializeInvoice(invoiceReader)
|
||||
}
|
||||
|
||||
func deserializeInvoice(r io.Reader) (Invoice, error) {
|
||||
var err error
|
||||
invoice := Invoice{}
|
||||
@@ -1155,166 +548,3 @@ func deserializeHtlcs(r io.Reader) (map[CircuitKey]*InvoiceHTLC, error) {
|
||||
|
||||
return htlcs, nil
|
||||
}
|
||||
|
||||
// copySlice allocates a new slice and copies the source into it.
|
||||
func copySlice(src []byte) []byte {
|
||||
dest := make([]byte, len(src))
|
||||
copy(dest, src)
|
||||
return dest
|
||||
}
|
||||
|
||||
// copyInvoice makes a deep copy of the supplied invoice.
|
||||
func copyInvoice(src *Invoice) *Invoice {
|
||||
dest := Invoice{
|
||||
Memo: copySlice(src.Memo),
|
||||
Receipt: copySlice(src.Receipt),
|
||||
PaymentRequest: copySlice(src.PaymentRequest),
|
||||
FinalCltvDelta: src.FinalCltvDelta,
|
||||
CreationDate: src.CreationDate,
|
||||
SettleDate: src.SettleDate,
|
||||
Terms: src.Terms,
|
||||
AddIndex: src.AddIndex,
|
||||
SettleIndex: src.SettleIndex,
|
||||
AmtPaid: src.AmtPaid,
|
||||
Htlcs: make(
|
||||
map[CircuitKey]*InvoiceHTLC, len(src.Htlcs),
|
||||
),
|
||||
}
|
||||
|
||||
for k, v := range src.Htlcs {
|
||||
dest.Htlcs[k] = v
|
||||
}
|
||||
|
||||
return &dest
|
||||
}
|
||||
|
||||
// updateInvoice fetches the invoice, obtains the update descriptor from the
|
||||
// callback and applies the updates in a single db transaction.
|
||||
func (d *DB) updateInvoice(hash lntypes.Hash, invoices, settleIndex *bbolt.Bucket,
|
||||
invoiceNum []byte, callback InvoiceUpdateCallback) (*Invoice, error) {
|
||||
|
||||
invoice, err := fetchInvoice(invoiceNum, invoices)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
preUpdateState := invoice.Terms.State
|
||||
|
||||
// Create deep copy to prevent any accidental modification in the
|
||||
// callback.
|
||||
copy := copyInvoice(&invoice)
|
||||
|
||||
// Call the callback and obtain the update descriptor.
|
||||
update, err := callback(copy)
|
||||
if err != nil {
|
||||
return &invoice, err
|
||||
}
|
||||
|
||||
// Update invoice state.
|
||||
invoice.Terms.State = update.State
|
||||
|
||||
now := d.now()
|
||||
|
||||
// Update htlc set.
|
||||
for key, htlcUpdate := range update.Htlcs {
|
||||
htlc, ok := invoice.Htlcs[key]
|
||||
|
||||
// No update means the htlc needs to be canceled.
|
||||
if htlcUpdate == nil {
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unknown htlc %v", key)
|
||||
}
|
||||
if htlc.State != HtlcStateAccepted {
|
||||
return nil, fmt.Errorf("can only cancel " +
|
||||
"accepted htlcs")
|
||||
}
|
||||
|
||||
htlc.State = HtlcStateCanceled
|
||||
htlc.ResolveTime = now
|
||||
invoice.AmtPaid -= htlc.Amt
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// Add new htlc paying to the invoice.
|
||||
if ok {
|
||||
return nil, fmt.Errorf("htlc %v already exists", key)
|
||||
}
|
||||
htlc = &InvoiceHTLC{
|
||||
Amt: htlcUpdate.Amt,
|
||||
Expiry: htlcUpdate.Expiry,
|
||||
AcceptHeight: uint32(htlcUpdate.AcceptHeight),
|
||||
AcceptTime: now,
|
||||
}
|
||||
if preUpdateState == ContractSettled {
|
||||
htlc.State = HtlcStateSettled
|
||||
htlc.ResolveTime = now
|
||||
} else {
|
||||
htlc.State = HtlcStateAccepted
|
||||
}
|
||||
|
||||
invoice.Htlcs[key] = htlc
|
||||
invoice.AmtPaid += htlc.Amt
|
||||
}
|
||||
|
||||
// If invoice moved to the settled state, update settle index and settle
|
||||
// time.
|
||||
if preUpdateState != invoice.Terms.State &&
|
||||
invoice.Terms.State == ContractSettled {
|
||||
|
||||
if update.Preimage.Hash() != hash {
|
||||
return nil, fmt.Errorf("preimage does not match")
|
||||
}
|
||||
invoice.Terms.PaymentPreimage = update.Preimage
|
||||
|
||||
// Settle all accepted htlcs.
|
||||
for _, htlc := range invoice.Htlcs {
|
||||
if htlc.State != HtlcStateAccepted {
|
||||
continue
|
||||
}
|
||||
|
||||
htlc.State = HtlcStateSettled
|
||||
htlc.ResolveTime = now
|
||||
}
|
||||
|
||||
err := setSettleFields(settleIndex, invoiceNum, &invoice, now)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := serializeInvoice(&buf, &invoice); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := invoices.Put(invoiceNum[:], buf.Bytes()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &invoice, nil
|
||||
}
|
||||
|
||||
func setSettleFields(settleIndex *bbolt.Bucket, invoiceNum []byte,
|
||||
invoice *Invoice, now time.Time) error {
|
||||
|
||||
// Now that we know the invoice hasn't already been settled, we'll
|
||||
// update the settle index so we can place this settle event in the
|
||||
// proper location within our time series.
|
||||
nextSettleSeqNo, err := settleIndex.NextSequence()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var seqNoBytes [8]byte
|
||||
byteOrder.PutUint64(seqNoBytes[:], nextSettleSeqNo)
|
||||
if err := settleIndex.Put(seqNoBytes[:], invoiceNum); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
invoice.Terms.State = ContractSettled
|
||||
invoice.SettleDate = now
|
||||
invoice.SettleIndex = nextSettleSeqNo
|
||||
|
||||
return nil
|
||||
}
|
||||
|
Reference in New Issue
Block a user