@@ -961,6 +961,16 @@ static bool CompareNodeTXTime(const NodeEvictionCandidate &a, const NodeEviction
961
961
return a.nTimeConnected > b.nTimeConnected ;
962
962
}
963
963
964
+
965
+ // ! Sort an array by the specified comparator, then erase the last K elements.
966
+ template <typename T, typename Comparator>
967
+ static void EraseLastKElements (std::vector<T> &elements, Comparator comparator, size_t k)
968
+ {
969
+ std::sort (elements.begin (), elements.end (), comparator);
970
+ size_t eraseSize = std::min (k, elements.size ());
971
+ elements.erase (elements.end () - eraseSize, elements.end ());
972
+ }
973
+
964
974
/* * Try to find a connection to evict when the node is full.
965
975
* Extreme care must be taken to avoid opening the node to attacker
966
976
* triggered network partitioning.
@@ -990,42 +1000,23 @@ bool CConnman::AttemptToEvictConnection()
990
1000
}
991
1001
}
992
1002
993
- if (vEvictionCandidates.empty ()) return false ;
994
-
995
1003
// Protect connections with certain characteristics
996
1004
997
1005
// Deterministically select 4 peers to protect by netgroup.
998
1006
// An attacker cannot predict which netgroups will be protected
999
- std::sort (vEvictionCandidates.begin (), vEvictionCandidates.end (), CompareNetGroupKeyed);
1000
- vEvictionCandidates.erase (vEvictionCandidates.end () - std::min (4 , static_cast <int >(vEvictionCandidates.size ())), vEvictionCandidates.end ());
1001
-
1002
- if (vEvictionCandidates.empty ()) return false ;
1003
-
1007
+ EraseLastKElements (vEvictionCandidates, CompareNetGroupKeyed, 4 );
1004
1008
// Protect the 8 nodes with the lowest minimum ping time.
1005
1009
// An attacker cannot manipulate this metric without physically moving nodes closer to the target.
1006
- std::sort (vEvictionCandidates.begin (), vEvictionCandidates.end (), ReverseCompareNodeMinPingTime);
1007
- vEvictionCandidates.erase (vEvictionCandidates.end () - std::min (8 , static_cast <int >(vEvictionCandidates.size ())), vEvictionCandidates.end ());
1008
-
1009
- if (vEvictionCandidates.empty ()) return false ;
1010
-
1010
+ EraseLastKElements (vEvictionCandidates, ReverseCompareNodeMinPingTime, 8 );
1011
1011
// Protect 4 nodes that most recently sent us transactions.
1012
1012
// An attacker cannot manipulate this metric without performing useful work.
1013
- std::sort (vEvictionCandidates.begin (), vEvictionCandidates.end (), CompareNodeTXTime);
1014
- vEvictionCandidates.erase (vEvictionCandidates.end () - std::min (4 , static_cast <int >(vEvictionCandidates.size ())), vEvictionCandidates.end ());
1015
-
1016
- if (vEvictionCandidates.empty ()) return false ;
1017
-
1013
+ EraseLastKElements (vEvictionCandidates, CompareNodeTXTime, 4 );
1018
1014
// Protect 4 nodes that most recently sent us blocks.
1019
1015
// An attacker cannot manipulate this metric without performing useful work.
1020
- std::sort (vEvictionCandidates.begin (), vEvictionCandidates.end (), CompareNodeBlockTime);
1021
- vEvictionCandidates.erase (vEvictionCandidates.end () - std::min (4 , static_cast <int >(vEvictionCandidates.size ())), vEvictionCandidates.end ());
1022
-
1023
- if (vEvictionCandidates.empty ()) return false ;
1024
-
1016
+ EraseLastKElements (vEvictionCandidates, CompareNodeBlockTime, 4 );
1025
1017
// Protect the half of the remaining nodes which have been connected the longest.
1026
1018
// This replicates the non-eviction implicit behavior, and precludes attacks that start later.
1027
- std::sort (vEvictionCandidates.begin (), vEvictionCandidates.end (), ReverseCompareNodeTimeConnected);
1028
- vEvictionCandidates.erase (vEvictionCandidates.end () - static_cast <int >(vEvictionCandidates.size () / 2 ), vEvictionCandidates.end ());
1019
+ EraseLastKElements (vEvictionCandidates, ReverseCompareNodeTimeConnected, vEvictionCandidates.size () / 2 );
1029
1020
1030
1021
if (vEvictionCandidates.empty ()) return false ;
1031
1022
@@ -1036,12 +1027,12 @@ bool CConnman::AttemptToEvictConnection()
1036
1027
int64_t nMostConnectionsTime = 0 ;
1037
1028
std::map<uint64_t , std::vector<NodeEvictionCandidate> > mapNetGroupNodes;
1038
1029
for (const NodeEvictionCandidate &node : vEvictionCandidates) {
1039
- mapNetGroupNodes[node.nKeyedNetGroup ]. push_back (node) ;
1040
- int64_t grouptime = mapNetGroupNodes[node. nKeyedNetGroup ][ 0 ]. nTimeConnected ;
1041
- size_t groupsize = mapNetGroupNodes[node. nKeyedNetGroup ]. size () ;
1030
+ std::vector<NodeEvictionCandidate> &group = mapNetGroupNodes[node.nKeyedNetGroup ];
1031
+ group. push_back (node) ;
1032
+ int64_t grouptime = group[ 0 ]. nTimeConnected ;
1042
1033
1043
- if (groupsize > nMostConnections || (groupsize == nMostConnections && grouptime > nMostConnectionsTime)) {
1044
- nMostConnections = groupsize ;
1034
+ if (group. size () > nMostConnections || (group. size () == nMostConnections && grouptime > nMostConnectionsTime)) {
1035
+ nMostConnections = group. size () ;
1045
1036
nMostConnectionsTime = grouptime;
1046
1037
naMostConnections = node.nKeyedNetGroup ;
1047
1038
}
0 commit comments