diff --git a/routing/missioncontrol_test.go b/routing/missioncontrol_test.go index fd9596d2..93b37bf5 100644 --- a/routing/missioncontrol_test.go +++ b/routing/missioncontrol_test.go @@ -165,8 +165,8 @@ func TestMissionControl(t *testing.T) { ctx.restartMc() ctx.expectP(1000, 0.4) - // A node level failure should bring probability of every channel back - // to zero. + // A node level failure should bring probability of all known channels + // back to zero. ctx.reportFailure(0, lnwire.NewExpiryTooSoon(lnwire.ChannelUpdate{})) ctx.expectP(1000, 0) @@ -177,8 +177,8 @@ func TestMissionControl(t *testing.T) { len(history.Nodes)) } - if len(history.Pairs) != 2 { - t.Fatalf("expected 2 pairs, but got %v", len(history.Pairs)) + if len(history.Pairs) != 3 { + t.Fatalf("expected 3 pairs, but got %v", len(history.Pairs)) } // Test reporting a success. diff --git a/routing/result_interpretation.go b/routing/result_interpretation.go index d89f959a..696d930c 100644 --- a/routing/result_interpretation.go +++ b/routing/result_interpretation.go @@ -378,10 +378,30 @@ func (i *interpretedResult) processPaymentOutcomeUnknown(route *route.Route) { i.failPairRange(route, 0, n-1) } -// failNode marks the node indicated by idx in the route as failed. This -// function intentionally panics when the self node is failed. +// failNode marks the node indicated by idx in the route as failed. It also +// marks the incoming and outgoing channels of the node as failed. This function +// intentionally panics when the self node is failed. func (i *interpretedResult) failNode(rt *route.Route, idx int) { + // Mark the node as failing. i.nodeFailure = &rt.Hops[idx-1].PubKeyBytes + + // Mark the incoming connection as failed for the node. We intent to + // penalize as much as we can for a node level failure, including future + // outgoing traffic for this connection. The pair as it is returned by + // getPair is directed towards the failed node. Therefore we first + // reverse the pair. We don't want to affect the score of the node + // sending towards the failing node. + incomingChannelIdx := idx - 1 + inPair, _ := getPair(rt, incomingChannelIdx) + i.pairResults[inPair.Reverse()] = failPairResult(0) + + // If not the ultimate node, mark the outgoing connection as failed for + // the node. + if idx < len(rt.Hops) { + outgoingChannelIdx := idx + outPair, _ := getPair(rt, outgoingChannelIdx) + i.pairResults[outPair] = failPairResult(0) + } } // failPairRange marks the node pairs from node fromIdx to node toIdx as failed diff --git a/routing/result_interpretation_test.go b/routing/result_interpretation_test.go index 23ea5d1e..78b6088a 100644 --- a/routing/result_interpretation_test.go +++ b/routing/result_interpretation_test.go @@ -146,6 +146,10 @@ var resultTestCases = []resultTestCase{ expectedResult: &interpretedResult{ nodeFailure: &hops[1], + pairResults: map[DirectedNodePair]pairResult{ + getTestPair(1, 0): failPairResult(0), + getTestPair(1, 2): failPairResult(0), + }, }, }, @@ -160,6 +164,9 @@ var resultTestCases = []resultTestCase{ expectedResult: &interpretedResult{ finalFailureReason: &reasonError, nodeFailure: &hops[1], + pairResults: map[DirectedNodePair]pairResult{ + getTestPair(1, 0): failPairResult(0), + }, }, }, }