Skip to content

Commit

Permalink
htlcswitch: reject htlc for removed invoice
Browse files Browse the repository at this point in the history
  • Loading branch information
joostjager committed Nov 28, 2018
1 parent ab77df6 commit e2ad744
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 0 deletions.
71 changes: 71 additions & 0 deletions channeldb/invoices.go
Expand Up @@ -95,6 +95,9 @@ const (

// ContractAccepted means the HTLC has been accepted but not settled yet.
ContractAccepted = 2

// ContractRemoved means the invoice has been removed.
ContractRemoved = 3
)

// ContractTerm is a companion struct to the Invoice struct. This struct houses
Expand Down Expand Up @@ -702,6 +705,43 @@ func (d *DB) AcceptInvoice(paymentHash [32]byte,
return acceptedInvoice, nil
}

// RemoveInvoice attempts to remove an invoice corresponding to the
// passed payment hash.
func (d *DB) RemoveInvoice(paymentHash [32]byte) error {
return d.Update(func(tx *bolt.Tx) error {
invoices, err := tx.CreateBucketIfNotExists(invoiceBucket)
if err != nil {
return err
}
invoiceIndex, err := invoices.CreateBucketIfNotExists(
invoiceIndexBucket,
)
if err != nil {
return err
}
acceptedIndex, err := invoices.CreateBucketIfNotExists(
acceptedIndexBucket,
)
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
}

err = removeInvoice(invoices, acceptedIndex, invoiceNum)
if err != nil {
return err
}

return nil
})
}

// InvoicesAcceptedSince can be used by callers to catch up any accepted invoices
// they missed within the accepted invoice time series. We'll return all known
// accepted invoice that have a accept index higher than the passed
Expand Down Expand Up @@ -1101,3 +1141,34 @@ func acceptInvoice(invoices, acceptedIndex *bolt.Bucket, invoiceNum []byte,

return &invoice, nil
}

func removeInvoice(invoices, acceptedIndex *bolt.Bucket,
invoiceNum []byte) error {

invoice, err := fetchInvoice(invoiceNum, invoices)
if err != nil {
return err
}

// Add idempotency to duplicate removed state, return here to avoid
// overwriting the previous info.
switch invoice.Terms.State {
case ContractRemoved:
return nil
case ContractSettled:
return fmt.Errorf("invoice already settled")
}

invoice.Terms.State = ContractRemoved

var buf bytes.Buffer
if err := serializeInvoice(&buf, &invoice); err != nil {
return err
}

if err := invoices.Put(invoiceNum[:], buf.Bytes()); err != nil {
return err
}

return nil
}
4 changes: 4 additions & 0 deletions htlcswitch/interfaces.go
Expand Up @@ -23,6 +23,10 @@ type InvoiceDatabase interface {
// AcceptInvoice attempts to mark an invoice corresponding to the
// passed payment hash as accepted.
AcceptInvoice(payHash chainhash.Hash, paidAmount lnwire.MilliSatoshi) error

// RemoveInvoice attempts to remove an invoice corresponding to the
// passed payment hash.
RemoveInvoice(payHash chainhash.Hash) error
}

// ChannelLink is an interface which represents the subsystem for managing the
Expand Down
14 changes: 14 additions & 0 deletions htlcswitch/link.go
Expand Up @@ -2392,6 +2392,20 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg,
"hash=%x", pd.RHash[:])
}

// Reject htlcs for removed invoices.
if invoice.Terms.State == channeldb.ContractRemoved {
log.Errorf("rejecting htlc due to removed " +
"invoice")

failure := lnwire.FailUnknownPaymentHash{}
l.sendHTLCError(
pd.HtlcIndex, failure, obfuscator, pd.SourceRef,
)

needUpdate = true
continue
}

// If we're not currently in debug mode, and the
// extended htlc doesn't meet the value requested, then
// we'll fail the htlc. Otherwise, we settle this htlc
Expand Down
9 changes: 9 additions & 0 deletions htlcswitch/mock.go
Expand Up @@ -749,6 +749,15 @@ func (i *mockInvoiceRegistry) AcceptInvoice(rhash chainhash.Hash,
return nil
}

func (i *mockInvoiceRegistry) RemoveInvoice(payHash chainhash.Hash) error {
i.Lock()
defer i.Unlock()

delete(i.invoices, payHash)

return nil
}

func (i *mockInvoiceRegistry) AddInvoice(invoice channeldb.Invoice) error {
i.Lock()
defer i.Unlock()
Expand Down
13 changes: 13 additions & 0 deletions invoiceregistry.go
Expand Up @@ -433,6 +433,19 @@ func (i *invoiceRegistry) AcceptInvoice(rHash chainhash.Hash,
return nil
}

// RemoveInvoice attempts to remove an invoice corresponding to the
// passed payment hash.
func (i *invoiceRegistry) RemoveInvoice(payHash chainhash.Hash) error {
i.Lock()
defer i.Unlock()

ltndLog.Debugf("Removing invoice %x", payHash[:])

return i.cdb.RemoveInvoice(payHash)

// TODO: notification of removal.
}

// notifyClients notifies all currently registered invoice notification clients
// of a newly added/settled invoice.
func (i *invoiceRegistry) notifyClients(invoice *channeldb.Invoice,
Expand Down

0 comments on commit e2ad744

Please sign in to comment.