Skip to content

Commit 5ce7cb9

Browse files
committed
[net] De-duplicate connection eviction logic
1 parent 5a9da37 commit 5ce7cb9

File tree

1 file changed

+20
-29
lines changed

1 file changed

+20
-29
lines changed

src/net.cpp

Lines changed: 20 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -962,6 +962,16 @@ static bool CompareNodeTXTime(const NodeEvictionCandidate &a, const NodeEviction
962962
return a.nTimeConnected > b.nTimeConnected;
963963
}
964964

965+
966+
//! Sort an array by the specified comparator, then erase the last K elements.
967+
template<typename T, typename Comparator>
968+
static void EraseLastKElements(std::vector<T> &elements, Comparator comparator, size_t k)
969+
{
970+
std::sort(elements.begin(), elements.end(), comparator);
971+
size_t eraseSize = std::min(k, elements.size());
972+
elements.erase(elements.end() - eraseSize, elements.end());
973+
}
974+
965975
/** Try to find a connection to evict when the node is full.
966976
* Extreme care must be taken to avoid opening the node to attacker
967977
* triggered network partitioning.
@@ -991,42 +1001,23 @@ bool CConnman::AttemptToEvictConnection()
9911001
}
9921002
}
9931003

994-
if (vEvictionCandidates.empty()) return false;
995-
9961004
// Protect connections with certain characteristics
9971005

9981006
// Deterministically select 4 peers to protect by netgroup.
9991007
// An attacker cannot predict which netgroups will be protected
1000-
std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), CompareNetGroupKeyed);
1001-
vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(4, static_cast<int>(vEvictionCandidates.size())), vEvictionCandidates.end());
1002-
1003-
if (vEvictionCandidates.empty()) return false;
1004-
1008+
EraseLastKElements(vEvictionCandidates, CompareNetGroupKeyed, 4);
10051009
// Protect the 8 nodes with the lowest minimum ping time.
10061010
// An attacker cannot manipulate this metric without physically moving nodes closer to the target.
1007-
std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), ReverseCompareNodeMinPingTime);
1008-
vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(8, static_cast<int>(vEvictionCandidates.size())), vEvictionCandidates.end());
1009-
1010-
if (vEvictionCandidates.empty()) return false;
1011-
1011+
EraseLastKElements(vEvictionCandidates, ReverseCompareNodeMinPingTime, 8);
10121012
// Protect 4 nodes that most recently sent us transactions.
10131013
// An attacker cannot manipulate this metric without performing useful work.
1014-
std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), CompareNodeTXTime);
1015-
vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(4, static_cast<int>(vEvictionCandidates.size())), vEvictionCandidates.end());
1016-
1017-
if (vEvictionCandidates.empty()) return false;
1018-
1014+
EraseLastKElements(vEvictionCandidates, CompareNodeTXTime, 4);
10191015
// Protect 4 nodes that most recently sent us blocks.
10201016
// An attacker cannot manipulate this metric without performing useful work.
1021-
std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), CompareNodeBlockTime);
1022-
vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(4, static_cast<int>(vEvictionCandidates.size())), vEvictionCandidates.end());
1023-
1024-
if (vEvictionCandidates.empty()) return false;
1025-
1017+
EraseLastKElements(vEvictionCandidates, CompareNodeBlockTime, 4);
10261018
// Protect the half of the remaining nodes which have been connected the longest.
10271019
// This replicates the non-eviction implicit behavior, and precludes attacks that start later.
1028-
std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), ReverseCompareNodeTimeConnected);
1029-
vEvictionCandidates.erase(vEvictionCandidates.end() - static_cast<int>(vEvictionCandidates.size() / 2), vEvictionCandidates.end());
1020+
EraseLastKElements(vEvictionCandidates, ReverseCompareNodeTimeConnected, vEvictionCandidates.size() / 2);
10301021

10311022
if (vEvictionCandidates.empty()) return false;
10321023

@@ -1037,12 +1028,12 @@ bool CConnman::AttemptToEvictConnection()
10371028
int64_t nMostConnectionsTime = 0;
10381029
std::map<uint64_t, std::vector<NodeEvictionCandidate> > mapNetGroupNodes;
10391030
for (const NodeEvictionCandidate &node : vEvictionCandidates) {
1040-
mapNetGroupNodes[node.nKeyedNetGroup].push_back(node);
1041-
int64_t grouptime = mapNetGroupNodes[node.nKeyedNetGroup][0].nTimeConnected;
1042-
size_t groupsize = mapNetGroupNodes[node.nKeyedNetGroup].size();
1031+
std::vector<NodeEvictionCandidate> &group = mapNetGroupNodes[node.nKeyedNetGroup];
1032+
group.push_back(node);
1033+
int64_t grouptime = group[0].nTimeConnected;
10431034

1044-
if (groupsize > nMostConnections || (groupsize == nMostConnections && grouptime > nMostConnectionsTime)) {
1045-
nMostConnections = groupsize;
1035+
if (group.size() > nMostConnections || (group.size() == nMostConnections && grouptime > nMostConnectionsTime)) {
1036+
nMostConnections = group.size();
10461037
nMostConnectionsTime = grouptime;
10471038
naMostConnections = node.nKeyedNetGroup;
10481039
}

0 commit comments

Comments
 (0)