Skip to content

Commit

Permalink
invoices: implement the rest of the InvoiceUpdater interface
Browse files Browse the repository at this point in the history
  • Loading branch information
bhandras committed Nov 17, 2023
1 parent 42e1e4f commit fbd6170
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 30 deletions.
40 changes: 40 additions & 0 deletions channeldb/invoices.go
Original file line number Diff line number Diff line change
Expand Up @@ -1797,6 +1797,46 @@ type kvInvoiceUpdater struct {
settledSetIDs map[invpkg.SetID]struct{}
}

// NOTE: this method does nothing the k/v InvoiceUpdater.
func (k *kvInvoiceUpdater) AddHtlc(_ models.CircuitKey,
_ *invpkg.InvoiceHTLC) error {

return nil
}

// NOTE: this method does nothing the k/v InvoiceUpdater.
func (k *kvInvoiceUpdater) ResolveHtlc(_ models.CircuitKey, _ invpkg.HtlcState,
_ time.Time) error {

return nil
}

// NOTE: this method does nothing the k/v InvoiceUpdater.
func (k *kvInvoiceUpdater) AddAmpHtlcPreimage(_ [32]byte, _ models.CircuitKey,
_ lntypes.Preimage) error {

return nil
}

// NOTE: this method does nothing the k/v InvoiceUpdater.
func (k *kvInvoiceUpdater) UpdateInvoiceState(_ invpkg.ContractState,
_ *lntypes.Preimage) error {

return nil
}

// NOTE: this method does nothing the k/v InvoiceUpdater.
func (k *kvInvoiceUpdater) UpdateInvoiceAmtPaid(_ lnwire.MilliSatoshi) error {
return nil
}

// NOTE: this method does nothing in the k/v InvoiceUpdater.
func (k *kvInvoiceUpdater) UpdateAmpState(_ [32]byte,
_ invpkg.InvoiceStateAMP) error {

return nil
}

func (k *kvInvoiceUpdater) AcceptHtlcAmp(setID [32]byte,
circuitKey models.CircuitKey) error {

Expand Down
18 changes: 10 additions & 8 deletions invoices/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

"github.com/lightningnetwork/lnd/channeldb/models"
"github.com/lightningnetwork/lnd/lntypes"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/record"
)

