routing: penalize node-level failures harder

Previously we only penalized the outgoing connections of a failing node.
This turned out not to be sufficient, because the next route sometimes
went into the same failing node again to try a different outgoing
connection that wasn't yet known to mission control and therefore not
penalized before.
This commit is contained in:
Joost Jager 2020-01-21 09:02:25 +01:00
parent ad0a89b844
commit ef28d2aaed
No known key found for this signature in database
GPG Key ID: A61B9D4C393C59C7
4 changed files with 26 additions and 15 deletions

@ -333,18 +333,18 @@ func (m *MissionControl) setLastPairResult(fromNode, toNode route.Vertex,
nodePairs[toNode] = current nodePairs[toNode] = current
} }
// setAllFail stores a fail result for all known connection of the given node. // setAllFail stores a fail result for all known connections to and from the
func (m *MissionControl) setAllFail(fromNode route.Vertex, // given node.
func (m *MissionControl) setAllFail(node route.Vertex,
timestamp time.Time) { timestamp time.Time) {
nodePairs, ok := m.lastPairResult[fromNode] for fromNode, nodePairs := range m.lastPairResult {
if !ok { for toNode := range nodePairs {
return if fromNode == node || toNode == node {
} nodePairs[toNode] = TimedPairResult{
FailTime: timestamp,
for connection := range nodePairs { }
nodePairs[connection] = TimedPairResult{ }
FailTime: timestamp,
} }
} }
} }

@ -186,8 +186,8 @@ func TestMissionControl(t *testing.T) {
// Check whether history snapshot looks sane. // Check whether history snapshot looks sane.
history := ctx.mc.GetHistorySnapshot() history := ctx.mc.GetHistorySnapshot()
if len(history.Pairs) != 3 { if len(history.Pairs) != 4 {
t.Fatalf("expected 3 pairs, but got %v", len(history.Pairs)) t.Fatalf("expected 4 pairs, but got %v", len(history.Pairs))
} }
// Test reporting a success. // Test reporting a success.

@ -424,11 +424,13 @@ func (i *interpretedResult) failNode(rt *route.Route, idx int) {
// Mark the incoming connection as failed for the node. We intent to // 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 // 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 // outgoing traffic for this connection. The pair as it is returned by
// getPair is directed towards the failed node. Therefore we first // getPair is penalized in the original and the reversed direction. Note
// reverse the pair. We don't want to affect the score of the node // that this will also affect the score of the failing node's peers.
// sending towards the failing node. // This is necessary to prevent future routes from keep going into the
// same node again.
incomingChannelIdx := idx - 1 incomingChannelIdx := idx - 1
inPair, _ := getPair(rt, incomingChannelIdx) inPair, _ := getPair(rt, incomingChannelIdx)
i.pairResults[inPair] = failPairResult(0)
i.pairResults[inPair.Reverse()] = failPairResult(0) i.pairResults[inPair.Reverse()] = failPairResult(0)
// If not the ultimate node, mark the outgoing connection as failed for // If not the ultimate node, mark the outgoing connection as failed for
@ -437,6 +439,7 @@ func (i *interpretedResult) failNode(rt *route.Route, idx int) {
outgoingChannelIdx := idx outgoingChannelIdx := idx
outPair, _ := getPair(rt, outgoingChannelIdx) outPair, _ := getPair(rt, outgoingChannelIdx)
i.pairResults[outPair] = failPairResult(0) i.pairResults[outPair] = failPairResult(0)
i.pairResults[outPair.Reverse()] = failPairResult(0)
} }
} }

@ -165,6 +165,8 @@ var resultTestCases = []resultTestCase{
pairResults: map[DirectedNodePair]pairResult{ pairResults: map[DirectedNodePair]pairResult{
getTestPair(1, 0): failPairResult(0), getTestPair(1, 0): failPairResult(0),
getTestPair(1, 2): failPairResult(0), getTestPair(1, 2): failPairResult(0),
getTestPair(0, 1): failPairResult(0),
getTestPair(2, 1): failPairResult(0),
}, },
}, },
}, },
@ -182,6 +184,7 @@ var resultTestCases = []resultTestCase{
nodeFailure: &hops[1], nodeFailure: &hops[1],
pairResults: map[DirectedNodePair]pairResult{ pairResults: map[DirectedNodePair]pairResult{
getTestPair(1, 0): failPairResult(0), getTestPair(1, 0): failPairResult(0),
getTestPair(0, 1): failPairResult(0),
}, },
}, },
}, },
@ -233,6 +236,7 @@ var resultTestCases = []resultTestCase{
amt: 97, amt: 97,
}, },
getTestPair(4, 3): {}, getTestPair(4, 3): {},
getTestPair(3, 4): {},
}, },
finalFailureReason: &reasonError, finalFailureReason: &reasonError,
nodeFailure: &hops[4], nodeFailure: &hops[4],
@ -257,6 +261,7 @@ var resultTestCases = []resultTestCase{
amt: 99, amt: 99,
}, },
getTestPair(3, 2): {}, getTestPair(3, 2): {},
getTestPair(2, 3): {},
}, },
finalFailureReason: &reasonError, finalFailureReason: &reasonError,
nodeFailure: &hops[3], nodeFailure: &hops[3],
@ -284,6 +289,8 @@ var resultTestCases = []resultTestCase{
}, },
getTestPair(3, 2): {}, getTestPair(3, 2): {},
getTestPair(3, 4): {}, getTestPair(3, 4): {},
getTestPair(2, 3): {},
getTestPair(4, 3): {},
}, },
nodeFailure: &hops[3], nodeFailure: &hops[3],
}, },
@ -301,6 +308,7 @@ var resultTestCases = []resultTestCase{
expectedResult: &interpretedResult{ expectedResult: &interpretedResult{
pairResults: map[DirectedNodePair]pairResult{ pairResults: map[DirectedNodePair]pairResult{
getTestPair(1, 0): {}, getTestPair(1, 0): {},
getTestPair(0, 1): {},
}, },
finalFailureReason: &reasonError, finalFailureReason: &reasonError,
nodeFailure: &hops[1], nodeFailure: &hops[1],