htlcswitch: add failure details to incoming failures
This commit adds LinkErrors with failure details to htlcs which fail on our incoming link. This change is made with the intention of notifying detailed htlc failure reasons in sendHTLCError. The FailureDetail interface is implemented on FailureResolutionResults so that they can directly be used to enrich LinkErrors. sendHtlcError is updated to take a LinkError in preparation for the addition of a htlcnotifier which will notify the detail of the error.
This commit is contained in:
parent
74e0d545fe
commit
1ad395ec3f
@ -1220,8 +1220,8 @@ func (l *channelLink) processHtlcResolution(resolution invoices.HtlcResolution,
|
|||||||
failure := getResolutionFailure(res, htlc.pd.Amount)
|
failure := getResolutionFailure(res, htlc.pd.Amount)
|
||||||
|
|
||||||
l.sendHTLCError(
|
l.sendHTLCError(
|
||||||
htlc.pd.HtlcIndex, failure, htlc.obfuscator,
|
htlc.pd.HtlcIndex, failure,
|
||||||
htlc.pd.SourceRef,
|
htlc.obfuscator, htlc.pd.SourceRef,
|
||||||
)
|
)
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
@ -1236,21 +1236,25 @@ func (l *channelLink) processHtlcResolution(resolution invoices.HtlcResolution,
|
|||||||
// getResolutionFailure returns the wire message that a htlc resolution should
|
// getResolutionFailure returns the wire message that a htlc resolution should
|
||||||
// be failed with.
|
// be failed with.
|
||||||
func getResolutionFailure(resolution *invoices.HtlcFailResolution,
|
func getResolutionFailure(resolution *invoices.HtlcFailResolution,
|
||||||
amount lnwire.MilliSatoshi) lnwire.FailureMessage {
|
amount lnwire.MilliSatoshi) *LinkError {
|
||||||
|
|
||||||
// If the resolution has been resolved as part of a MPP timeout,
|
// If the resolution has been resolved as part of a MPP timeout,
|
||||||
// we need to fail the htlc with lnwire.FailMppTimeout.
|
// we need to fail the htlc with lnwire.FailMppTimeout.
|
||||||
if resolution.Outcome == invoices.ResultMppTimeout {
|
if resolution.Outcome == invoices.ResultMppTimeout {
|
||||||
return &lnwire.FailMPPTimeout{}
|
return NewDetailedLinkError(
|
||||||
|
&lnwire.FailMPPTimeout{}, resolution.Outcome,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the htlc is not a MPP timeout, we fail it with
|
// If the htlc is not a MPP timeout, we fail it with
|
||||||
// FailIncorrectDetails. This error is sent for invoice payment
|
// FailIncorrectDetails. This error is sent for invoice payment
|
||||||
// failures such as underpayment/ expiry too soon and hodl invoices
|
// failures such as underpayment/ expiry too soon and hodl invoices
|
||||||
// (which return FailIncorrectDetails to avoid leaking information).
|
// (which return FailIncorrectDetails to avoid leaking information).
|
||||||
return lnwire.NewFailIncorrectDetails(
|
incorrectDetails := lnwire.NewFailIncorrectDetails(
|
||||||
amount, uint32(resolution.AcceptHeight),
|
amount, uint32(resolution.AcceptHeight),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
return NewDetailedLinkError(incorrectDetails, resolution.Outcome)
|
||||||
}
|
}
|
||||||
|
|
||||||
// randomFeeUpdateTimeout returns a random timeout between the bounds defined
|
// randomFeeUpdateTimeout returns a random timeout between the bounds defined
|
||||||
@ -2650,9 +2654,10 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg,
|
|||||||
// for TLV payloads that also supports injecting invalid
|
// for TLV payloads that also supports injecting invalid
|
||||||
// payloads. Deferring this non-trival effort till a
|
// payloads. Deferring this non-trival effort till a
|
||||||
// later date
|
// later date
|
||||||
|
failure := lnwire.NewInvalidOnionPayload(failedType, 0)
|
||||||
l.sendHTLCError(
|
l.sendHTLCError(
|
||||||
pd.HtlcIndex,
|
pd.HtlcIndex,
|
||||||
lnwire.NewInvalidOnionPayload(failedType, 0),
|
NewLinkError(failure),
|
||||||
obfuscator, pd.SourceRef,
|
obfuscator, pd.SourceRef,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -2766,7 +2771,10 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg,
|
|||||||
)
|
)
|
||||||
|
|
||||||
l.sendHTLCError(
|
l.sendHTLCError(
|
||||||
pd.HtlcIndex, failure, obfuscator, pd.SourceRef,
|
pd.HtlcIndex,
|
||||||
|
NewLinkError(failure),
|
||||||
|
obfuscator,
|
||||||
|
pd.SourceRef,
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -2849,7 +2857,9 @@ func (l *channelLink) processExitHop(pd *lnwallet.PaymentDescriptor,
|
|||||||
"value: expected %v, got %v", pd.RHash,
|
"value: expected %v, got %v", pd.RHash,
|
||||||
pd.Amount, fwdInfo.AmountToForward)
|
pd.Amount, fwdInfo.AmountToForward)
|
||||||
|
|
||||||
failure := lnwire.NewFinalIncorrectHtlcAmount(pd.Amount)
|
failure := NewLinkError(
|
||||||
|
lnwire.NewFinalIncorrectHtlcAmount(pd.Amount),
|
||||||
|
)
|
||||||
l.sendHTLCError(pd.HtlcIndex, failure, obfuscator, pd.SourceRef)
|
l.sendHTLCError(pd.HtlcIndex, failure, obfuscator, pd.SourceRef)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -2862,7 +2872,9 @@ func (l *channelLink) processExitHop(pd *lnwallet.PaymentDescriptor,
|
|||||||
"time-lock: expected %v, got %v",
|
"time-lock: expected %v, got %v",
|
||||||
pd.RHash[:], pd.Timeout, fwdInfo.OutgoingCTLV)
|
pd.RHash[:], pd.Timeout, fwdInfo.OutgoingCTLV)
|
||||||
|
|
||||||
failure := lnwire.NewFinalIncorrectCltvExpiry(pd.Timeout)
|
failure := NewLinkError(
|
||||||
|
lnwire.NewFinalIncorrectCltvExpiry(pd.Timeout),
|
||||||
|
)
|
||||||
l.sendHTLCError(pd.HtlcIndex, failure, obfuscator, pd.SourceRef)
|
l.sendHTLCError(pd.HtlcIndex, failure, obfuscator, pd.SourceRef)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -2979,10 +2991,10 @@ func (l *channelLink) handleBatchFwdErrs(errChan chan error) {
|
|||||||
|
|
||||||
// sendHTLCError functions cancels HTLC and send cancel message back to the
|
// sendHTLCError functions cancels HTLC and send cancel message back to the
|
||||||
// peer from which HTLC was received.
|
// peer from which HTLC was received.
|
||||||
func (l *channelLink) sendHTLCError(htlcIndex uint64, failure lnwire.FailureMessage,
|
func (l *channelLink) sendHTLCError(htlcIndex uint64, failure *LinkError,
|
||||||
e hop.ErrorEncrypter, sourceRef *channeldb.AddRef) {
|
e hop.ErrorEncrypter, sourceRef *channeldb.AddRef) {
|
||||||
|
|
||||||
reason, err := e.EncryptFirstHop(failure)
|
reason, err := e.EncryptFirstHop(failure.WireMessage())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.log.Errorf("unable to obfuscate error: %v", err)
|
l.log.Errorf("unable to obfuscate error: %v", err)
|
||||||
return
|
return
|
||||||
|
@ -107,8 +107,10 @@ const (
|
|||||||
ResultMppInProgress
|
ResultMppInProgress
|
||||||
)
|
)
|
||||||
|
|
||||||
// String returns a string representation of the result.
|
// FailureString returns a string representation of the result.
|
||||||
func (f FailResolutionResult) String() string {
|
//
|
||||||
|
// Note: it is part of the FailureDetail interface.
|
||||||
|
func (f FailResolutionResult) FailureString() string {
|
||||||
switch f {
|
switch f {
|
||||||
case resultInvalidFailure:
|
case resultInvalidFailure:
|
||||||
return "invalid failure result"
|
return "invalid failure result"
|
||||||
|
Loading…
Reference in New Issue
Block a user