mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-01-18 21:35:24 +01:00
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:
parent
568b977a1f
commit
49bafc0207
@ -300,7 +300,7 @@ lifecycle:
|
||||
// We must inspect the error to know whether it was
|
||||
// critical or not, to decide whether we should
|
||||
// continue trying.
|
||||
err := p.handleSwitchErr(
|
||||
_, err := p.handleSwitchErr(
|
||||
attempt, outcome.err,
|
||||
)
|
||||
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
|
||||
// it.
|
||||
sendErr := p.sendAttempt(attempt)
|
||||
_, sendErr := p.sendAttempt(attempt)
|
||||
if sendErr != nil {
|
||||
// TODO(joostjager): Distinguish unexpected internal 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
|
||||
// defer function will use the param to proceed. Notice
|
||||
// that the errToSend could be nil here.
|
||||
errToSend = p.handleSwitchErr(attempt, result.err)
|
||||
_, errToSend = p.handleSwitchErr(attempt, result.err)
|
||||
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
|
||||
// available route.
|
||||
func (p *paymentLifecycle) sendAttempt(
|
||||
attempt *channeldb.HTLCAttempt) error {
|
||||
attempt *channeldb.HTLCAttempt) (*attemptResult, error) {
|
||||
|
||||
log.Tracef("Attempting to send payment %v (pid=%v), "+
|
||||
"using route: %v", p.identifier, attempt.AttemptID,
|
||||
@ -687,8 +687,13 @@ func (p *paymentLifecycle) sendAttempt(
|
||||
&rt, attempt.Hash[:], attempt.SessionKey(),
|
||||
)
|
||||
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)
|
||||
|
||||
// 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 "+
|
||||
"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",
|
||||
p.identifier, attempt.AttemptID, &attempt.Route)
|
||||
|
||||
return nil
|
||||
return &attemptResult{
|
||||
attempt: attempt,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 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
|
||||
// a non-nil reason value.
|
||||
func (p *paymentLifecycle) handleSwitchErr(attempt *channeldb.HTLCAttempt,
|
||||
sendErr error) error {
|
||||
sendErr error) (*attemptResult, error) {
|
||||
|
||||
internalErrorReason := channeldb.FailureReasonError
|
||||
attemptID := attempt.AttemptID
|
||||
@ -776,10 +783,13 @@ func (p *paymentLifecycle) handleSwitchErr(attempt *channeldb.HTLCAttempt,
|
||||
}
|
||||
|
||||
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)
|
||||
return err
|
||||
// Since this error message cannot be decrypted, we will send a
|
||||
// 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
|
||||
@ -789,10 +799,9 @@ func (p *paymentLifecycle) handleSwitchErr(attempt *channeldb.HTLCAttempt,
|
||||
// occurred.
|
||||
rtErr, ok := sendErr.(htlcswitch.ClearTextError)
|
||||
if !ok {
|
||||
_, err := p.failPaymentAndAttempt(
|
||||
return p.failPaymentAndAttempt(
|
||||
attemptID, &internalErrorReason, sendErr,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
// 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,
|
||||
)
|
||||
if err != nil {
|
||||
_, err := p.failPaymentAndAttempt(
|
||||
return p.failPaymentAndAttempt(
|
||||
attemptID, &internalErrorReason, sendErr,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
log.Tracef("Node=%v reported failure when sending htlc",
|
||||
failureSourceIdx)
|
||||
|
||||
_, err = reportAndFail(&failureSourceIdx, failureMessage)
|
||||
return err
|
||||
return reportAndFail(&failureSourceIdx, failureMessage)
|
||||
}
|
||||
|
||||
// handleFailureMessage tries to apply a channel update present in the failure
|
||||
|
@ -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
|
||||
// a generic NO_ROUTE error.
|
||||
var failureReason *channeldb.FailureReason
|
||||
err = p.handleSwitchErr(attempt, shardError)
|
||||
_, err = p.handleSwitchErr(attempt, shardError)
|
||||
|
||||
switch {
|
||||
// If a non-terminal error is returned and `skipTempErr` is false, then
|
||||
|
Loading…
Reference in New Issue
Block a user