channeldb: clean updateInvoice func
All the updates type are now catched in a switch statement, we can delete the rest of the body of this function + add a default path for not matched flows.
This commit is contained in:
1 file changed
+4
-243
+4
-243
@@ -1913,250 +1913,11 @@ func (d *DB) updateInvoice(hash *lntypes.Hash, refSetID *invpkg.SetID, invoices,
|
|||||||
return d.cancelInvoice(
|
return d.cancelInvoice(
|
||||||
invoices, invoiceNum, &invoice, hash, update.State,
|
invoices, invoiceNum, &invoice, hash, update.State,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unknown update type: %s",
|
||||||
|
update.UpdateType)
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
setID *[32]byte
|
|
||||||
)
|
|
||||||
|
|
||||||
// We can either get the set ID from the main state update (if the
|
|
||||||
// state is changing), or via the hint passed in returned by the update
|
|
||||||
// call back.
|
|
||||||
if update.State != nil {
|
|
||||||
setID = update.State.SetID
|
|
||||||
}
|
|
||||||
|
|
||||||
now := d.clock.Now()
|
|
||||||
|
|
||||||
invoiceIsAMP := invoiceCopy.IsAMP()
|
|
||||||
|
|
||||||
// Process add actions from update descriptor.
|
|
||||||
htlcsAmpUpdate := make(map[invpkg.SetID]map[models.CircuitKey]*invpkg.InvoiceHTLC) //nolint:lll
|
|
||||||
for key, htlcUpdate := range update.AddHtlcs {
|
|
||||||
if _, exists := invoice.Htlcs[key]; exists {
|
|
||||||
return nil, fmt.Errorf("duplicate add of htlc %v", key)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Force caller to supply htlc without custom records in a
|
|
||||||
// consistent way.
|
|
||||||
if htlcUpdate.CustomRecords == nil {
|
|
||||||
return nil, errors.New("nil custom records map")
|
|
||||||
}
|
|
||||||
|
|
||||||
// If a newly added HTLC has an associated set id, use it to
|
|
||||||
// index this invoice in the set id index. An error is returned
|
|
||||||
// if we find the index already points to a different invoice.
|
|
||||||
var setID [32]byte
|
|
||||||
if htlcUpdate.AMP != nil {
|
|
||||||
setID = htlcUpdate.AMP.Record.SetID()
|
|
||||||
setIDInvNum := setIDIndex.Get(setID[:])
|
|
||||||
if setIDInvNum == nil {
|
|
||||||
err = setIDIndex.Put(setID[:], invoiceNum)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
} else if !bytes.Equal(setIDInvNum, invoiceNum) {
|
|
||||||
err = invpkg.ErrDuplicateSetID{SetID: setID}
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
htlc := &invpkg.InvoiceHTLC{
|
|
||||||
Amt: htlcUpdate.Amt,
|
|
||||||
MppTotalAmt: htlcUpdate.MppTotalAmt,
|
|
||||||
Expiry: htlcUpdate.Expiry,
|
|
||||||
AcceptHeight: uint32(htlcUpdate.AcceptHeight),
|
|
||||||
AcceptTime: now,
|
|
||||||
State: invpkg.HtlcStateAccepted,
|
|
||||||
CustomRecords: htlcUpdate.CustomRecords,
|
|
||||||
AMP: htlcUpdate.AMP.Copy(),
|
|
||||||
}
|
|
||||||
|
|
||||||
invoice.Htlcs[key] = htlc
|
|
||||||
|
|
||||||
// Collect the set of new HTLCs so we can write them properly
|
|
||||||
// below, but only if this is an AMP invoice.
|
|
||||||
if invoiceIsAMP {
|
|
||||||
updateHtlcsAmp(
|
|
||||||
&invoice, htlcsAmpUpdate, htlc, setID, key,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// At this point, the set of accepted HTLCs should be fully
|
|
||||||
// populated with added HTLCs or removed of canceled ones. Update
|
|
||||||
// invoice state if the update descriptor indicates an invoice state
|
|
||||||
// change, which depends on having an accurate view of the accepted
|
|
||||||
// HTLCs.
|
|
||||||
if update.State != nil {
|
|
||||||
newState, err := updateInvoiceState(
|
|
||||||
&invoice, hash, *update.State,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// If this isn't an AMP invoice, then we'll go ahead and update
|
|
||||||
// the invoice state directly here. For AMP invoices, we
|
|
||||||
// instead will keep the top-level invoice open, and instead
|
|
||||||
// update the state of each _htlc set_ instead. However, we'll
|
|
||||||
// allow the invoice to transition to the cancelled state
|
|
||||||
// regardless.
|
|
||||||
if !invoiceIsAMP || *newState == invpkg.ContractCanceled {
|
|
||||||
invoice.State = *newState
|
|
||||||
}
|
|
||||||
|
|
||||||
// If this is a non-AMP invoice, then the state can eventually
|
|
||||||
// go to ContractSettled, so we pass in nil value as part of
|
|
||||||
// setSettleMetaFields.
|
|
||||||
isSettled := update.State.NewState == invpkg.ContractSettled
|
|
||||||
if !invoiceIsAMP && isSettled {
|
|
||||||
err := setSettleMetaFields(
|
|
||||||
settleIndex, invoiceNum, &invoice, now, nil,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The set of HTLC pre-images will only be set if we were actually able
|
|
||||||
// to reconstruct all the AMP pre-images.
|
|
||||||
var settleEligibleAMP bool
|
|
||||||
if update.State != nil {
|
|
||||||
settleEligibleAMP = len(update.State.HTLCPreimages) != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// With any invoice level state transitions recorded, we'll now
|
|
||||||
// finalize the process by updating the state transitions for
|
|
||||||
// individual HTLCs
|
|
||||||
var (
|
|
||||||
settledSetIDs = make(map[invpkg.SetID]struct{})
|
|
||||||
amtPaid lnwire.MilliSatoshi
|
|
||||||
)
|
|
||||||
for key, htlc := range invoice.Htlcs {
|
|
||||||
// Set the HTLC preimage for any AMP HTLCs.
|
|
||||||
if setID != nil && update.State != nil {
|
|
||||||
preimage, ok := update.State.HTLCPreimages[key]
|
|
||||||
switch {
|
|
||||||
// If we don't already have a preimage for this HTLC, we
|
|
||||||
// can set it now.
|
|
||||||
case ok && htlc.AMP.Preimage == nil:
|
|
||||||
htlc.AMP.Preimage = &preimage
|
|
||||||
|
|
||||||
// Otherwise, prevent over-writing an existing
|
|
||||||
// preimage. Ignore the case where the preimage is
|
|
||||||
// identical.
|
|
||||||
case ok && *htlc.AMP.Preimage != preimage:
|
|
||||||
return nil, invpkg.ErrHTLCPreimageAlreadyExists
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The invoice state may have changed and this could have
|
|
||||||
// implications for the states of the individual htlcs. Align
|
|
||||||
// the htlc state with the current invoice state.
|
|
||||||
//
|
|
||||||
// If we have all the pre-images for an AMP invoice, then we'll
|
|
||||||
// act as if we're able to settle the entire invoice. We need
|
|
||||||
// to do this since it's possible for us to settle AMP invoices
|
|
||||||
// while the contract state (on disk) is still in the accept
|
|
||||||
// state.
|
|
||||||
htlcContextState := invoice.State
|
|
||||||
if settleEligibleAMP {
|
|
||||||
htlcContextState = invpkg.ContractSettled
|
|
||||||
}
|
|
||||||
htlcSettled, err := updateHtlc(
|
|
||||||
now, htlc, htlcContextState, setID,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the HTLC has being settled for the first time, and this
|
|
||||||
// is an AMP invoice, then we'll need to update some additional
|
|
||||||
// meta data state.
|
|
||||||
if htlcSettled && invoiceIsAMP {
|
|
||||||
settleHtlcsAmp(
|
|
||||||
&invoice, settledSetIDs, htlcsAmpUpdate, htlc,
|
|
||||||
key,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
accepted := htlc.State == invpkg.HtlcStateAccepted
|
|
||||||
settled := htlc.State == invpkg.HtlcStateSettled
|
|
||||||
invoiceStateReady := accepted || settled
|
|
||||||
|
|
||||||
if !invoiceIsAMP {
|
|
||||||
// Update the running amount paid to this invoice. We
|
|
||||||
// don't include accepted htlcs when the invoice is
|
|
||||||
// still open.
|
|
||||||
if invoice.State != invpkg.ContractOpen &&
|
|
||||||
invoiceStateReady {
|
|
||||||
|
|
||||||
amtPaid += htlc.Amt
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// For AMP invoices, since we won't always be reading
|
|
||||||
// out the total invoice set each time, we'll instead
|
|
||||||
// accumulate newly added invoices to the total amount
|
|
||||||
// paid.
|
|
||||||
if _, ok := update.AddHtlcs[key]; !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the running amount paid to this invoice. AMP
|
|
||||||
// invoices never go to the settled state, so if it's
|
|
||||||
// open, then we tally the HTLC.
|
|
||||||
if invoice.State == invpkg.ContractOpen &&
|
|
||||||
invoiceStateReady {
|
|
||||||
|
|
||||||
amtPaid += htlc.Amt
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
// As we don't update the settle index above for AMP invoices, we'll do
|
|
||||||
// it here for each sub-AMP invoice that was settled.
|
|
||||||
for settledSetID := range settledSetIDs {
|
|
||||||
settledSetID := settledSetID
|
|
||||||
err := setSettleMetaFields(
|
|
||||||
settleIndex, invoiceNum, &invoice, now, &settledSetID,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reserialize and update invoice.
|
|
||||||
var buf bytes.Buffer
|
|
||||||
if err := serializeInvoice(&buf, &invoice); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := invoices.Put(invoiceNum[:], buf.Bytes()); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// If this is an AMP invoice, then we'll actually store the rest of the
|
|
||||||
// HTLCs in-line with the invoice, using the invoice ID as a prefix,
|
|
||||||
// and the AMP key as a suffix: invoiceNum || setID.
|
|
||||||
if invoiceIsAMP {
|
|
||||||
err := updateAMPInvoices(invoices, invoiceNum, htlcsAmpUpdate)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &invoice, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// cancelHTLCs tries to cancel the htlcs in the given InvoiceUpdateDesc.
|
// cancelHTLCs tries to cancel the htlcs in the given InvoiceUpdateDesc.
|
||||||
|
|||||||
Reference in new issue
Block a user