routing: handle switch error when sendAttempt fails
This commit starts handling switch error inside `sendAttempt` when an error is returned from sending the HTLC. To make sure the updated `HTLCAttempt` is always returned to the callsite, `handleSwitchErr` now also returns a `attemptResult`.
This commit is contained in:
2 files changed
+25
-18
No files matched your search
@@ -300,7 +300,7 @@ lifecycle:
|
|||||||
// We must inspect the error to know whether it was
|
// We must inspect the error to know whether it was
|
||||||
// critical or not, to decide whether we should
|
// critical or not, to decide whether we should
|
||||||
// continue trying.
|
// continue trying.
|
||||||
err := p.handleSwitchErr(
|
_, err := p.handleSwitchErr(
|
||||||
attempt, outcome.err,
|
attempt, outcome.err,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -392,7 +392,7 @@ func (p *paymentLifecycle) launchShard(rt *route.Route,
|
|||||||
|
|
||||||
// Now that the attempt is created and checkpointed to the DB, we send
|
// Now that the attempt is created and checkpointed to the DB, we send
|
||||||
// it.
|
// it.
|
||||||
sendErr := p.sendAttempt(attempt)
|
_, sendErr := p.sendAttempt(attempt)
|
||||||
if sendErr != nil {
|
if sendErr != nil {
|
||||||
// TODO(joostjager): Distinguish unexpected internal errors
|
// TODO(joostjager): Distinguish unexpected internal errors
|
||||||
// from real send errors.
|
// from real send errors.
|
||||||
@@ -460,7 +460,7 @@ func (p *paymentLifecycle) collectResultAsync(attempt *channeldb.HTLCAttempt) {
|
|||||||
// Overwrite the param errToSend and return so that the
|
// Overwrite the param errToSend and return so that the
|
||||||
// defer function will use the param to proceed. Notice
|
// defer function will use the param to proceed. Notice
|
||||||
// that the errToSend could be nil here.
|
// that the errToSend could be nil here.
|
||||||
errToSend = p.handleSwitchErr(attempt, result.err)
|
_, errToSend = p.handleSwitchErr(attempt, result.err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@@ -657,7 +657,7 @@ func (p *paymentLifecycle) createNewPaymentAttempt(rt *route.Route,
|
|||||||
// the payment. If this attempt fails, then we'll continue on to the next
|
// the payment. If this attempt fails, then we'll continue on to the next
|
||||||
// available route.
|
// available route.
|
||||||
func (p *paymentLifecycle) sendAttempt(
|
func (p *paymentLifecycle) sendAttempt(
|
||||||
attempt *channeldb.HTLCAttempt) error {
|
attempt *channeldb.HTLCAttempt) (*attemptResult, error) {
|
||||||
|
|
||||||
log.Tracef("Attempting to send payment %v (pid=%v), "+
|
log.Tracef("Attempting to send payment %v (pid=%v), "+
|
||||||
"using route: %v", p.identifier, attempt.AttemptID,
|
"using route: %v", p.identifier, attempt.AttemptID,
|
||||||
@@ -687,8 +687,13 @@ func (p *paymentLifecycle) sendAttempt(
|
|||||||
&rt, attempt.Hash[:], attempt.SessionKey(),
|
&rt, attempt.Hash[:], attempt.SessionKey(),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
log.Errorf("Failed to create onion blob: attempt=%d in "+
|
||||||
|
"payment=%v, err:%v", attempt.AttemptID,
|
||||||
|
p.identifier, err)
|
||||||
|
|
||||||
|
return p.failAttempt(attempt.AttemptID, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
copy(htlcAdd.OnionBlob[:], onionBlob)
|
copy(htlcAdd.OnionBlob[:], onionBlob)
|
||||||
|
|
||||||
// Send it to the Switch. When this method returns we assume
|
// Send it to the Switch. When this method returns we assume
|
||||||
@@ -700,13 +705,15 @@ func (p *paymentLifecycle) sendAttempt(
|
|||||||
log.Errorf("Failed sending attempt %d for payment %v to "+
|
log.Errorf("Failed sending attempt %d for payment %v to "+
|
||||||
"switch: %v", attempt.AttemptID, p.identifier, err)
|
"switch: %v", attempt.AttemptID, p.identifier, err)
|
||||||
|
|
||||||
return err
|
return p.handleSwitchErr(attempt, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("Payment %v (pid=%v) successfully sent to switch, route: %v",
|
log.Debugf("Payment %v (pid=%v) successfully sent to switch, route: %v",
|
||||||
p.identifier, attempt.AttemptID, &attempt.Route)
|
p.identifier, attempt.AttemptID, &attempt.Route)
|
||||||
|
|
||||||
return nil
|
return &attemptResult{
|
||||||
|
attempt: attempt,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// failAttemptAndPayment fails both the payment and its attempt via the
|
// failAttemptAndPayment fails both the payment and its attempt via the
|
||||||
@@ -742,7 +749,7 @@ func (p *paymentLifecycle) failPaymentAndAttempt(
|
|||||||
// need to continue with an alternative route. A final outcome is indicated by
|
// need to continue with an alternative route. A final outcome is indicated by
|
||||||
// a non-nil reason value.
|
// a non-nil reason value.
|
||||||
func (p *paymentLifecycle) handleSwitchErr(attempt *channeldb.HTLCAttempt,
|
func (p *paymentLifecycle) handleSwitchErr(attempt *channeldb.HTLCAttempt,
|
||||||
sendErr error) error {
|
sendErr error) (*attemptResult, error) {
|
||||||
|
|
||||||
internalErrorReason := channeldb.FailureReasonError
|
internalErrorReason := channeldb.FailureReasonError
|
||||||
attemptID := attempt.AttemptID
|
attemptID := attempt.AttemptID
|
||||||
@@ -776,10 +783,13 @@ func (p *paymentLifecycle) handleSwitchErr(attempt *channeldb.HTLCAttempt,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if sendErr == htlcswitch.ErrUnreadableFailureMessage {
|
if sendErr == htlcswitch.ErrUnreadableFailureMessage {
|
||||||
log.Tracef("Unreadable failure when sending htlc")
|
log.Warn("Unreadable failure when sending htlc: id=%v, hash=%v",
|
||||||
|
attempt.AttemptID, attempt.Hash)
|
||||||
|
|
||||||
_, err := reportAndFail(nil, nil)
|
// Since this error message cannot be decrypted, we will send a
|
||||||
return err
|
// nil error message to our mission controller and fail the
|
||||||
|
// payment.
|
||||||
|
return reportAndFail(nil, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the error is a ClearTextError, we have received a valid wire
|
// If the error is a ClearTextError, we have received a valid wire
|
||||||
@@ -789,10 +799,9 @@ func (p *paymentLifecycle) handleSwitchErr(attempt *channeldb.HTLCAttempt,
|
|||||||
// occurred.
|
// occurred.
|
||||||
rtErr, ok := sendErr.(htlcswitch.ClearTextError)
|
rtErr, ok := sendErr.(htlcswitch.ClearTextError)
|
||||||
if !ok {
|
if !ok {
|
||||||
_, err := p.failPaymentAndAttempt(
|
return p.failPaymentAndAttempt(
|
||||||
attemptID, &internalErrorReason, sendErr,
|
attemptID, &internalErrorReason, sendErr,
|
||||||
)
|
)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// failureSourceIdx is the index of the node that the failure occurred
|
// failureSourceIdx is the index of the node that the failure occurred
|
||||||
@@ -815,17 +824,15 @@ func (p *paymentLifecycle) handleSwitchErr(attempt *channeldb.HTLCAttempt,
|
|||||||
&attempt.Route, failureSourceIdx, failureMessage,
|
&attempt.Route, failureSourceIdx, failureMessage,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_, err := p.failPaymentAndAttempt(
|
return p.failPaymentAndAttempt(
|
||||||
attemptID, &internalErrorReason, sendErr,
|
attemptID, &internalErrorReason, sendErr,
|
||||||
)
|
)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Tracef("Node=%v reported failure when sending htlc",
|
log.Tracef("Node=%v reported failure when sending htlc",
|
||||||
failureSourceIdx)
|
failureSourceIdx)
|
||||||
|
|
||||||
_, err = reportAndFail(&failureSourceIdx, failureMessage)
|
return reportAndFail(&failureSourceIdx, failureMessage)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleFailureMessage tries to apply a channel update present in the failure
|
// handleFailureMessage tries to apply a channel update present in the failure
|
||||||
|
|||||||
+1
-1
@@ -2558,7 +2558,7 @@ func (r *ChannelRouter) sendToRoute(htlcHash lntypes.Hash, rt *route.Route,
|
|||||||
// the error to check if it maps into a terminal error code, if not use
|
// the error to check if it maps into a terminal error code, if not use
|
||||||
// a generic NO_ROUTE error.
|
// a generic NO_ROUTE error.
|
||||||
var failureReason *channeldb.FailureReason
|
var failureReason *channeldb.FailureReason
|
||||||
err = p.handleSwitchErr(attempt, shardError)
|
_, err = p.handleSwitchErr(attempt, shardError)
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
// If a non-terminal error is returned and `skipTempErr` is false, then
|
// If a non-terminal error is returned and `skipTempErr` is false, then
|
||||||
|
|||||||
Reference in new issue
Block a user