routing: move unreadable failure handling into mission control

This commit is contained in:
Joost Jager 2019-06-26 11:34:25 +02:00
parent 934ea8e78d
commit 334b6a3bfe
No known key found for this signature in database
GPG Key ID: A61B9D4C393C59C7
4 changed files with 38 additions and 29 deletions

@ -390,29 +390,40 @@ func (m *MissionControl) GetHistorySnapshot() *MissionControlSnapshot {
} }
// ReportPaymentFail reports a failed payment to mission control as input for // ReportPaymentFail reports a failed payment to mission control as input for
// future probability estimates. It returns a bool indicating whether this error // future probability estimates. The failureSourceIdx argument indicates the
// is a final error and no further payment attempts need to be made. // 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, func (m *MissionControl) ReportPaymentFail(rt *route.Route,
failureSourceIdx int, failure lnwire.FailureMessage) (bool, failureSourceIdx *int, failure lnwire.FailureMessage) (bool,
channeldb.FailureReason) { channeldb.FailureReason) {
var ( var failureSourceIdxInt int
failureVertex route.Vertex 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 var failureVertex route.Vertex
// slice. Otherwise return the self node pubkey.
if failureSourceIdx > 0 { if failureSourceIdxInt > 0 {
failureVertex = rt.Hops[failureSourceIdx-1].PubKeyBytes failureVertex = rt.Hops[failureSourceIdxInt-1].PubKeyBytes
} else { } else {
failureVertex = rt.SourcePubKey failureVertex = rt.SourcePubKey
} }
log.Tracef("Node %x (index %v) reported failure when sending htlc", log.Tracef("Node %x (index %v) reported failure when sending htlc",
failureVertex, failureSourceIdx) failureVertex, failureSourceIdx)
// Always determine chan id ourselves, because a channel // Always determine chan id ourselves, because a channel update with id
// update with id may not be available. // may not be available.
failedEdge, failedAmt := getFailedEdge(rt, failureSourceIdx) failedEdge, failedAmt := getFailedEdge(rt, failureSourceIdxInt)
switch failure.(type) { switch failure.(type) {

@ -78,7 +78,7 @@ func (ctx *mcTestContext) reportFailure(t time.Time,
errorSourceIdx := 1 errorSourceIdx := 1
ctx.mc.ReportPaymentFail( ctx.mc.ReportPaymentFail(
mcTestRoute, errorSourceIdx, failure, mcTestRoute, &errorSourceIdx, failure,
) )
} }

@ -99,7 +99,7 @@ type mockMissionControl struct {
var _ MissionController = (*mockMissionControl)(nil) var _ MissionController = (*mockMissionControl)(nil)
func (m *mockMissionControl) ReportPaymentFail(rt *route.Route, func (m *mockMissionControl) ReportPaymentFail(rt *route.Route,
failureSourceIdx int, failure lnwire.FailureMessage) (bool, failureSourceIdx *int, failure lnwire.FailureMessage) (bool,
channeldb.FailureReason) { channeldb.FailureReason) {
return false, 0 return false, 0

@ -179,7 +179,7 @@ type MissionController interface {
// whether this error is a final error and no further payment attempts // whether this error is a final error and no further payment attempts
// need to be made. // need to be made.
ReportPaymentFail(rt *route.Route, ReportPaymentFail(rt *route.Route,
failureSourceIdx int, failure lnwire.FailureMessage) (bool, failureSourceIdx *int, failure lnwire.FailureMessage) (bool,
channeldb.FailureReason) channeldb.FailureReason)
// GetEdgeProbability is expected to return the success probability of a // 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 // 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(rt *route.Route, sendErr error) ( func (r *ChannelRouter) processSendError(rt *route.Route, sendErr error) (bool,
bool, channeldb.FailureReason) { 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 { if sendErr == htlcswitch.ErrUnreadableFailureMessage {
sendErr = &htlcswitch.ForwardingError{ log.Tracef("Unreadable failure when sending htlc")
FailureSourceIdx: 0,
FailureMessage: lnwire.NewTemporaryChannelFailure(nil),
}
}
// 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) fErr, ok := sendErr.(*htlcswitch.ForwardingError)
if !ok { if !ok {
return true, channeldb.FailureReasonError 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( return r.cfg.MissionControl.ReportPaymentFail(
rt, failureSourceIdx, failureMessage, rt, &failureSourceIdx, failureMessage,
) )
} }