src/net.cpp
bool CConnman::AttemptToEvictConnection()
{
    std::vector<NodeEvictionCandidate> vEvictionCandidates;
    {
        LOCK(cs_vNodes);

        for (const CNode* node : vNodes) {
            if (node->HasPermission(PF_NOBAN))
                continue;
            if (!node->fInbound)
                continue;
            if (node->fDisconnect)
                continue;
            bool peer_relay_txes = false;
            bool peer_filter_not_null = false;
            if (node->m_tx_relay != nullptr) {
                LOCK(node->m_tx_relay->cs_filter);
                peer_relay_txes = node->m_tx_relay->fRelayTxes;
                peer_filter_not_null = node->m_tx_relay->pfilter != nullptr;
            }
            NodeEvictionCandidate candidate = {node->GetId(), node->nTimeConnected, node->nMinPingUsecTime,
                                               node->nLastBlockTime, node->nLastTXTime,
                                               HasAllDesirableServiceFlags(node->nServices),
                                               peer_relay_txes, peer_filter_not_null, node->addr, node->nKeyedNetGroup,
                                               node->m_prefer_evict};
            vEvictionCandidates.push_back(candidate);
        }
    }

    // Protect connections with certain characteristics

    // Deterministically select 4 peers to protect by netgroup.
    // An attacker cannot predict which netgroups will be protected
    EraseLastKElements(vEvictionCandidates, CompareNetGroupKeyed, 4);
    // Protect the 8 nodes with the lowest minimum ping time.
    // An attacker cannot manipulate this metric without physically moving nodes closer to the target.
    EraseLastKElements(vEvictionCandidates, ReverseCompareNodeMinPingTime, 8);
    // Protect 4 nodes that most recently sent us transactions.
    // An attacker cannot manipulate this metric without performing useful work.
    EraseLastKElements(vEvictionCandidates, CompareNodeTXTime, 4);
    // Protect 4 nodes that most recently sent us blocks.
    // An attacker cannot manipulate this metric without performing useful work.
    EraseLastKElements(vEvictionCandidates, CompareNodeBlockTime, 4);
    // Protect the half of the remaining nodes which have been connected the longest.
    // This replicates the non-eviction implicit behavior, and precludes attacks that start later.
    EraseLastKElements(vEvictionCandidates, ReverseCompareNodeTimeConnected, vEvictionCandidates.size() / 2);

    if (vEvictionCandidates.empty()) return false;

    // If any remaining peers are preferred for eviction consider only them.
    // This happens after the other preferences since if a peer is really the best by other criteria (esp relaying blocks)
    //  then we probably don't want to evict it no matter what.
    if (std::any_of(vEvictionCandidates.begin(),vEvictionCandidates.end(),[](NodeEvictionCandidate const &n){return n.prefer_evict;})) {
        vEvictionCandidates.erase(std::remove_if(vEvictionCandidates.begin(),vEvictionCandidates.end(),
                                  [](NodeEvictionCandidate const &n){return !n.prefer_evict;}),vEvictionCandidates.end());
    }

    // Identify the network group with the most connections and youngest member.
    // (vEvictionCandidates is already sorted by reverse connect time)
    uint64_t naMostConnections;
    unsigned int nMostConnections = 0;
    int64_t nMostConnectionsTime = 0;
    std::map<uint64_t, std::vector<NodeEvictionCandidate> > mapNetGroupNodes;
    for (const NodeEvictionCandidate &node : vEvictionCandidates) {
        std::vector<NodeEvictionCandidate> &group = mapNetGroupNodes[node.nKeyedNetGroup];
        group.push_back(node);
        int64_t grouptime = group[0].nTimeConnected;

        if (group.size() > nMostConnections || (group.size() == nMostConnections && grouptime > nMostConnectionsTime)) {
            nMostConnections = group.size();
            nMostConnectionsTime = grouptime;
            naMostConnections = node.nKeyedNetGroup;
        }
    }

    // Reduce to the network group with the most connections
    vEvictionCandidates = std::move(mapNetGroupNodes[naMostConnections]);

    // Disconnect from the network group with the most connections
    NodeId evicted = vEvictionCandidates.front().id;
    LOCK(cs_vNodes);
    for (CNode* pnode : vNodes) {
        if (pnode->GetId() == evicted) {
            pnode->fDisconnect = true;
            return true;
        }
    }
    return false;
}
/** Try to find a connection to evict when the node is full.
 *  Extreme care must be taken to avoid opening the node to attacker
 *   triggered network partitioning.
 *  The strategy used here is to protect a small number of peers
 *   for each of several distinct characteristics which are difficult
 *   to forge.  In order to partition a node the attacker must be
 *   simultaneously better at all of them than honest peers.
 */
