channeldb+invoices: move hold invoice settle logic into registry

This commit is a continuation of the centralization of invoice state
transition logic in the invoice registry.
This commit is contained in:
Joost Jager 2019-08-21 15:24:21 +02:00
parent ad3522f1a6
commit 416bc8c68c
No known key found for this signature in database
GPG Key ID: A61B9D4C393C59C7
3 changed files with 37 additions and 84 deletions

@ -692,8 +692,9 @@ func getUpdateInvoice(amt lnwire.MilliSatoshi) InvoiceUpdateCallback {
}
update := &InvoiceUpdateDesc{
State: ContractSettled,
AmtPaid: amt,
Preimage: invoice.Terms.PaymentPreimage,
State: ContractSettled,
AmtPaid: amt,
}
return update, nil

@ -284,6 +284,9 @@ type InvoiceUpdateDesc struct {
// AmtPaid is the updated amount that has been paid to this invoice.
AmtPaid lnwire.MilliSatoshi
// 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
@ -740,47 +743,8 @@ func (d *DB) UpdateInvoice(paymentHash lntypes.Hash,
}
updatedInvoice, err = updateInvoice(
invoices, settleIndex, invoiceNum, callback,
)
return err
})
return updatedInvoice, err
}
// SettleHoldInvoice sets the preimage of a hodl invoice and marks the invoice
// as settled.
func (d *DB) SettleHoldInvoice(preimage lntypes.Preimage) (*Invoice, error) {
var updatedInvoice *Invoice
hash := preimage.Hash()
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(hash[:])
if invoiceNum == nil {
return ErrInvoiceNotFound
}
updatedInvoice, err = settleHoldInvoice(
invoices, settleIndex, invoiceNum, preimage,
paymentHash, invoices, settleIndex, invoiceNum,
callback,
)
return err
@ -1243,8 +1207,8 @@ func copyInvoice(src *Invoice) *Invoice {
// updateInvoice fetches the invoice, obtains the update descriptor from the
// callback and applies the updates in a single db transaction.
func updateInvoice(invoices, settleIndex *bbolt.Bucket, invoiceNum []byte,
callback InvoiceUpdateCallback) (*Invoice, error) {
func updateInvoice(hash lntypes.Hash, invoices, settleIndex *bbolt.Bucket,
invoiceNum []byte, callback InvoiceUpdateCallback) (*Invoice, error) {
invoice, err := fetchInvoice(invoiceNum, invoices)
if err != nil {
@ -1272,6 +1236,11 @@ func updateInvoice(invoices, settleIndex *bbolt.Bucket, invoiceNum []byte,
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
err := setSettleFields(settleIndex, invoiceNum, &invoice)
if err != nil {
return nil, err
@ -1314,43 +1283,6 @@ func setSettleFields(settleIndex *bbolt.Bucket, invoiceNum []byte,
return nil
}
func settleHoldInvoice(invoices, settleIndex *bbolt.Bucket,
invoiceNum []byte, preimage lntypes.Preimage) (*Invoice,
error) {
invoice, err := fetchInvoice(invoiceNum, invoices)
if err != nil {
return nil, err
}
switch invoice.Terms.State {
case ContractOpen:
return &invoice, ErrInvoiceStillOpen
case ContractCanceled:
return &invoice, ErrInvoiceAlreadyCanceled
case ContractSettled:
return &invoice, ErrInvoiceAlreadySettled
}
invoice.Terms.PaymentPreimage = preimage
err = setSettleFields(settleIndex, invoiceNum, &invoice)
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 cancelInvoice(invoices *bbolt.Bucket, invoiceNum []byte) (
*Invoice, error) {

@ -456,6 +456,7 @@ func (i *InvoiceRegistry) updateInvoice(invoice *channeldb.Invoice,
if holdInvoice {
update.State = channeldb.ContractAccepted
} else {
update.Preimage = invoice.Terms.PaymentPreimage
update.State = channeldb.ContractSettled
}
return &update, nil
@ -587,13 +588,32 @@ func (i *InvoiceRegistry) SettleHodlInvoice(preimage lntypes.Preimage) error {
i.Lock()
defer i.Unlock()
invoice, err := i.cdb.SettleHoldInvoice(preimage)
updateInvoice := func(invoice *channeldb.Invoice) (
*channeldb.InvoiceUpdateDesc, error) {
switch invoice.Terms.State {
case channeldb.ContractOpen:
return nil, channeldb.ErrInvoiceStillOpen
case channeldb.ContractCanceled:
return nil, channeldb.ErrInvoiceAlreadyCanceled
case channeldb.ContractSettled:
return nil, channeldb.ErrInvoiceAlreadySettled
}
return &channeldb.InvoiceUpdateDesc{
AmtPaid: invoice.AmtPaid,
State: channeldb.ContractSettled,
Preimage: preimage,
}, nil
}
hash := preimage.Hash()
invoice, err := i.cdb.UpdateInvoice(hash, updateInvoice)
if err != nil {
log.Errorf("SettleHodlInvoice with preimage %v: %v", preimage, err)
return err
}
hash := preimage.Hash()
log.Debugf("Invoice(%v): settled with preimage %v", hash,
invoice.Terms.PaymentPreimage)