| 3167 | } |
| 3168 | |
| 3169 | void PeerLogicValidation::EvictExtraOutboundPeers(int64_t time_in_seconds) |
| 3170 | { |
| 3171 | // Check whether we have too many outbound peers |
| 3172 | int extra_peers = connman->GetExtraOutboundCount(); |
| 3173 | if (extra_peers > 0) { |
| 3174 | // If we have more outbound peers than we target, disconnect one. |
| 3175 | // Pick the outbound peer that least recently announced |
| 3176 | // us a new block, with ties broken by choosing the more recent |
| 3177 | // connection (higher node id) |
| 3178 | NodeId worst_peer = -1; |
| 3179 | int64_t oldest_block_announcement = std::numeric_limits<int64_t>::max(); |
| 3180 | |
| 3181 | LOCK(cs_main); |
| 3182 | |
| 3183 | connman->ForEachNode([&](CNode* pnode) { |
| 3184 | AssertLockHeld(cs_main); |
| 3185 | |
| 3186 | // Ignore non-outbound peers, or nodes marked for disconnect already |
| 3187 | if (!IsOutboundDisconnectionCandidate(pnode) || pnode->fDisconnect) return; |
| 3188 | CNodeState *state = State(pnode->GetId()); |
| 3189 | if (state == nullptr) return; // shouldn't be possible, but just in case |
| 3190 | // Don't evict our protected peers |
| 3191 | if (state->m_chain_sync.m_protect) return; |
| 3192 | if (state->m_last_block_announcement < oldest_block_announcement || (state->m_last_block_announcement == oldest_block_announcement && pnode->GetId() > worst_peer)) { |
| 3193 | worst_peer = pnode->GetId(); |
| 3194 | oldest_block_announcement = state->m_last_block_announcement; |
| 3195 | } |
| 3196 | }); |
| 3197 | if (worst_peer != -1) { |
| 3198 | bool disconnected = connman->ForNode(worst_peer, [&](CNode *pnode) { |
| 3199 | AssertLockHeld(cs_main); |
| 3200 | |
| 3201 | // Only disconnect a peer that has been connected to us for |
| 3202 | // some reasonable fraction of our check-frequency, to give |
| 3203 | // it time for new information to have arrived. |
| 3204 | // Also don't disconnect any peer we're trying to download a |
| 3205 | // block from. |
| 3206 | CNodeState &state = *State(pnode->GetId()); |
| 3207 | if (time_in_seconds - pnode->nTimeConnected > MINIMUM_CONNECT_TIME && state.nBlocksInFlight == 0) { |
| 3208 | LogPrint(BCLog::NET, "disconnecting extra outbound peer=%d (last block announcement received at time %d)\n", pnode->GetId(), oldest_block_announcement); |
| 3209 | pnode->fDisconnect = true; |
| 3210 | return true; |
| 3211 | } else { |
| 3212 | LogPrint(BCLog::NET, "keeping outbound peer=%d chosen for eviction (connect time: %d, blocks_in_flight: %d)\n", pnode->GetId(), pnode->nTimeConnected, state.nBlocksInFlight); |
| 3213 | return false; |
| 3214 | } |
| 3215 | }); |
| 3216 | if (disconnected) { |
| 3217 | // If we disconnected an extra peer, that means we successfully |
| 3218 | // connected to at least one peer after the last time we |
| 3219 | // detected a stale tip. Don't try any more extra peers until |
| 3220 | // we next detect a stale tip, to limit the load we put on the |
| 3221 | // network from these extra connections. |
| 3222 | connman->SetTryNewOutboundPeer(false); |
| 3223 | } |
| 3224 | } |
| 3225 | } |
| 3226 | } |
nothing calls this directly
no test coverage detected