routing: report failures to mission control directly

As there is no more state kept in the payment session, failure reporting
can go straight to mission control.
This commit is contained in:
Joost Jager 2019-06-26 08:52:49 +02:00
parent dc13da5abb
commit 8055bcf2e0
No known key found for this signature in database
GPG Key ID: A61B9D4C393C59C7
3 changed files with 18 additions and 85 deletions

@ -343,7 +343,7 @@ func (p *paymentLifecycle) sendPaymentAttempt(firstHop lnwire.ShortChannelID,
func (p *paymentLifecycle) handleSendError(sendErr error) error { func (p *paymentLifecycle) handleSendError(sendErr error) error {
final, reason := p.router.processSendError( final, reason := p.router.processSendError(
p.paySession, &p.attempt.Route, sendErr, &p.attempt.Route, sendErr,
) )
if !final { if !final {
// Save the forwarding error so it can be returned if // Save the forwarding error so it can be returned if

@ -16,27 +16,6 @@ type PaymentSession interface {
// specified HTLC payment to the target node. // specified HTLC payment to the target node.
RequestRoute(payment *LightningPayment, RequestRoute(payment *LightningPayment,
height uint32, finalCltvDelta uint16) (*route.Route, error) height uint32, finalCltvDelta uint16) (*route.Route, error)
// ReportVertexFailure reports to the PaymentSession that the passsed
// vertex failed to route the previous payment attempt. The
// PaymentSession will use this information to produce a better next
// route.
ReportVertexFailure(v route.Vertex)
// ReportEdgeFailure reports to the PaymentSession that the passed edge
// failed to route the previous payment attempt. A minimum penalization
// amount is included to attenuate the failure. This is set to a
// non-zero value for channel balance failures. The PaymentSession will
// use this information to produce a better next route.
ReportEdgeFailure(failedEdge edge, minPenalizeAmt lnwire.MilliSatoshi)
// ReportEdgePolicyFailure reports to the PaymentSession that we
// received a failure message that relates to a channel policy. For
// these types of failures, the PaymentSession can decide whether to to
// keep the edge included in the next attempted route. The
// PaymentSession will use this information to produce a better next
// route.
ReportEdgePolicyFailure(failedEdge edge)
} }
// paymentSession is used during an HTLC routings session to prune the local // paymentSession is used during an HTLC routings session to prune the local
@ -60,52 +39,6 @@ type paymentSession struct {
pathFinder pathFinder pathFinder pathFinder
} }
// A compile time assertion to ensure paymentSession meets the PaymentSession
// interface.
var _ PaymentSession = (*paymentSession)(nil)
// ReportVertexFailure adds a vertex to the graph prune view after a client
// reports a routing failure localized to the vertex. The time the vertex was
// added is noted, as it'll be pruned from the shared view after a period of
// vertexDecay. However, the vertex will remain pruned for the *local* session.
// This ensures we don't retry this vertex during the payment attempt.
//
// NOTE: Part of the PaymentSession interface.
func (p *paymentSession) ReportVertexFailure(v route.Vertex) {
p.sessionSource.MissionControl.ReportVertexFailure(v)
}
// ReportEdgeFailure adds a channel to the graph prune view. The time the
// channel was added is noted, as it'll be pruned from the global view after a
// period of edgeDecay. However, the edge will remain pruned for the duration
// of the *local* session. This ensures that we don't flap by continually
// retrying an edge after its pruning has expired.
//
// TODO(roasbeef): also add value attempted to send and capacity of channel
//
// NOTE: Part of the PaymentSession interface.
func (p *paymentSession) ReportEdgeFailure(failedEdge edge,
minPenalizeAmt lnwire.MilliSatoshi) {
p.sessionSource.MissionControl.ReportEdgeFailure(
failedEdge, minPenalizeAmt,
)
}
// ReportEdgePolicyFailure handles a failure message that relates to a
// channel policy. For these types of failures, the policy is updated and we
// want to keep it included during path finding. This function does mark the
// edge as 'policy failed once'. The next time it fails, the whole node will be
// pruned. This is to prevent nodes from keeping us busy by continuously sending
// new channel updates.
//
// NOTE: Part of the PaymentSession interface.
//
// TODO(joostjager): Move this logic into global mission control.
func (p *paymentSession) ReportEdgePolicyFailure(failedEdge edge) {
p.sessionSource.MissionControl.ReportEdgePolicyFailure(failedEdge)
}
// RequestRoute returns a route which is likely to be capable for successfully // RequestRoute returns a route which is likely to be capable for successfully
// routing the specified HTLC payment to the target node. Initially the first // routing the specified HTLC payment to the target node. Initially the first
// set of paths returned from this method may encounter routing failure along // set of paths returned from this method may encounter routing failure along

@ -1875,8 +1875,8 @@ func (r *ChannelRouter) tryApplyChannelUpdate(rt *route.Route,
// error type, this error is either the final outcome of the payment or we need // error type, this error is either the final outcome of the payment or we need
// to continue with an alternative route. This is indicated by the boolean // to continue with an alternative route. This is indicated by the boolean
// return value. // return value.
func (r *ChannelRouter) processSendError(paySession PaymentSession, func (r *ChannelRouter) processSendError(rt *route.Route, sendErr error) (
rt *route.Route, sendErr error) (bool, channeldb.FailureReason) { bool, channeldb.FailureReason) {
// If the failure message could not be decrypted, attribute the failure // If the failure message could not be decrypted, attribute the failure
// to our own outgoing channel. // to our own outgoing channel.
@ -1981,7 +1981,7 @@ func (r *ChannelRouter) processSendError(paySession PaymentSession,
// that sent us this error, as it doesn't now what the // that sent us this error, as it doesn't now what the
// correct block height is. // correct block height is.
case *lnwire.FailExpiryTooSoon: case *lnwire.FailExpiryTooSoon:
paySession.ReportVertexFailure(failureVertex) r.cfg.MissionControl.ReportVertexFailure(failureVertex)
return false, 0 return false, 0
// If we hit an instance of onion payload corruption or an invalid // If we hit an instance of onion payload corruption or an invalid
@ -2001,49 +2001,49 @@ func (r *ChannelRouter) processSendError(paySession PaymentSession,
// amount, we'll apply the new minimum amount and retry // amount, we'll apply the new minimum amount and retry
// routing. // routing.
case *lnwire.FailAmountBelowMinimum: case *lnwire.FailAmountBelowMinimum:
paySession.ReportEdgePolicyFailure(failedEdge) r.cfg.MissionControl.ReportEdgePolicyFailure(failedEdge)
return false, 0 return false, 0
// If we get a failure due to a fee, we'll apply the // If we get a failure due to a fee, we'll apply the
// new fee update, and retry our attempt using the // new fee update, and retry our attempt using the
// newly updated fees. // newly updated fees.
case *lnwire.FailFeeInsufficient: case *lnwire.FailFeeInsufficient:
paySession.ReportEdgePolicyFailure(failedEdge) r.cfg.MissionControl.ReportEdgePolicyFailure(failedEdge)
return false, 0 return false, 0
// If we get the failure for an intermediate node that // If we get the failure for an intermediate node that
// disagrees with our time lock values, then we'll // disagrees with our time lock values, then we'll
// apply the new delta value and try it once more. // apply the new delta value and try it once more.
case *lnwire.FailIncorrectCltvExpiry: case *lnwire.FailIncorrectCltvExpiry:
paySession.ReportEdgePolicyFailure(failedEdge) r.cfg.MissionControl.ReportEdgePolicyFailure(failedEdge)
return false, 0 return false, 0
// The outgoing channel that this node was meant to // The outgoing channel that this node was meant to
// forward one is currently disabled, so we'll apply // forward one is currently disabled, so we'll apply
// the update and continue. // the update and continue.
case *lnwire.FailChannelDisabled: case *lnwire.FailChannelDisabled:
paySession.ReportEdgeFailure(failedEdge, 0) r.cfg.MissionControl.ReportEdgeFailure(failedEdge, 0)
return false, 0 return false, 0
// It's likely that the outgoing channel didn't have // It's likely that the outgoing channel didn't have
// sufficient capacity, so we'll prune this edge for // sufficient capacity, so we'll prune this edge for
// now, and continue onwards with our path finding. // now, and continue onwards with our path finding.
case *lnwire.FailTemporaryChannelFailure: case *lnwire.FailTemporaryChannelFailure:
paySession.ReportEdgeFailure(failedEdge, failedAmt) r.cfg.MissionControl.ReportEdgeFailure(failedEdge, failedAmt)
return false, 0 return false, 0
// If the send fail due to a node not having the // If the send fail due to a node not having the
// required features, then we'll note this error and // required features, then we'll note this error and
// continue. // continue.
case *lnwire.FailRequiredNodeFeatureMissing: case *lnwire.FailRequiredNodeFeatureMissing:
paySession.ReportVertexFailure(failureVertex) r.cfg.MissionControl.ReportVertexFailure(failureVertex)
return false, 0 return false, 0
// If the send fail due to a node not having the // If the send fail due to a node not having the
// required features, then we'll note this error and // required features, then we'll note this error and
// continue. // continue.
case *lnwire.FailRequiredChannelFeatureMissing: case *lnwire.FailRequiredChannelFeatureMissing:
paySession.ReportVertexFailure(failureVertex) r.cfg.MissionControl.ReportVertexFailure(failureVertex)
return false, 0 return false, 0
// If the next hop in the route wasn't known or // If the next hop in the route wasn't known or
@ -2054,18 +2054,18 @@ func (r *ChannelRouter) processSendError(paySession PaymentSession,
// returning errors in order to attempt to black list // returning errors in order to attempt to black list
// another node. // another node.
case *lnwire.FailUnknownNextPeer: case *lnwire.FailUnknownNextPeer:
paySession.ReportEdgeFailure(failedEdge, 0) r.cfg.MissionControl.ReportEdgeFailure(failedEdge, 0)
return false, 0 return false, 0
// If the node wasn't able to forward for which ever // If the node wasn't able to forward for which ever
// reason, then we'll note this and continue with the // reason, then we'll note this and continue with the
// routes. // routes.
case *lnwire.FailTemporaryNodeFailure: case *lnwire.FailTemporaryNodeFailure:
paySession.ReportVertexFailure(failureVertex) r.cfg.MissionControl.ReportVertexFailure(failureVertex)
return false, 0 return false, 0
case *lnwire.FailPermanentNodeFailure: case *lnwire.FailPermanentNodeFailure:
paySession.ReportVertexFailure(failureVertex) r.cfg.MissionControl.ReportVertexFailure(failureVertex)
return false, 0 return false, 0
// If we crafted a route that contains a too long time // If we crafted a route that contains a too long time
@ -2078,15 +2078,15 @@ func (r *ChannelRouter) processSendError(paySession PaymentSession,
// that as a hint during future path finding through // that as a hint during future path finding through
// that node. // that node.
case *lnwire.FailExpiryTooFar: case *lnwire.FailExpiryTooFar:
paySession.ReportVertexFailure(failureVertex) r.cfg.MissionControl.ReportVertexFailure(failureVertex)
return false, 0 return false, 0
// If we get a permanent channel or node failure, then // If we get a permanent channel or node failure, then
// we'll prune the channel in both directions and // we'll prune the channel in both directions and
// continue with the rest of the routes. // continue with the rest of the routes.
case *lnwire.FailPermanentChannelFailure: case *lnwire.FailPermanentChannelFailure:
paySession.ReportEdgeFailure(failedEdge, 0) r.cfg.MissionControl.ReportEdgeFailure(failedEdge, 0)
paySession.ReportEdgeFailure(edge{ r.cfg.MissionControl.ReportEdgeFailure(edge{
from: failedEdge.to, from: failedEdge.to,
to: failedEdge.from, to: failedEdge.from,
channel: failedEdge.channel, channel: failedEdge.channel,
@ -2095,7 +2095,7 @@ func (r *ChannelRouter) processSendError(paySession PaymentSession,
// Any other failure or an empty failure will get the node pruned. // Any other failure or an empty failure will get the node pruned.
default: default:
paySession.ReportVertexFailure(failureVertex) r.cfg.MissionControl.ReportVertexFailure(failureVertex)
return false, 0 return false, 0
} }
} }