channeldb: move idempotency up the call tree

As a preparation for subscribing to single invoices, InvoiceRegistry
needs to become aware of settling a settled invoice.
This commit is contained in:
Joost Jager 2019-01-14 12:03:26 +01:00
parent 2a4c93cdc4
commit 436dd41c77
No known key found for this signature in database
GPG Key ID: A61B9D4C393C59C7
3 changed files with 20 additions and 16 deletions

@ -359,10 +359,10 @@ func TestDuplicateSettleInvoice(t *testing.T) {
} }
// If we try to settle the invoice again, then we should get the very // If we try to settle the invoice again, then we should get the very
// same invoice back. // same invoice back, but with an error this time.
dbInvoice, err = db.SettleInvoice(payHash, amt) dbInvoice, err = db.SettleInvoice(payHash, amt)
if err != nil { if err != ErrInvoiceAlreadySettled {
t.Fatalf("unable to settle invoice: %v", err) t.Fatalf("expected ErrInvoiceAlreadySettled")
} }
if dbInvoice == nil { if dbInvoice == nil {

@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"crypto/sha256" "crypto/sha256"
"encoding/binary" "encoding/binary"
"errors"
"fmt" "fmt"
"io" "io"
"time" "time"
@ -57,6 +58,10 @@ var (
// //
// settleIndexNo => invoiceKey // settleIndexNo => invoiceKey
settleIndexBucket = []byte("invoice-settle-index") settleIndexBucket = []byte("invoice-settle-index")
// ErrInvoiceAlreadySettled is returned when the invoice is already
// settled.
ErrInvoiceAlreadySettled = errors.New("invoice already settled")
) )
const ( const (
@ -626,21 +631,14 @@ func (d *DB) SettleInvoice(paymentHash [32]byte,
return ErrInvoiceNotFound return ErrInvoiceNotFound
} }
invoice, err := settleInvoice( settledInvoice, err = settleInvoice(
invoices, settleIndex, invoiceNum, amtPaid, invoices, settleIndex, invoiceNum, amtPaid,
) )
if err != nil {
return err
}
settledInvoice = invoice return err
return nil
}) })
if err != nil {
return nil, err
}
return settledInvoice, nil return settledInvoice, err
} }
// InvoicesSettledSince can be used by callers to catch up any settled invoices // InvoicesSettledSince can be used by callers to catch up any settled invoices
@ -898,10 +896,8 @@ func settleInvoice(invoices, settleIndex *bbolt.Bucket, invoiceNum []byte,
return nil, err return nil, err
} }
// Add idempotency to duplicate settles, return here to avoid
// overwriting the previous info.
if invoice.Terms.State == ContractSettled { if invoice.Terms.State == ContractSettled {
return &invoice, nil return &invoice, ErrInvoiceAlreadySettled
} }
// Now that we know the invoice hasn't already been settled, we'll // Now that we know the invoice hasn't already been settled, we'll

@ -378,6 +378,14 @@ func (i *InvoiceRegistry) SettleInvoice(rHash lntypes.Hash,
// If this isn't a debug invoice, then we'll attempt to settle an // If this isn't a debug invoice, then we'll attempt to settle an
// invoice matching this rHash on disk (if one exists). // invoice matching this rHash on disk (if one exists).
invoice, err := i.cdb.SettleInvoice(rHash, amtPaid) invoice, err := i.cdb.SettleInvoice(rHash, amtPaid)
// Implement idempotency by returning success if the invoice was already
// settled.
if err == channeldb.ErrInvoiceAlreadySettled {
log.Debugf("Invoice %v already settled", rHash)
return nil
}
if err != nil { if err != nil {
return err return err
} }