@@ -962,6 +962,16 @@ static bool CompareNodeTXTime(const NodeEvictionCandidate &a, const NodeEviction
962
962
return a.nTimeConnected > b.nTimeConnected ;
963
963
}
964
964
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
+
965
975
/* * Try to find a connection to evict when the node is full.
966
976
* Extreme care must be taken to avoid opening the node to attacker
967
977
* triggered network partitioning.
@@ -991,42 +1001,23 @@ bool CConnman::AttemptToEvictConnection()
991
1001
}
992
1002
}
993
1003
994
- if (vEvictionCandidates.empty ()) return false ;
995
-
996
1004
// Protect connections with certain characteristics
997
1005
998
1006
// Deterministically select 4 peers to protect by netgroup.
999
1007
// 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 );
1005
1009
// Protect the 8 nodes with the lowest minimum ping time.
1006
1010
// 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 );
1012
1012
// Protect 4 nodes that most recently sent us transactions.
1013
1013
// 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 );
1019
1015
// Protect 4 nodes that most recently sent us blocks.
1020
1016
// 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 );
1026
1018
// Protect the half of the remaining nodes which have been connected the longest.
1027
1019
// 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 );
1030
1021
1031
1022
if (vEvictionCandidates.empty ()) return false ;
1032
1023
@@ -1037,12 +1028,12 @@ bool CConnman::AttemptToEvictConnection()
1037
1028
int64_t nMostConnectionsTime = 0 ;
1038
1029
std::map<uint64_t , std::vector<NodeEvictionCandidate> > mapNetGroupNodes;
1039
1030
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 ;
1043
1034
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 () ;
1046
1037
nMostConnectionsTime = grouptime;
1047
1038
naMostConnections = node.nKeyedNetGroup ;
1048
1039
}
0 commit comments