package invoices import ( "context" "time" "github.com/lightningnetwork/lnd/channeldb/models" "github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/record" ) // InvoiceDB is the database that stores the information about invoices. type InvoiceDB interface { // 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. // // NOTE: A side effect of this function is that it sets AddIndex on // newInvoice. AddInvoice(ctx context.Context, invoice *Invoice, paymentHash lntypes.Hash) (uint64, error) // 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. InvoicesAddedSince(ctx context.Context, sinceAddIndex uint64) ( []Invoice, error) // 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. LookupInvoice(ctx context.Context, ref InvoiceRef) (Invoice, error) // FetchPendingInvoices returns all invoices that have not yet been // settled or canceled. FetchPendingInvoices(ctx context.Context) (map[lntypes.Hash]Invoice, error) // QueryInvoices allows a caller to query the invoice database for // invoices within the specified add index range. QueryInvoices(ctx context.Context, q InvoiceQuery) (InvoiceSlice, error) // 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. // // TODO(positiveblue): abstract this functionality so it makes sense for // other backends like sql. UpdateInvoice(ctx context.Context, ref InvoiceRef, setIDHint *SetID, callback InvoiceUpdateCallback) (*Invoice, error) // 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. InvoicesSettledSince(ctx context.Context, sinceSettleIndex uint64) ( []Invoice, error) // DeleteInvoice attempts to delete the passed invoices from the // database in one transaction. The passed delete references hold all // keys required to delete the invoices without also needing to // deserialize them. DeleteInvoice(ctx context.Context, invoicesToDelete []InvoiceDeleteRef) error // DeleteCanceledInvoices removes all canceled invoices from the // database. DeleteCanceledInvoices(ctx context.Context) error } // Payload abstracts access to any additional fields provided in the final hop's // TLV onion payload. type Payload interface { // MultiPath returns the record corresponding the option_mpp parsed from // the onion payload. MultiPath() *record.MPP // AMPRecord returns the record corresponding to the option_amp record // parsed from the onion payload. AMPRecord() *record.AMP // CustomRecords returns the custom tlv type records that were parsed // from the payload. CustomRecords() record.CustomSet // Metadata returns the additional data that is sent along with the // payment to the payee. Metadata() []byte } // 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 // CreationDateStart, expressed in Unix seconds, if set, filters out // all invoices with a creation date greater than or equal to it. CreationDateStart int64 // CreationDateEnd, if set, filters out all invoices with a creation // date less than or equal to it. CreationDateEnd int64 } // 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 } // CircuitKey is a tuple of channel ID and HTLC ID, used to uniquely identify // HTLCs in a circuit. type CircuitKey = models.CircuitKey // InvoiceUpdater is an interface to abstract away the details of updating an // invoice in the database. The methods of this interface are called during the // in-memory update of an invoice when the database needs to be updated or the // updated state needs to be marked as needing to be written to the database. type InvoiceUpdater interface { // AddHtlc adds a new htlc to the invoice. AddHtlc(circuitKey CircuitKey, newHtlc *InvoiceHTLC) error // ResolveHtlc marks an htlc as resolved with the given state. ResolveHtlc(circuitKey CircuitKey, state HtlcState, resolveTime time.Time) error // AddAmpHtlcPreimage adds a preimage of an AMP htlc to the AMP invoice // identified by the setID. AddAmpHtlcPreimage(setID [32]byte, circuitKey CircuitKey, preimage lntypes.Preimage) error // UpdateInvoiceState updates the invoice state to the new state. UpdateInvoiceState(newState ContractState, preimage *lntypes.Preimage) error // UpdateInvoiceAmtPaid updates the invoice amount paid to the new // amount. UpdateInvoiceAmtPaid(amtPaid lnwire.MilliSatoshi) error // UpdateAmpState updates the state of the AMP invoice identified by // the setID. UpdateAmpState(setID [32]byte, newState InvoiceStateAMP, circuitKey models.CircuitKey) error // Finalize finalizes the update before it is written to the database. Finalize(updateType UpdateType) error }