Expand Down Expand Up @@ -169,19 +170,20 @@ type CircuitKey = models.CircuitKey
// in-memory update of an invoice is complete, and the database needs to be
// updated.
type InvoiceUpdater interface {
// TODO(bhandras): add theses methods to the interface.
AddHtlc(circuitKey CircuitKey, newHtlc *InvoiceHTLC) error

//UpdateInvoiceState(newState ContractState) error
ResolveHtlc(circuitKey CircuitKey, state HtlcState,
resolveTime time.Time) error

//ResolveHtlc(circuitKey CircuitKey, state HtlcState,
// resolveTime time.Time) error
AddAmpHtlcPreimage(setID [32]byte, circuitKey CircuitKey,
preimage lntypes.Preimage) error

//AddAmpHtlcPreimage(setID [32]byte, circuitKey CircuitKey,
// preimage lntypes.Preimage) error
UpdateInvoiceState(newState ContractState,
preimage *lntypes.Preimage) error

//UpdteInvoiceAmtPaid(amtPaid lnwire.MilliSatoshi) error
UpdateInvoiceAmtPaid(amtPaid lnwire.MilliSatoshi) error

//UpdateAmpState(setID [32]byte, newState InvoiceStateAMP) error
UpdateAmpState(setID [32]byte, newState InvoiceStateAMP) error

AcceptHtlcAmp(setID [32]byte, circuitKey CircuitKey) error

Expand Down
124 changes: 102 additions & 22 deletions invoices/update_invoice.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,16 @@ func UpdateInvoice(hash *lntypes.Hash, invoice *Invoice, updateTime time.Time,

case SettleHodlInvoiceUpdate:
err := settleHodlInvoice(
invoice, hash, updateTime, update.State,
invoice, hash, updateTime, update.State, updater,
)
if err != nil {
return nil, err
}

case CancelInvoiceUpdate:
err := cancelInvoice(invoice, hash, updateTime, update.State)
err := cancelInvoice(
invoice, hash, updateTime, update.State, updater,
)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -93,8 +95,12 @@ func cancelHTLCs(invoice *Invoice, updateTime time.Time,
return err
}

htlc.State = HtlcStateCanceled
htlc.ResolveTime = updateTime
err = resolveHtlc(
key, htlc, HtlcStateCanceled, updateTime, updater,
)
if err != nil {
return err
}

// Tally this into the set of HTLCs that need to be updated on
// disk, but once again, only if this is an AMP invoice.
Expand Down Expand Up @@ -141,6 +147,9 @@ func addHTLCs(invoice *Invoice, hash *lntypes.Hash, updateTime time.Time,
AMP: htlcUpdate.AMP.Copy(),
}

if err := updater.AddHtlc(key, htlc); err != nil {
return err
}
invoice.Htlcs[key] = htlc

// Collect the set of new HTLCs so we can write them properly
Expand Down Expand Up @@ -181,6 +190,10 @@ func addHTLCs(invoice *Invoice, hash *lntypes.Hash, updateTime time.Time,
// each _htlc set_ instead. However, we'll allow the invoice to
// transition to the cancelled state regardless.
if !invoiceIsAMP || *newState == ContractCanceled {
err := updater.UpdateInvoiceState(*newState, preimage)
if err != nil {
return err
}
invoice.State = *newState
invoice.Terms.PaymentPreimage = preimage
}
Expand All @@ -206,6 +219,12 @@ func addHTLCs(invoice *Invoice, hash *lntypes.Hash, updateTime time.Time,
// If we don't already have a preimage for this HTLC, we
// can set it now.
case ok && htlc.AMP.Preimage == nil:
err := updater.AddAmpHtlcPreimage(
htlc.AMP.Record.SetID(), key, preimage,
)
if err != nil {
return err
}
htlc.AMP.Preimage = &preimage

// Otherwise, prevent over-writing an existing
Expand Down Expand Up @@ -237,8 +256,9 @@ func addHTLCs(invoice *Invoice, hash *lntypes.Hash, updateTime time.Time,
}

if htlcStateChanged {
htlc.State = htlcState
htlc.ResolveTime = updateTime
err = resolveHtlc(

Check failure on line 259 in invoices/update_invoice.go

View workflow job for this annotation

GitHub Actions / lint code

ineffectual assignment to err (ineffassign)
key, htlc, htlcState, updateTime, updater,
)
}

htlcSettled := htlcStateChanged && htlcState == HtlcStateSettled
Expand Down Expand Up @@ -286,20 +306,45 @@ func addHTLCs(invoice *Invoice, hash *lntypes.Hash, updateTime time.Time,
// For non-AMP invoices we recalculate the amount paid from scratch
// each time, while for AMP invoices, we'll accumulate only based on
// newly added HTLCs.
if !invoiceIsAMP {
invoice.AmtPaid = amtPaid
} else {
invoice.AmtPaid += amtPaid
if invoiceIsAMP {
amtPaid += invoice.AmtPaid
}

return updateInvoiceAmtPaid(invoice, amtPaid, updater)

}

func resolveHtlc(circuitKey models.CircuitKey, htlc *InvoiceHTLC,
state HtlcState, resolveTime time.Time, updater InvoiceUpdater) error {

err := updater.ResolveHtlc(circuitKey, state, resolveTime)
if err != nil {
return err
}
htlc.State = state
htlc.ResolveTime = resolveTime

return nil
}

func updateInvoiceAmtPaid(invoice *Invoice, amt lnwire.MilliSatoshi,
updater InvoiceUpdater) error {

err := updater.UpdateInvoiceAmtPaid(amt)
if err != nil {
return err
}
invoice.AmtPaid = amt

return nil
}

// settleHodlInvoice marks a hodl invoice as settled.
//
// NOTE: Currently it is not possible to have HODL AMP invoices.
func settleHodlInvoice(invoice *Invoice, hash *lntypes.Hash,
updateTime time.Time, update *InvoiceStateUpdateDesc) error {
updateTime time.Time, update *InvoiceStateUpdateDesc,
updater InvoiceUpdater) error {

if !invoice.HodlInvoice {
return fmt.Errorf("unable to settle hodl invoice: %v is "+
Expand Down Expand Up @@ -333,12 +378,16 @@ func settleHodlInvoice(invoice *Invoice, hash *lntypes.Hash,
"new computed state is not settled: %s", newState)
}

err = updater.UpdateInvoiceState(ContractSettled, preimage)
if err != nil {
return err
}
invoice.State = ContractSettled
invoice.Terms.PaymentPreimage = preimage

// TODO(positiveblue): this logic can be further simplified.
var amtPaid lnwire.MilliSatoshi
for _, htlc := range invoice.Htlcs {
for key, htlc := range invoice.Htlcs {
settled, _, err := getUpdatedHtlcState(
htlc, ContractSettled, nil,
)
Expand All @@ -347,21 +396,26 @@ func settleHodlInvoice(invoice *Invoice, hash *lntypes.Hash,
}

if settled {
htlc.State = HtlcStateSettled
htlc.ResolveTime = updateTime
err = resolveHtlc(
key, htlc, HtlcStateSettled, updateTime,
updater,
)
if err != nil {
return err
}

amtPaid += htlc.Amt
}
}

invoice.AmtPaid = amtPaid

return nil
return updateInvoiceAmtPaid(invoice, amtPaid, updater)
}

// cancelInvoice attempts to cancel the given invoice. That includes changing
// the invoice state and the state of any relevant HTLC.
func cancelInvoice(invoice *Invoice, hash *lntypes.Hash,
updateTime time.Time, update *InvoiceStateUpdateDesc) error {
updateTime time.Time, update *InvoiceStateUpdateDesc,
updater InvoiceUpdater) error {

switch {
case update == nil:
Expand Down Expand Up @@ -393,9 +447,13 @@ func cancelInvoice(invoice *Invoice, hash *lntypes.Hash,
newState)
}

err = updater.UpdateInvoiceState(ContractCanceled, nil)
if err != nil {
return err
}
invoice.State = ContractCanceled

for _, htlc := range invoice.Htlcs {
for key, htlc := range invoice.Htlcs {
canceled, _, err := getUpdatedHtlcState(
htlc, ContractCanceled, setID,
)
Expand All @@ -404,8 +462,13 @@ func cancelInvoice(invoice *Invoice, hash *lntypes.Hash,
}

if canceled {
htlc.State = HtlcStateCanceled
htlc.ResolveTime = updateTime
err = resolveHtlc(
key, htlc, HtlcStateCanceled, updateTime,
updater,
)
if err != nil {
return err
}
}
}

Expand Down Expand Up @@ -560,6 +623,11 @@ func cancelHtlcsAmp(invoice *Invoice, circuitKey models.CircuitKey,

invoice.AMPState[setID] = newAmpState

// Mark the updates as needing to be written to disk.
if err := updater.UpdateAmpState(setID, newAmpState); err != nil {
return err
}

err := updater.CancelHtlcAmp(setID, circuitKey)
if err != nil {
return err
Expand All @@ -568,7 +636,9 @@ func cancelHtlcsAmp(invoice *Invoice, circuitKey models.CircuitKey,
// We'll only decrement the total amount paid if the invoice was
// already in the accepted state.
if invoice.AmtPaid != 0 {
invoice.AmtPaid -= htlc.Amt
return updateInvoiceAmtPaid(
invoice, invoice.AmtPaid-htlc.Amt, updater,
)
}

return nil
Expand Down Expand Up @@ -603,6 +673,11 @@ func acceptHtlcsAmp(invoice *Invoice, setID SetID, circuitKey models.CircuitKey,
)
invoice.AMPState[setID] = newAmpState

// Mark the updates as needing to be written to disk.
if err := updater.UpdateAmpState(setID, newAmpState); err != nil {
return err
}

return updater.AcceptHtlcAmp(setID, circuitKey)
}

Expand All @@ -622,6 +697,11 @@ func settleHtlcsAmp(invoice *Invoice, circuitKey models.CircuitKey,

invoice.AMPState[setID] = newAmpState

// Mark the updates as needing to be written to disk.
if err := updater.UpdateAmpState(setID, newAmpState); err != nil {
return err
}

return updater.SettleHtlcAmp(setID, circuitKey)
}

Expand Down

0 comments on commit fbd6170

Please sign in to comment.