routing+routerrpc+channeldb: return route on invalid payment details

This commit is contained in:
Joost Jager committed 2019-07-04 09:27:16 +02:00
1 parent 7bc56f5a7b
commit 5ce04091d8
4 files changed
+55 -15

No files matched your search

+22 -5
View File
@@ -246,9 +246,12 @@ func (p *PaymentControl) Success(paymentHash lntypes.Hash,
// its next call for this payment hash, allowing the switch to make a // its next call for this payment hash, allowing the switch to make a
// subsequent payment. // subsequent payment.
func (p *PaymentControl) Fail(paymentHash lntypes.Hash, func (p *PaymentControl) Fail(paymentHash lntypes.Hash,
reason FailureReason) error { reason FailureReason) (*route.Route, error) {
var updateErr error var (
updateErr error
route *route.Route
)
err := p.db.Batch(func(tx *bbolt.Tx) error { err := p.db.Batch(func(tx *bbolt.Tx) error {
// Reset the update error, to avoid carrying over an error // Reset the update error, to avoid carrying over an error
// from a previous execution of the batched db transaction. // from a previous execution of the batched db transaction.
@@ -270,13 +273,27 @@ func (p *PaymentControl) Fail(paymentHash lntypes.Hash,
// Put the failure reason in the bucket for record keeping. // Put the failure reason in the bucket for record keeping.
v := []byte{byte(reason)} v := []byte{byte(reason)}
return bucket.Put(paymentFailInfoKey, v) err = bucket.Put(paymentFailInfoKey, v)
if err != nil {
return err
}
// Retrieve attempt info for the notification, if available.
attempt, err := fetchPaymentAttempt(bucket)
if err != nil && err != errNoAttemptInfo {
return err
}
if err != errNoAttemptInfo {
route = &attempt.Route
}
return nil
}) })
if err != nil { if err != nil {
return err return nil, err
} }
return updateErr return route, updateErr
} }
// FetchPayment returns information about a payment from the database. // FetchPayment returns information about a payment from the database.
+3 -3
View File
@@ -94,7 +94,7 @@ func TestPaymentControlSwitchFail(t *testing.T) {
// Fail the payment, which should moved it to Failed. // Fail the payment, which should moved it to Failed.
failReason := FailureReasonNoRoute failReason := FailureReasonNoRoute
err = pControl.Fail(info.PaymentHash, failReason) _, err = pControl.Fail(info.PaymentHash, failReason)
if err != nil { if err != nil {
t.Fatalf("unable to fail payment hash: %v", err) t.Fatalf("unable to fail payment hash: %v", err)
} }
@@ -270,7 +270,7 @@ func TestPaymentControlFailsWithoutInFlight(t *testing.T) {
} }
// Calling Fail should return an error. // Calling Fail should return an error.
err = pControl.Fail(info.PaymentHash, FailureReasonNoRoute) _, err = pControl.Fail(info.PaymentHash, FailureReasonNoRoute)
if err != ErrPaymentNotInitiated { if err != ErrPaymentNotInitiated {
t.Fatalf("expected ErrPaymentNotInitiated, got %v", err) t.Fatalf("expected ErrPaymentNotInitiated, got %v", err)
} }
@@ -330,7 +330,7 @@ func TestPaymentControlDeleteNonInFligt(t *testing.T) {
if p.failed { if p.failed {
// Fail the payment, which should moved it to Failed. // Fail the payment, which should moved it to Failed.
failReason := FailureReasonNoRoute failReason := FailureReasonNoRoute
err = pControl.Fail(info.PaymentHash, failReason) _, err = pControl.Fail(info.PaymentHash, failReason)
if err != nil { if err != nil {
t.Fatalf("unable to fail payment hash: %v", err) t.Fatalf("unable to fail payment hash: %v", err)
} }
+9 -2
View File
@@ -499,8 +499,10 @@ func (s *Server) TrackPayment(request *TrackPaymentRequest,
func (s *Server) trackPayment(paymentHash lntypes.Hash, func (s *Server) trackPayment(paymentHash lntypes.Hash,
stream Router_TrackPaymentServer) error { stream Router_TrackPaymentServer) error {
router := s.cfg.RouterBackend
// Subscribe to the outcome of this payment. // Subscribe to the outcome of this payment.
inFlight, resultChan, err := s.cfg.RouterBackend.Tower.SubscribePayment( inFlight, resultChan, err := router.Tower.SubscribePayment(
paymentHash, paymentHash,
) )
switch { switch {
@@ -535,7 +537,7 @@ func (s *Server) trackPayment(paymentHash lntypes.Hash,
status.State = PaymentState_SUCCEEDED status.State = PaymentState_SUCCEEDED
status.Preimage = result.Preimage[:] status.Preimage = result.Preimage[:]
status.Route = s.cfg.RouterBackend.MarshallRoute( status.Route = router.MarshallRoute(
result.Route, result.Route,
) )
} else { } else {
@@ -546,6 +548,11 @@ func (s *Server) trackPayment(paymentHash lntypes.Hash,
return err return err
} }
status.State = state status.State = state
if result.Route != nil {
status.Route = router.MarshallRoute(
result.Route,
)
}
} }
// Send event to the client. // Send event to the client.
+21 -5
View File
@@ -132,11 +132,21 @@ func createSuccessResult(rt *route.Route,
} }
// createFailResult creates a failed result to send to subscribers. // createFailResult creates a failed result to send to subscribers.
func createFailedResult(reason channeldb.FailureReason) *PaymentResult { func createFailedResult(rt *route.Route,
return &PaymentResult{ reason channeldb.FailureReason) *PaymentResult {
result := &PaymentResult{
Success: false, Success: false,
FailureReason: reason, FailureReason: reason,
} }
// In case of incorrect payment details, set the route. This can be used
// for probing and to extract a fee estimate from the route.
if reason == channeldb.FailureReasonIncorrectPaymentDetails {
result.Route = rt
}
return result
} }
// Fail transitions a payment into the Failed state, and records the reason the // Fail transitions a payment into the Failed state, and records the reason the
@@ -146,14 +156,14 @@ func createFailedResult(reason channeldb.FailureReason) *PaymentResult {
func (p *controlTower) Fail(paymentHash lntypes.Hash, func (p *controlTower) Fail(paymentHash lntypes.Hash,
reason channeldb.FailureReason) error { reason channeldb.FailureReason) error {
err := p.db.Fail(paymentHash, reason) route, err := p.db.Fail(paymentHash, reason)
if err != nil { if err != nil {
return err return err
} }
// Notify subscribers of fail event. // Notify subscribers of fail event.
p.notifyFinalEvent( p.notifyFinalEvent(
paymentHash, createFailedResult(reason), paymentHash, createFailedResult(route, reason),
) )
return nil return nil
@@ -211,7 +221,13 @@ func (p *controlTower) SubscribePayment(paymentHash lntypes.Hash) (
// subscriber, because we can send the result on the channel // subscriber, because we can send the result on the channel
// immediately. // immediately.
case channeldb.StatusFailed: case channeldb.StatusFailed:
event = *createFailedResult(*payment.Failure) var route *route.Route
if payment.Attempt != nil {
route = &payment.Attempt.Route
}
event = *createFailedResult(
route, *payment.Failure,
)
default: default:
return false, nil, errors.New("unknown payment status") return false, nil, errors.New("unknown payment status")