diff --git a/invoices/errors.go b/invoices/errors.go index 4cc592357..450155b59 100644 --- a/invoices/errors.go +++ b/invoices/errors.go @@ -14,6 +14,9 @@ var ( // canceled. ErrInvoiceAlreadyCanceled = errors.New("invoice already canceled") + // ErrInvoiceNotCanceled is returned when the invoice is not canceled. + ErrInvoiceNotCanceled = errors.New("invoice not canceled") + // ErrInvoiceAlreadyAccepted is returned when the invoice is already // accepted. ErrInvoiceAlreadyAccepted = errors.New("invoice already accepted") @@ -33,6 +36,10 @@ var ( // match the invoice hash. ErrInvoicePreimageMismatch = errors.New("preimage does not match") + // ErrNoInvoiceHash is returned when an invoice hash is expected, and + // none is provided. + ErrNoInvoiceHash = errors.New("invoice hash must be provided") + // ErrHTLCPreimageMissing is returned when trying to accept/settle an // AMP HTLC but the HTLC-level preimage has not been set. ErrHTLCPreimageMissing = errors.New("AMP htlc missing preimage") diff --git a/rpcserver.go b/rpcserver.go index 42074d904..ac4e98e27 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -467,6 +467,10 @@ func MainRPCServerPermissions() map[string][]bakery.Op { Entity: "info", Action: "read", }}, + "/lnrpc.Lightning/DeleteCanceledInvoice": {{ + Entity: "invoices", + Action: "write", + }}, "/lnrpc.Lightning/ListPayments": {{ Entity: "offchain", Action: "read", @@ -7550,6 +7554,45 @@ func (r *rpcServer) ListPayments(ctx context.Context, return paymentsResp, nil } +// DeleteCanceledInvoice remove a canceled invoice from the database. +func (r *rpcServer) DeleteCanceledInvoice(ctx context.Context, + req *lnrpc.DelCanceledInvoiceReq) (*lnrpc.DelCanceledInvoiceResp, + error) { + + if req.InvoiceHash == "" { + return nil, invoices.ErrNoInvoiceHash + } + + hash, err := lntypes.MakeHashFromStr(req.InvoiceHash) + if err != nil { + return nil, err + } + + invoice, err := r.server.invoices.LookupInvoice(ctx, hash) + if err != nil { + return nil, err + } + + if invoice.State != invoices.ContractCanceled { + return nil, invoices.ErrInvoiceNotCanceled + } + + err = r.server.invoicesDB.DeleteInvoice(ctx, + []invoices.InvoiceDeleteRef{ + { + PayHash: hash, + AddIndex: invoice.AddIndex, + }, + }, + ) + if err != nil { + return nil, err + } + + return &lnrpc.DelCanceledInvoiceResp{Status: fmt.Sprintf("canceled "+ + "invoice deleted successfully: invoice hash %v", hash)}, nil +} + // DeletePayment deletes a payment from the DB given its payment hash. If // failedHtlcsOnly is set, only failed HTLC attempts of the payment will be // deleted.