htlcswitch+router: define PaymentResult, GetPaymentResult

This lets us distinguish an critical error from a actual payment result
(success or failure). This is important since we know that we can only
attempt another payment when a final result from the previous payment
attempt is received.
This commit is contained in:
Johan T. Halseth
2019-05-16 15:27:29 +02:00
parent be129eb7c7
commit ec087a9f73
7 changed files with 251 additions and 68 deletions

View File

@@ -2,7 +2,6 @@ package routing
import (
"bytes"
"crypto/sha256"
"fmt"
"runtime"
"sync"
@@ -136,7 +135,15 @@ type PaymentAttemptDispatcher interface {
SendHTLC(firstHop lnwire.ShortChannelID,
paymentID uint64,
htlcAdd *lnwire.UpdateAddHTLC,
deobfuscator htlcswitch.ErrorDecrypter) ([sha256.Size]byte, error)
deobfuscator htlcswitch.ErrorDecrypter) error
// GetPaymentResult returns the the result of the payment attempt with
// the given paymentID. The method returns a channel where the payment
// result will be sent when available, or an error is encountered. If
// the paymentID is unknown, htlcswitch.ErrPaymentIDNotFound will be
// returned.
GetPaymentResult(paymentID uint64) (
<-chan *htlcswitch.PaymentResult, error)
}
// FeeSchema is the set fee configuration for a Lightning Node on the network.
@@ -1711,19 +1718,50 @@ func (r *ChannelRouter) sendPaymentAttempt(paySession *paymentSession,
return [32]byte{}, true, err
}
preimage, err := r.cfg.Payer.SendHTLC(
err = r.cfg.Payer.SendHTLC(
firstHop, paymentID, htlcAdd, errorDecryptor,
)
if err == nil {
return preimage, true, nil
if err != nil {
log.Errorf("Failed sending attempt %d for payment %x to "+
"switch: %v", paymentID, paymentHash, err)
// We must inspect the error to know whether it was critical or
// not, to decide whether we should continue trying.
finalOutcome := r.processSendError(
paySession, route, err,
)
return [32]byte{}, finalOutcome, err
}
log.Errorf("Attempt to send payment %x failed: %v",
paymentHash, err)
// Now ask the switch to return the result of the payment when
// available.
resultChan, err := r.cfg.Payer.GetPaymentResult(paymentID)
if err != nil {
log.Errorf("Failed getting result for paymentID %d "+
"from switch: %v", paymentID, err)
return [32]byte{}, true, err
}
finalOutcome := r.processSendError(paySession, route, err)
var result *htlcswitch.PaymentResult
select {
case result = <-resultChan:
case <-r.quit:
return [32]byte{}, true, ErrRouterShuttingDown
}
return [32]byte{}, finalOutcome, err
if result.Error != nil {
log.Errorf("Attempt to send payment %x failed: %v",
paymentHash, result.Error)
finalOutcome := r.processSendError(
paySession, route, result.Error,
)
return [32]byte{}, finalOutcome, result.Error
}
return result.Preimage, true, nil
}
// processSendError analyzes the error for the payment attempt received from the