Try to find a connection to evict when the node is full.
Extreme care must be taken to avoid opening the node to attacker
triggered network partitioning.
The strategy used here is to protect a small number of peers
for each of several distinct characteristics which are difficult
to forge.  In order to partition a node the attacker must be
simultaneously better at all of them than honest peers.
Try to find a connection to evict when the node is full . Extreme care must be taken to avoid opening the node to attacker triggered network partitioning . The strategy used here is to protect a small number of peers for each of several distinct characteristics which are difficult to forge . In order to partition a node the attacker must be simultaneously better at all of them than honest peers .
bool CConnman::AttemptToEvictConnection()
{
    std::vector<NodeEvictionCandidate> vEvictionCandidates;
    {
        LOCK(cs_vNodes);
        for (const CNode* node : vNodes) {
            if (node->HasPermission(PF_NOBAN))
                continue;
            if (!node->fInbound)
                continue;
            if (node->fDisconnect)
                continue;
            bool peer_relay_txes = false;
            bool peer_filter_not_null = false;
            if (node->m_tx_relay != nullptr) {
                LOCK(node->m_tx_relay->cs_filter);
                peer_relay_txes = node->m_tx_relay->fRelayTxes;
                peer_filter_not_null = node->m_tx_relay->pfilter != nullptr;
            }
            NodeEvictionCandidate candidate = {node->GetId(), node->nTimeConnected, node->nMinPingUsecTime,
                                               node->nLastBlockTime, node->nLastTXTime,
                                               HasAllDesirableServiceFlags(node->nServices),
                                               peer_relay_txes, peer_filter_not_null, node->addr, node->nKeyedNetGroup,
                                               node->m_prefer_evict};
            vEvictionCandidates.push_back(candidate);
        }
    }
    EraseLastKElements(vEvictionCandidates, CompareNetGroupKeyed, 4);
    EraseLastKElements(vEvictionCandidates, ReverseCompareNodeMinPingTime, 8);
    EraseLastKElements(vEvictionCandidates, CompareNodeTXTime, 4);
    EraseLastKElements(vEvictionCandidates, CompareNodeBlockTime, 4);
    EraseLastKElements(vEvictionCandidates, ReverseCompareNodeTimeConnected, vEvictionCandidates.size() / 2);
    if (vEvictionCandidates.empty()) return false;
    if (std::any_of(vEvictionCandidates.begin(),vEvictionCandidates.end(),[](NodeEvictionCandidate const &n){return n.prefer_evict;})) {
        vEvictionCandidates.erase(std::remove_if(vEvictionCandidates.begin(),vEvictionCandidates.end(),
                                  [](NodeEvictionCandidate const &n){return !n.prefer_evict;}),vEvictionCandidates.end());
    }
    uint64_t naMostConnections;
    unsigned int nMostConnections = 0;
    int64_t nMostConnectionsTime = 0;
    std::map<uint64_t, std::vector<NodeEvictionCandidate> > mapNetGroupNodes;
    for (const NodeEvictionCandidate &node : vEvictionCandidates) {
        std::vector<NodeEvictionCandidate> &group = mapNetGroupNodes[node.nKeyedNetGroup];
        group.push_back(node);
        int64_t grouptime = group[0].nTimeConnected;
        if (group.size() > nMostConnections || (group.size() == nMostConnections && grouptime > nMostConnectionsTime)) {
            nMostConnections = group.size();
            nMostConnectionsTime = grouptime;
            naMostConnections = node.nKeyedNetGroup;
        }
    }
    vEvictionCandidates = std::move(mapNetGroupNodes[naMostConnections]);
    NodeId evicted = vEvictionCandidates.front().id;
    LOCK(cs_vNodes);
    for (CNode* pnode : vNodes) {
        if (pnode->GetId() == evicted) {
            pnode->fDisconnect = true;
            return true;
        }
    }
    return false;
}
bool CConnman :: AttemptToEvictConnection ( ) { std :: vector < NodeEvictionCandidate > vEvictionCandidates ; { LOCK ( cs_vNodes ) ; for ( const CNode * node : vNodes ) { if ( node -> HasPermission ( PF_NOBAN ) ) continue ; if ( ! node -> fInbound ) continue ; if ( node -> fDisconnect ) continue ; bool peer_relay_txes = false ; bool peer_filter_not_null = false ; if ( node -> m_tx_relay != nullptr ) { LOCK ( node -> m_tx_relay -> cs_filter ) ; peer_relay_txes = node -> m_tx_relay -> fRelayTxes ; peer_filter_not_null = node -> m_tx_relay -> pfilter != nullptr ; } NodeEvictionCandidate candidate = { node -> GetId ( ) , node -> nTimeConnected , node -> nMinPingUsecTime , node -> nLastBlockTime , node -> nLastTXTime , HasAllDesirableServiceFlags ( node -> nServices ) , peer_relay_txes , peer_filter_not_null , node -> addr , node -> nKeyedNetGroup , node -> m_prefer_evict } ; vEvictionCandidates . push_back ( candidate ) ; } } EraseLastKElements ( vEvictionCandidates , CompareNetGroupKeyed , 4 ) ; EraseLastKElements ( vEvictionCandidates , ReverseCompareNodeMinPingTime , 8 ) ; EraseLastKElements ( vEvictionCandidates , CompareNodeTXTime , 4 ) ; EraseLastKElements ( vEvictionCandidates , CompareNodeBlockTime , 4 ) ; EraseLastKElements ( vEvictionCandidates , ReverseCompareNodeTimeConnected , vEvictionCandidates . size ( ) / 2 ) ; if ( vEvictionCandidates . empty ( ) ) return false ; if ( std :: any_of ( vEvictionCandidates . begin ( ) , vEvictionCandidates . end ( ) , [ ] ( NodeEvictionCandidate const & n ) { return n . prefer_evict ; } ) ) { vEvictionCandidates . erase ( std :: remove_if ( vEvictionCandidates . begin ( ) , vEvictionCandidates . end ( ) , [ ] ( NodeEvictionCandidate const & n ) { return ! n . prefer_evict ; } ) , vEvictionCandidates . end ( ) ) ; } uint64_t naMostConnections ; unsigned int nMostConnections = 0 ; int64_t nMostConnectionsTime = 0 ; std :: map < uint64_t , std :: vector < NodeEvictionCandidate > > mapNetGroupNodes ; for ( const NodeEvictionCandidate & node : vEvictionCandidates ) { std :: vector < NodeEvictionCandidate > & group = mapNetGroupNodes [ node . nKeyedNetGroup ] ; group . push_back ( node ) ; int64_t grouptime = group [ 0 ] . nTimeConnected ; if ( group . size ( ) > nMostConnections || ( group . size ( ) == nMostConnections && grouptime > nMostConnectionsTime ) ) { nMostConnections = group . size ( ) ; nMostConnectionsTime = grouptime ; naMostConnections = node . nKeyedNetGroup ; } } vEvictionCandidates = std :: move ( mapNetGroupNodes [ naMostConnections ] ) ; NodeId evicted = vEvictionCandidates . front ( ) . id ; LOCK ( cs_vNodes ) ; for ( CNode * pnode : vNodes ) { if ( pnode -> GetId ( ) == evicted ) { pnode -> fDisconnect = true ; return true ; } } return false ; }
Try to find a connection to evict when the node is full.
Try to find a connection to evict when the node is full .
// Protect connections with certain characteristics // Deterministically select 4 peers to protect by netgroup. // An attacker cannot predict which netgroups will be protected // Protect the 8 nodes with the lowest minimum ping time. // An attacker cannot manipulate this metric without physically moving nodes closer to the target. // Protect 4 nodes that most recently sent us transactions. // An attacker cannot manipulate this metric without performing useful work. // Protect 4 nodes that most recently sent us blocks. // An attacker cannot manipulate this metric without performing useful work. // Protect the half of the remaining nodes which have been connected the longest. // This replicates the non-eviction implicit behavior, and precludes attacks that start later. // If any remaining peers are preferred for eviction consider only them. // This happens after the other preferences since if a peer is really the best by other criteria (esp relaying blocks) //  then we probably don't want to evict it no matter what. // Identify the network group with the most connections and youngest member. // (vEvictionCandidates is already sorted by reverse connect time) // Reduce to the network group with the most connections // Disconnect from the network group with the most connections