From 334b6a3bfe958f01bfad4e430b74b53d874c9a15 Mon Sep 17 00:00:00 2001 From: Joost Jager Date: Wed, 26 Jun 2019 11:34:25 +0200 Subject: [PATCH] routing: move unreadable failure handling into mission control --- routing/missioncontrol.go | 37 ++++++++++++++++++++++------------ routing/missioncontrol_test.go | 2 +- routing/mock_test.go | 2 +- routing/router.go | 26 +++++++++++------------- 4 files changed, 38 insertions(+), 29 deletions(-) diff --git a/routing/missioncontrol.go b/routing/missioncontrol.go index f3a79e0d..c4f0157e 100644 --- a/routing/missioncontrol.go +++ b/routing/missioncontrol.go @@ -390,29 +390,40 @@ func (m *MissionControl) GetHistorySnapshot() *MissionControlSnapshot { } // ReportPaymentFail reports a failed payment to mission control as input for -// future probability estimates. It returns a bool indicating whether this error -// is a final error and no further payment attempts need to be made. +// future probability estimates. The failureSourceIdx argument indicates the +// failure source. If it is nil, the failure source is unknown. This function +// returns a bool indicating whether this error is a final error. If it is +// final, a failure reason is returned and no further payment attempts need to +// be made. func (m *MissionControl) ReportPaymentFail(rt *route.Route, - failureSourceIdx int, failure lnwire.FailureMessage) (bool, + failureSourceIdx *int, failure lnwire.FailureMessage) (bool, channeldb.FailureReason) { - var ( - failureVertex route.Vertex - ) + var failureSourceIdxInt int + if failureSourceIdx == nil { + // If the failure message could not be decrypted, attribute the + // failure to our own outgoing channel. + // + // TODO(joostager): Penalize all channels in the route. + failureSourceIdxInt = 0 + failure = lnwire.NewTemporaryChannelFailure(nil) + } else { + failureSourceIdxInt = *failureSourceIdx + } - // For any non-self failure, look up the source pub key in the hops - // slice. Otherwise return the self node pubkey. - if failureSourceIdx > 0 { - failureVertex = rt.Hops[failureSourceIdx-1].PubKeyBytes + var failureVertex route.Vertex + + if failureSourceIdxInt > 0 { + failureVertex = rt.Hops[failureSourceIdxInt-1].PubKeyBytes } else { failureVertex = rt.SourcePubKey } log.Tracef("Node %x (index %v) reported failure when sending htlc", failureVertex, failureSourceIdx) - // Always determine chan id ourselves, because a channel - // update with id may not be available. - failedEdge, failedAmt := getFailedEdge(rt, failureSourceIdx) + // Always determine chan id ourselves, because a channel update with id + // may not be available. + failedEdge, failedAmt := getFailedEdge(rt, failureSourceIdxInt) switch failure.(type) { diff --git a/routing/missioncontrol_test.go b/routing/missioncontrol_test.go index 5eaf9980..21c835f1 100644 --- a/routing/missioncontrol_test.go +++ b/routing/missioncontrol_test.go @@ -78,7 +78,7 @@ func (ctx *mcTestContext) reportFailure(t time.Time, errorSourceIdx := 1 ctx.mc.ReportPaymentFail( - mcTestRoute, errorSourceIdx, failure, + mcTestRoute, &errorSourceIdx, failure, ) } diff --git a/routing/mock_test.go b/routing/mock_test.go index 23667b5a..eae42f6f 100644 --- a/routing/mock_test.go +++ b/routing/mock_test.go @@ -99,7 +99,7 @@ type mockMissionControl struct { var _ MissionController = (*mockMissionControl)(nil) func (m *mockMissionControl) ReportPaymentFail(rt *route.Route, - failureSourceIdx int, failure lnwire.FailureMessage) (bool, + failureSourceIdx *int, failure lnwire.FailureMessage) (bool, channeldb.FailureReason) { return false, 0 diff --git a/routing/router.go b/routing/router.go index afe7ed0d..8b3143e9 100644 --- a/routing/router.go +++ b/routing/router.go @@ -179,7 +179,7 @@ type MissionController interface { // whether this error is a final error and no further payment attempts // need to be made. ReportPaymentFail(rt *route.Route, - failureSourceIdx int, failure lnwire.FailureMessage) (bool, + failureSourceIdx *int, failure lnwire.FailureMessage) (bool, channeldb.FailureReason) // GetEdgeProbability is expected to return the success probability of a @@ -1893,21 +1893,16 @@ func (r *ChannelRouter) tryApplyChannelUpdate(rt *route.Route, // 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 // return value. -func (r *ChannelRouter) processSendError(rt *route.Route, sendErr error) ( - bool, channeldb.FailureReason) { +func (r *ChannelRouter) processSendError(rt *route.Route, sendErr error) (bool, + channeldb.FailureReason) { - // If the failure message could not be decrypted, attribute the failure - // to our own outgoing channel. - // - // TODO(joostager): Penalize all channels in the route. if sendErr == htlcswitch.ErrUnreadableFailureMessage { - sendErr = &htlcswitch.ForwardingError{ - FailureSourceIdx: 0, - FailureMessage: lnwire.NewTemporaryChannelFailure(nil), - } - } + log.Tracef("Unreadable failure when sending htlc") - // If an internal, non-forwarding error occurred, we can stop trying. + return r.cfg.MissionControl.ReportPaymentFail(rt, nil, nil) + } + // If an internal, non-forwarding error occurred, we can stop + // trying. fErr, ok := sendErr.(*htlcswitch.ForwardingError) if !ok { return true, channeldb.FailureReasonError @@ -1927,8 +1922,11 @@ func (r *ChannelRouter) processSendError(rt *route.Route, sendErr error) ( } } + log.Tracef("Node=%v reported failure when sending htlc", + failureSourceIdx) + return r.cfg.MissionControl.ReportPaymentFail( - rt, failureSourceIdx, failureMessage, + rt, &failureSourceIdx, failureMessage, ) }