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 committed 2019-05-16 23:56:12 +02:00
1 parent be129eb7c7
commit ec087a9f73
7 files changed
+251 -68

No files matched your search

+40 -7
View File
@@ -1,28 +1,61 @@
package routing
import (
"crypto/sha256"
"github.com/lightningnetwork/lnd/htlcswitch"
"github.com/lightningnetwork/lnd/lnwire"
)
type mockPaymentAttemptDispatcher struct {
onPayment func(firstHop lnwire.ShortChannelID) ([32]byte, error)
results map[uint64]*htlcswitch.PaymentResult
}
var _ PaymentAttemptDispatcher = (*mockPaymentAttemptDispatcher)(nil)
func (m *mockPaymentAttemptDispatcher) SendHTLC(firstHop lnwire.ShortChannelID,
_ uint64,
pid uint64,
_ *lnwire.UpdateAddHTLC,
_ htlcswitch.ErrorDecrypter) ([sha256.Size]byte, error) {
_ htlcswitch.ErrorDecrypter) error {
if m.onPayment != nil {
return m.onPayment(firstHop)
if m.onPayment == nil {
return nil
}
return [sha256.Size]byte{}, nil
if m.results == nil {
m.results = make(map[uint64]*htlcswitch.PaymentResult)
}
var result *htlcswitch.PaymentResult
preimage, err := m.onPayment(firstHop)
if err != nil {
fwdErr, ok := err.(*htlcswitch.ForwardingError)
if !ok {
return err
}
result = &htlcswitch.PaymentResult{
Error: fwdErr,
}
} else {
result = &htlcswitch.PaymentResult{Preimage: preimage}
}
m.results[pid] = result
return nil
}
func (m *mockPaymentAttemptDispatcher) GetPaymentResult(paymentID uint64) (
<-chan *htlcswitch.PaymentResult, error) {
c := make(chan *htlcswitch.PaymentResult, 1)
res, ok := m.results[paymentID]
if !ok {
return nil, htlcswitch.ErrPaymentIDNotFound
}
c <- res
return c, nil
}
func (m *mockPaymentAttemptDispatcher) setPaymentResult(
+47 -9
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