multi: replace htlcResolution with an interface

This commit repalces the htlcResolution struct with an interface.
This interface is implemeted by failure, settle and accept resolution
structs. Only settles and fails are exported because the existing
code that handles htlc resolutions uses a nil resolution to indicate
that a htlc was accepted. The accept resolution is used internally
to report on the resolution result of the accepted htlc, but a nil
resolution is surfaced. Further refactoring of all the functions
that call NotifyExitHopHtlc to handle a htlc accept case (rather than
having a nil check) is required.
This commit is contained in:
carla committed 2020-02-06 19:41:36 +02:00
1 parent 2cd26d7556
commit 2569b4d08a
11 files changed
+477 -257

No files matched your search

+1 -1
View File
@@ -27,7 +27,7 @@ type InvoiceDatabase interface {
NotifyExitHopHtlc(payHash lntypes.Hash, paidAmount lnwire.MilliSatoshi,
expiry uint32, currentHeight int32,
circuitKey channeldb.CircuitKey, hodlChan chan<- interface{},
payload invoices.Payload) (*invoices.HtlcResolution, error)
payload invoices.Payload) (invoices.HtlcResolution, error)
// CancelInvoice attempts to cancel the invoice corresponding to the
// passed payment hash.
+41 -26
View File
@@ -1158,7 +1158,7 @@ loop:
for {
// Lookup all hodl htlcs that can be failed or settled with this event.
// The hodl htlc must be present in the map.
circuitKey := htlcResolution.CircuitKey
circuitKey := htlcResolution.CircuitKey()
hodlHtlc, ok := l.hodlMap[circuitKey]
if !ok {
return fmt.Errorf("hodl htlc not found: %v", circuitKey)
@@ -1193,46 +1193,61 @@ loop:
func (l *channelLink) processHtlcResolution(resolution invoices.HtlcResolution,
htlc hodlHtlc) error {
circuitKey := resolution.CircuitKey
circuitKey := resolution.CircuitKey()
// Determine required action for the resolution. If the event's preimage is
// non-nil, the htlc must be settled. Otherwise, it should be canceled.
if resolution.Preimage != nil {
l.log.Debugf("received settle resolution for %v", circuitKey)
// Determine required action for the resolution based on the type of
// resolution we have received.
switch res := resolution.(type) {
// Settle htlcs that returned a settle resolution using the preimage
// in the resolution.
case *invoices.HtlcSettleResolution:
l.log.Debugf("received settle resolution for %v"+
"with outcome: %v", circuitKey, res.Outcome)
return l.settleHTLC(
*resolution.Preimage, htlc.pd.HtlcIndex,
res.Preimage, htlc.pd.HtlcIndex,
htlc.pd.SourceRef,
)
// For htlc failures, we get the relevant failure message based
// on the failure resolution and then fail the htlc.
case *invoices.HtlcFailResolution:
l.log.Debugf("received cancel resolution for "+
"%v with outcome: %v", circuitKey, res.Outcome)
// Get the lnwire failure message based on the resolution
// result.
failure := getResolutionFailure(res, htlc.pd.Amount)
l.sendHTLCError(
htlc.pd.HtlcIndex, failure, htlc.obfuscator,
htlc.pd.SourceRef,
)
return nil
// Fail if we do not get a settle of fail resolution, since we
// are only expecting to handle settles and fails.
default:
return fmt.Errorf("unknown htlc resolution type: %T",
resolution)
}
l.log.Debugf("received cancel resolution for %v with outcome: %v",
circuitKey, resolution.Outcome)
// Get the lnwire failure message based on the resolution result.
failure := getResolutionFailure(resolution, htlc.pd.Amount)
l.sendHTLCError(
htlc.pd.HtlcIndex, failure, htlc.obfuscator,
htlc.pd.SourceRef,
)
return nil
}
// getResolutionFailure returns the wire message that a htlc resolution should
// be failed with.
func getResolutionFailure(resolution invoices.HtlcResolution,
func getResolutionFailure(resolution *invoices.HtlcFailResolution,
amount lnwire.MilliSatoshi) lnwire.FailureMessage {
// If the resolution has been resolved as part of a MPP timeout, we need
// to fail the htlc with lnwire.FailMppTimeout.
// If the resolution has been resolved as part of a MPP timeout,
// we need to fail the htlc with lnwire.FailMppTimeout.
if resolution.Outcome == invoices.ResultMppTimeout {
return &lnwire.FailMPPTimeout{}
}
// If the htlc is not a MPP timeout, we fail it with FailIncorrectDetails
// This covers hodl cancels (which return it to avoid leaking information
// and other invoice failures such as underpayment or expiry too soon.
// If the htlc is not a MPP timeout, we fail it with
// FailIncorrectDetails. This error is sent for invoice payment
// failures such as underpayment/ expiry too soon and hodl invoices
// (which return FailIncorrectDetails to avoid leaking information).
return lnwire.NewFailIncorrectDetails(
amount, uint32(resolution.AcceptHeight),
)
@@ -2863,7 +2878,7 @@ func (l *channelLink) processExitHop(pd *lnwallet.PaymentDescriptor,
}
// Process the received resolution.
return l.processHtlcResolution(*event, htlc)
return l.processHtlcResolution(event, htlc)
}
// settleHTLC settles the HTLC on the channel.
+1 -1
View File
@@ -816,7 +816,7 @@ func (i *mockInvoiceRegistry) SettleHodlInvoice(preimage lntypes.Preimage) error
func (i *mockInvoiceRegistry) NotifyExitHopHtlc(rhash lntypes.Hash,
amt lnwire.MilliSatoshi, expiry uint32, currentHeight int32,
circuitKey channeldb.CircuitKey, hodlChan chan<- interface{},
payload invoices.Payload) (*invoices.HtlcResolution, error) {
payload invoices.Payload) (invoices.HtlcResolution, error) {
event, err := i.registry.NotifyExitHopHtlc(
rhash, amt, expiry, currentHeight, circuitKey, hodlChan,