mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-02-22 22:25:24 +01:00
multi: replace errInvoiceNotFound with resolution result
This commit moves handling of invoice not found errors into NotifyExitHopHtlc and exposes a resolution result to the calling functions. The intention of this change is to make calling functions as naive of the invoice registry's mechanics as possible. When NotifyExitHopHtlc is called and an invoice is not found, calling functions can take action based on the HtlcResolution's InvoiceNotFound outcome rather than having to add a special error check on every call to handle the error.
This commit is contained in:
parent
7b5dda0417
commit
d2e395d5f2
6 changed files with 54 additions and 36 deletions
|
@ -201,23 +201,26 @@ func (h *htlcIncomingContestResolver) Resolve() (ContractResolver, error) {
|
||||||
HtlcID: h.htlc.HtlcIndex,
|
HtlcID: h.htlc.HtlcIndex,
|
||||||
}
|
}
|
||||||
|
|
||||||
event, err := h.Registry.NotifyExitHopHtlc(
|
resolution, err := h.Registry.NotifyExitHopHtlc(
|
||||||
h.htlc.RHash, h.htlc.Amt, h.htlcExpiry, currentHeight,
|
h.htlc.RHash, h.htlc.Amt, h.htlcExpiry, currentHeight,
|
||||||
circuitKey, hodlChan, payload,
|
circuitKey, hodlChan, payload,
|
||||||
)
|
)
|
||||||
switch err {
|
if err != nil {
|
||||||
case channeldb.ErrInvoiceNotFound:
|
|
||||||
case nil:
|
|
||||||
defer h.Registry.HodlUnsubscribeAll(hodlChan)
|
|
||||||
|
|
||||||
// Resolve the htlc directly if possible.
|
|
||||||
if event != nil {
|
|
||||||
return processHtlcResolution(*event)
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defer h.Registry.HodlUnsubscribeAll(hodlChan)
|
||||||
|
|
||||||
|
// If the resolution is non-nil (indicating that a settle or cancel has
|
||||||
|
// occurred), and the invoice is known to the registry (indicating that
|
||||||
|
// the htlc is paying one of our invoices and is not a forward), try to
|
||||||
|
// resolve it directly.
|
||||||
|
if resolution != nil &&
|
||||||
|
resolution.Outcome != invoices.ResultInvoiceNotFound {
|
||||||
|
|
||||||
|
return processHtlcResolution(*resolution)
|
||||||
|
}
|
||||||
|
|
||||||
// With the epochs and preimage subscriptions initialized, we'll query
|
// With the epochs and preimage subscriptions initialized, we'll query
|
||||||
// to see if we already know the preimage.
|
// to see if we already know the preimage.
|
||||||
preimage, ok := h.PreimageDB.LookupPreimage(h.htlc.RHash)
|
preimage, ok := h.PreimageDB.LookupPreimage(h.htlc.RHash)
|
||||||
|
|
|
@ -35,7 +35,10 @@ func TestHtlcIncomingResolverFwdPreimageKnown(t *testing.T) {
|
||||||
defer timeout(t)()
|
defer timeout(t)()
|
||||||
|
|
||||||
ctx := newIncomingResolverTestContext(t)
|
ctx := newIncomingResolverTestContext(t)
|
||||||
ctx.registry.notifyErr = channeldb.ErrInvoiceNotFound
|
ctx.registry.notifyResolution = invoices.NewFailureResolution(
|
||||||
|
testResCircuitKey, testHtlcExpiry,
|
||||||
|
invoices.ResultInvoiceNotFound,
|
||||||
|
)
|
||||||
ctx.witnessBeacon.lookupPreimage[testResHash] = testResPreimage
|
ctx.witnessBeacon.lookupPreimage[testResHash] = testResPreimage
|
||||||
ctx.resolve()
|
ctx.resolve()
|
||||||
ctx.waitForResult(true)
|
ctx.waitForResult(true)
|
||||||
|
@ -49,7 +52,10 @@ func TestHtlcIncomingResolverFwdContestedSuccess(t *testing.T) {
|
||||||
defer timeout(t)()
|
defer timeout(t)()
|
||||||
|
|
||||||
ctx := newIncomingResolverTestContext(t)
|
ctx := newIncomingResolverTestContext(t)
|
||||||
ctx.registry.notifyErr = channeldb.ErrInvoiceNotFound
|
ctx.registry.notifyResolution = invoices.NewFailureResolution(
|
||||||
|
testResCircuitKey, testHtlcExpiry,
|
||||||
|
invoices.ResultInvoiceNotFound,
|
||||||
|
)
|
||||||
ctx.resolve()
|
ctx.resolve()
|
||||||
|
|
||||||
// Simulate a new block coming in. HTLC is not yet expired.
|
// Simulate a new block coming in. HTLC is not yet expired.
|
||||||
|
@ -66,7 +72,10 @@ func TestHtlcIncomingResolverFwdContestedTimeout(t *testing.T) {
|
||||||
defer timeout(t)()
|
defer timeout(t)()
|
||||||
|
|
||||||
ctx := newIncomingResolverTestContext(t)
|
ctx := newIncomingResolverTestContext(t)
|
||||||
ctx.registry.notifyErr = channeldb.ErrInvoiceNotFound
|
ctx.registry.notifyResolution = invoices.NewFailureResolution(
|
||||||
|
testResCircuitKey, testHtlcExpiry,
|
||||||
|
invoices.ResultInvoiceNotFound,
|
||||||
|
)
|
||||||
ctx.resolve()
|
ctx.resolve()
|
||||||
|
|
||||||
// Simulate a new block coming in. HTLC expires.
|
// Simulate a new block coming in. HTLC expires.
|
||||||
|
@ -82,8 +91,10 @@ func TestHtlcIncomingResolverFwdTimeout(t *testing.T) {
|
||||||
defer timeout(t)()
|
defer timeout(t)()
|
||||||
|
|
||||||
ctx := newIncomingResolverTestContext(t)
|
ctx := newIncomingResolverTestContext(t)
|
||||||
|
ctx.registry.notifyResolution = invoices.NewFailureResolution(
|
||||||
ctx.registry.notifyErr = channeldb.ErrInvoiceNotFound
|
testResCircuitKey, testHtlcExpiry,
|
||||||
|
invoices.ResultInvoiceNotFound,
|
||||||
|
)
|
||||||
ctx.witnessBeacon.lookupPreimage[testResHash] = testResPreimage
|
ctx.witnessBeacon.lookupPreimage[testResHash] = testResPreimage
|
||||||
ctx.resolver.htlcExpiry = 90
|
ctx.resolver.htlcExpiry = 90
|
||||||
ctx.resolve()
|
ctx.resolve()
|
||||||
|
|
|
@ -2823,21 +2823,7 @@ func (l *channelLink) processExitHop(pd *lnwallet.PaymentDescriptor,
|
||||||
invoiceHash, pd.Amount, pd.Timeout, int32(heightNow),
|
invoiceHash, pd.Amount, pd.Timeout, int32(heightNow),
|
||||||
circuitKey, l.hodlQueue.ChanIn(), payload,
|
circuitKey, l.hodlQueue.ChanIn(), payload,
|
||||||
)
|
)
|
||||||
|
if err != nil {
|
||||||
switch err {
|
|
||||||
|
|
||||||
// Cancel htlc if we don't have an invoice for it.
|
|
||||||
case channeldb.ErrInvoiceNotFound:
|
|
||||||
failure := lnwire.NewFailIncorrectDetails(pd.Amount, heightNow)
|
|
||||||
l.sendHTLCError(pd.HtlcIndex, failure, obfuscator, pd.SourceRef)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
|
|
||||||
// No error.
|
|
||||||
case nil:
|
|
||||||
|
|
||||||
// Pass error to caller.
|
|
||||||
default:
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -758,11 +758,21 @@ func (i *InvoiceRegistry) NotifyExitHopHtlc(rHash lntypes.Hash,
|
||||||
return updateDesc, nil
|
return updateDesc, nil
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
switch err {
|
||||||
debugLog(err.Error())
|
case channeldb.ErrInvoiceNotFound:
|
||||||
|
// If the invoice was not found, return a failure resolution
|
||||||
|
// with an invoice not found result.
|
||||||
|
return NewFailureResolution(
|
||||||
|
circuitKey, currentHeight, ResultInvoiceNotFound,
|
||||||
|
), nil
|
||||||
|
|
||||||
|
case nil:
|
||||||
|
|
||||||
|
default:
|
||||||
|
debugLog(err.Error())
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
debugLog(result.String())
|
debugLog(result.String())
|
||||||
|
|
||||||
if updateSubscribers {
|
if updateSubscribers {
|
||||||
|
|
|
@ -585,12 +585,16 @@ func TestUnknownInvoice(t *testing.T) {
|
||||||
// succeed.
|
// succeed.
|
||||||
hodlChan := make(chan interface{})
|
hodlChan := make(chan interface{})
|
||||||
amt := lnwire.MilliSatoshi(100000)
|
amt := lnwire.MilliSatoshi(100000)
|
||||||
_, err := ctx.registry.NotifyExitHopHtlc(
|
result, err := ctx.registry.NotifyExitHopHtlc(
|
||||||
testInvoicePaymentHash, amt, testHtlcExpiry, testCurrentHeight,
|
testInvoicePaymentHash, amt, testHtlcExpiry, testCurrentHeight,
|
||||||
getCircuitKey(0), hodlChan, testPayload,
|
getCircuitKey(0), hodlChan, testPayload,
|
||||||
)
|
)
|
||||||
if err != channeldb.ErrInvoiceNotFound {
|
if err != nil {
|
||||||
t.Fatal("expected invoice not found error")
|
t.Fatal("unexpected error")
|
||||||
|
}
|
||||||
|
if result.Outcome != ResultInvoiceNotFound {
|
||||||
|
t.Fatalf("expected ResultInvoiceNotFound, got: %v",
|
||||||
|
result.Outcome)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -81,6 +81,10 @@ const (
|
||||||
|
|
||||||
// ResultHtlcSetOverpayment is returned when a mpp set is overpaid.
|
// ResultHtlcSetOverpayment is returned when a mpp set is overpaid.
|
||||||
ResultHtlcSetOverpayment
|
ResultHtlcSetOverpayment
|
||||||
|
|
||||||
|
// ResultInvoiceNotFound is returned when an attempt is made to pay an
|
||||||
|
// invoice that is unknown to us.
|
||||||
|
ResultInvoiceNotFound
|
||||||
)
|
)
|
||||||
|
|
||||||
// String returns a human-readable representation of the invoice update result.
|
// String returns a human-readable representation of the invoice update result.
|
||||||
|
|
Loading…
Add table
Reference in a new issue