routing: exit on unexpected RequestRoute error
We whitelist a set of "expected" errors that can be returned from RequestRoute, by converting them into a new type noRouteError. For any other error returned by RequestRoute, we'll now exit immediately.
This commit is contained in:
parent
fee5fd0093
commit
5e72a4b77c
@ -141,7 +141,7 @@ func (m *mockPaymentSession) RequestRoute(_, _ lnwire.MilliSatoshi,
|
||||
_, height uint32) (*route.Route, error) {
|
||||
|
||||
if len(m.routes) == 0 {
|
||||
return nil, fmt.Errorf("no routes")
|
||||
return nil, errNoPathFound
|
||||
}
|
||||
|
||||
r := m.routes[0]
|
||||
|
@ -58,24 +58,6 @@ var (
|
||||
// DefaultAprioriHopProbability is the default a priori probability for
|
||||
// a hop.
|
||||
DefaultAprioriHopProbability = float64(0.6)
|
||||
|
||||
// errNoTlvPayload is returned when the destination hop does not support
|
||||
// a tlv payload.
|
||||
errNoTlvPayload = errors.New("destination hop doesn't " +
|
||||
"understand new TLV payloads")
|
||||
|
||||
// errNoPaymentAddr is returned when the destination hop does not
|
||||
// support payment addresses.
|
||||
errNoPaymentAddr = errors.New("destination hop doesn't " +
|
||||
"understand payment addresses")
|
||||
|
||||
// errNoPathFound is returned when a path to the target destination does
|
||||
// not exist in the graph.
|
||||
errNoPathFound = errors.New("unable to find a path to destination")
|
||||
|
||||
// errInsufficientLocalBalance is returned when none of the local
|
||||
// channels have enough balance for the payment.
|
||||
errInsufficientBalance = errors.New("insufficient local balance")
|
||||
)
|
||||
|
||||
// edgePolicyWithSource is a helper struct to keep track of the source node
|
||||
|
@ -210,11 +210,16 @@ func (p *paymentLifecycle) resumePayment() ([32]byte, *route.Route, error) {
|
||||
log.Warnf("Failed to find route for payment %x: %v",
|
||||
p.paymentHash, err)
|
||||
|
||||
routeErr, ok := err.(noRouteError)
|
||||
if !ok {
|
||||
return [32]byte{}, nil, err
|
||||
}
|
||||
|
||||
// There is no route to try, and we have no active
|
||||
// shards. This means that there is no way for us to
|
||||
// send the payment, so mark it failed with no route.
|
||||
if state.numShardsInFlight == 0 {
|
||||
failureCode := errorToPaymentFailure(err)
|
||||
failureCode := routeErr.FailureReason()
|
||||
log.Debugf("Marking payment %v permanently "+
|
||||
"failed with no route: %v",
|
||||
p.paymentHash, failureCode)
|
||||
@ -570,25 +575,6 @@ func (p *shardHandler) collectResult(attempt *channeldb.HTLCAttemptInfo) (
|
||||
}, nil
|
||||
}
|
||||
|
||||
// errorToPaymentFailure takes a path finding error and converts it into a
|
||||
// payment-level failure.
|
||||
func errorToPaymentFailure(err error) channeldb.FailureReason {
|
||||
switch err {
|
||||
case
|
||||
errNoTlvPayload,
|
||||
errNoPaymentAddr,
|
||||
errNoPathFound,
|
||||
errEmptyPaySession:
|
||||
|
||||
return channeldb.FailureReasonNoRoute
|
||||
|
||||
case errInsufficientBalance:
|
||||
return channeldb.FailureReasonInsufficientBalance
|
||||
}
|
||||
|
||||
return channeldb.FailureReasonError
|
||||
}
|
||||
|
||||
// createNewPaymentAttempt creates a new payment attempt from the given route.
|
||||
func (p *shardHandler) createNewPaymentAttempt(rt *route.Route) (
|
||||
lnwire.ShortChannelID, *lnwire.UpdateAddHTLC,
|
||||
|
@ -1,8 +1,6 @@
|
||||
package routing
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
"github.com/lightningnetwork/lnd/routing/route"
|
||||
@ -12,12 +10,73 @@ import (
|
||||
// to prevent an HTLC being failed if some blocks are mined while it's in-flight.
|
||||
const BlockPadding uint16 = 3
|
||||
|
||||
var (
|
||||
// noRouteError encodes a non-critical error encountered during path finding.
|
||||
type noRouteError uint8
|
||||
|
||||
const (
|
||||
// errNoTlvPayload is returned when the destination hop does not support
|
||||
// a tlv payload.
|
||||
errNoTlvPayload noRouteError = iota
|
||||
|
||||
// errNoPaymentAddr is returned when the destination hop does not
|
||||
// support payment addresses.
|
||||
errNoPaymentAddr
|
||||
|
||||
// errNoPathFound is returned when a path to the target destination does
|
||||
// not exist in the graph.
|
||||
errNoPathFound
|
||||
|
||||
// errInsufficientLocalBalance is returned when none of the local
|
||||
// channels have enough balance for the payment.
|
||||
errInsufficientBalance
|
||||
|
||||
// errEmptyPaySession is returned when the empty payment session is
|
||||
// queried for a route.
|
||||
errEmptyPaySession = errors.New("empty payment session")
|
||||
errEmptyPaySession
|
||||
)
|
||||
|
||||
// Error returns the string representation of the noRouteError
|
||||
func (e noRouteError) Error() string {
|
||||
switch e {
|
||||
case errNoTlvPayload:
|
||||
return "destination hop doesn't understand new TLV payloads"
|
||||
|
||||
case errNoPaymentAddr:
|
||||
return "destination hop doesn't understand payment addresses"
|
||||
|
||||
case errNoPathFound:
|
||||
return "unable to find a path to destination"
|
||||
|
||||
case errEmptyPaySession:
|
||||
return "empty payment session"
|
||||
|
||||
case errInsufficientBalance:
|
||||
return "insufficient local balance"
|
||||
|
||||
default:
|
||||
return "unknown no-route error"
|
||||
}
|
||||
}
|
||||
|
||||
// FailureReason converts a path finding error into a payment-level failure.
|
||||
func (e noRouteError) FailureReason() channeldb.FailureReason {
|
||||
switch e {
|
||||
case
|
||||
errNoTlvPayload,
|
||||
errNoPaymentAddr,
|
||||
errNoPathFound,
|
||||
errEmptyPaySession:
|
||||
|
||||
return channeldb.FailureReasonNoRoute
|
||||
|
||||
case errInsufficientBalance:
|
||||
return channeldb.FailureReasonInsufficientBalance
|
||||
|
||||
default:
|
||||
return channeldb.FailureReasonError
|
||||
}
|
||||
}
|
||||
|
||||
// PaymentSession is used during SendPayment attempts to provide routes to
|
||||
// attempt. It also defines methods to give the PaymentSession additional
|
||||
// information learned during the previous attempts.
|
||||
@ -29,6 +88,9 @@ type PaymentSession interface {
|
||||
// argument should be set to instruct the payment session about the
|
||||
// number of in flight HTLCS for the payment, such that it can choose
|
||||
// splitting strategy accordingly.
|
||||
//
|
||||
// A noRouteError is returned if a non-critical error is encountered
|
||||
// during path finding.
|
||||
RequestRoute(maxAmt, feeLimit lnwire.MilliSatoshi,
|
||||
activeShards, height uint32) (*route.Route, error)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user