Skip to content

Commit ed73f8c

Browse files
net: Move eviction node selection logic to SelectNodeToEvict(...)
1 parent 00f4dcd commit ed73f8c

File tree

2 files changed

+65
-54
lines changed

2 files changed

+65
-54
lines changed

src/net.cpp

Lines changed: 47 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <net_permissions.h>
1717
#include <netbase.h>
1818
#include <node/ui_interface.h>
19+
#include <optional.h>
1920
#include <protocol.h>
2021
#include <random.h>
2122
#include <scheduler.h>
@@ -840,21 +841,6 @@ size_t CConnman::SocketSendData(CNode *pnode) const EXCLUSIVE_LOCKS_REQUIRED(pno
840841
return nSentSize;
841842
}
842843

843-
struct NodeEvictionCandidate
844-
{
845-
NodeId id;
846-
int64_t nTimeConnected;
847-
int64_t nMinPingUsecTime;
848-
int64_t nLastBlockTime;
849-
int64_t nLastTXTime;
850-
bool fRelevantServices;
851-
bool fRelayTxes;
852-
bool fBloomFilter;
853-
uint64_t nKeyedNetGroup;
854-
bool prefer_evict;
855-
bool m_is_local;
856-
};
857-
858844
static bool ReverseCompareNodeMinPingTime(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b)
859845
{
860846
return a.nMinPingUsecTime > b.nMinPingUsecTime;
@@ -910,43 +896,8 @@ static void EraseLastKElements(std::vector<T> &elements, Comparator comparator,
910896
elements.erase(elements.end() - eraseSize, elements.end());
911897
}
912898

913-
/** Try to find a connection to evict when the node is full.
914-
* Extreme care must be taken to avoid opening the node to attacker
915-
* triggered network partitioning.
916-
* The strategy used here is to protect a small number of peers
917-
* for each of several distinct characteristics which are difficult
918-
* to forge. In order to partition a node the attacker must be
919-
* simultaneously better at all of them than honest peers.
920-
*/
921-
bool CConnman::AttemptToEvictConnection()
899+
[[nodiscard]] Optional<NodeId> SelectNodeToEvict(std::vector<NodeEvictionCandidate>&& vEvictionCandidates)
922900
{
923-
std::vector<NodeEvictionCandidate> vEvictionCandidates;
924-
{
925-
LOCK(cs_vNodes);
926-
927-
for (const CNode* node : vNodes) {
928-
if (node->HasPermission(PF_NOBAN))
929-
continue;
930-
if (!node->IsInboundConn())
931-
continue;
932-
if (node->fDisconnect)
933-
continue;
934-
bool peer_relay_txes = false;
935-
bool peer_filter_not_null = false;
936-
if (node->m_tx_relay != nullptr) {
937-
LOCK(node->m_tx_relay->cs_filter);
938-
peer_relay_txes = node->m_tx_relay->fRelayTxes;
939-
peer_filter_not_null = node->m_tx_relay->pfilter != nullptr;
940-
}
941-
NodeEvictionCandidate candidate = {node->GetId(), node->nTimeConnected, node->nMinPingUsecTime,
942-
node->nLastBlockTime, node->nLastTXTime,
943-
HasAllDesirableServiceFlags(node->nServices),
944-
peer_relay_txes, peer_filter_not_null, node->nKeyedNetGroup,
945-
node->m_prefer_evict, node->addr.IsLocal()};
946-
vEvictionCandidates.push_back(candidate);
947-
}
948-
}
949-
950901
// Protect connections with certain characteristics
951902

952903
// Deterministically select 4 peers to protect by netgroup.
@@ -984,7 +935,7 @@ bool CConnman::AttemptToEvictConnection()
984935
total_protect_size -= initial_size - vEvictionCandidates.size();
985936
EraseLastKElements(vEvictionCandidates, ReverseCompareNodeTimeConnected, total_protect_size);
986937

987-
if (vEvictionCandidates.empty()) return false;
938+
if (vEvictionCandidates.empty()) return nullopt;
988939

989940
// If any remaining peers are preferred for eviction consider only them.
990941
// This happens after the other preferences since if a peer is really the best by other criteria (esp relaying blocks)
@@ -1016,10 +967,52 @@ bool CConnman::AttemptToEvictConnection()
1016967
vEvictionCandidates = std::move(mapNetGroupNodes[naMostConnections]);
1017968

1018969
// Disconnect from the network group with the most connections
1019-
NodeId evicted = vEvictionCandidates.front().id;
970+
return vEvictionCandidates.front().id;
971+
}
972+
973+
/** Try to find a connection to evict when the node is full.
974+
* Extreme care must be taken to avoid opening the node to attacker
975+
* triggered network partitioning.
976+
* The strategy used here is to protect a small number of peers
977+
* for each of several distinct characteristics which are difficult
978+
* to forge. In order to partition a node the attacker must be
979+
* simultaneously better at all of them than honest peers.
980+
*/
981+
bool CConnman::AttemptToEvictConnection()
982+
{
983+
std::vector<NodeEvictionCandidate> vEvictionCandidates;
984+
{
985+
986+
LOCK(cs_vNodes);
987+
for (const CNode* node : vNodes) {
988+
if (node->HasPermission(PF_NOBAN))
989+
continue;
990+
if (!node->IsInboundConn())
991+
continue;
992+
if (node->fDisconnect)
993+
continue;
994+
bool peer_relay_txes = false;
995+
bool peer_filter_not_null = false;
996+
if (node->m_tx_relay != nullptr) {
997+
LOCK(node->m_tx_relay->cs_filter);
998+
peer_relay_txes = node->m_tx_relay->fRelayTxes;
999+
peer_filter_not_null = node->m_tx_relay->pfilter != nullptr;
1000+
}
1001+
NodeEvictionCandidate candidate = {node->GetId(), node->nTimeConnected, node->nMinPingUsecTime,
1002+
node->nLastBlockTime, node->nLastTXTime,
1003+
HasAllDesirableServiceFlags(node->nServices),
1004+
peer_relay_txes, peer_filter_not_null, node->nKeyedNetGroup,
1005+
node->m_prefer_evict, node->addr.IsLocal()};
1006+
vEvictionCandidates.push_back(candidate);
1007+
}
1008+
}
1009+
const Optional<NodeId> node_id_to_evict = SelectNodeToEvict(std::move(vEvictionCandidates));
1010+
if (!node_id_to_evict) {
1011+
return false;
1012+
}
10201013
LOCK(cs_vNodes);
10211014
for (CNode* pnode : vNodes) {
1022-
if (pnode->GetId() == evicted) {
1015+
if (pnode->GetId() == *node_id_to_evict) {
10231016
pnode->fDisconnect = true;
10241017
return true;
10251018
}

src/net.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include <map>
3434
#include <memory>
3535
#include <thread>
36+
#include <vector>
3637

3738
class CScheduler;
3839
class CNode;
@@ -1226,4 +1227,21 @@ inline std::chrono::microseconds PoissonNextSend(std::chrono::microseconds now,
12261227
return std::chrono::microseconds{PoissonNextSend(now.count(), average_interval.count())};
12271228
}
12281229

1230+
struct NodeEvictionCandidate
1231+
{
1232+
NodeId id;
1233+
int64_t nTimeConnected;
1234+
int64_t nMinPingUsecTime;
1235+
int64_t nLastBlockTime;
1236+
int64_t nLastTXTime;
1237+
bool fRelevantServices;
1238+
bool fRelayTxes;
1239+
bool fBloomFilter;
1240+
uint64_t nKeyedNetGroup;
1241+
bool prefer_evict;
1242+
bool m_is_local;
1243+
};
1244+
1245+
[[nodiscard]] Optional<NodeId> SelectNodeToEvict(std::vector<NodeEvictionCandidate>&& vEvictionCandidates);
1246+
12291247
#endif // BITCOIN_NET_H

0 commit comments

Comments
 (0)