The eviction logic is one of the most important parts in our code base: a bug in the eviction logic could allow for attacker triggered network partitioning.

Unfortunately the eviction logic is currently not tested properly.

The unit tests and fuzz tests don't cover the eviction logic at all.

The functional tests cover some parts of the eviction logic but the coverage is spotty/incomplete.

Unfortunately `CConnman::AttemptToEvictConnection` is currently somewhat tricky to test.

To solve this I suggest simplifying `CConnman::AttemptToEvictConnection()` by introducing a new function ...

```
[[nodiscard]] Optional<NodeEvictionCandidate> SelectNodeToEvict(std::vector<NodeEvictionCandidate> vEvictionCandidates)
```

... which would be called from the now much simplified `CConnman::AttemptToEvictConnection`.

`SelectNodeToEvict` would contain all eviction selection logic and could thus be tested trivially.


rwise. The latter cannot be used directly
     * because it doesn't detect the former, and it's not the responsibility of
     * the CNetAddr class to know the actual network a peer is connected through.
     *
     * @return network the peer connected through.
     */
    Network ConnectedThroughNetwork() const;
protected:
    mapMsgCmdSize mapSendBytesPerMsgCmd;
    mapMsgCmdSize mapRecvBytesPerMsgCmd GUARDED_BY(cs_vRecv);
public:
    uint256 hashContinue;
    std::atomic<int> nStartingHeight{-1};
    // 
    std::atomic<bool> m_bip152_highbandwidth_to{false};
    // 
    std::atomic<bool> m_bip152_highbandwidth_from{false};
    // 
    std::vector<CAddress> vAddrToSend;
    std::unique_ptr<CRollingBloomFilter> m_addr_known{nullptr};
    bool fGetAddr{false};
    std::chrono::microseconds m_next_addr_send GUARDED_BY(cs_sendProcessing){0};
    std::chrono::microseconds m_next_local_addr_send GUARDED_BY(cs_sendProcessing){0};
    // 
    // 
    // 
    std::vector<uint256> vInventoryBlockToSend GUARDED_BY(cs_inventory);
    Mutex cs_inventory;
    struct TxRelay {
        mutable RecursiveMutex cs_filter;
        // 
        // 
        // 
        //    
        bool fRelayTxes GUARDED_BY(cs_filter){false};
        std::unique_ptr<CBloomFilter> pfilter PT_GUARDED_BY(cs_filter) GUARDED_BY(cs_filter){nullptr};
        mutable RecursiveMutex cs_tx_inventory;
        CRollingBloomFilter filterInventoryKnown GUARDED_BY(cs_tx_inventory){50000, 0.000001};
        // 
        // 
        std::set<uint256> setInventoryTxToSend;
        // 
        bool fSendMempool GUARDED_BY(cs_tx_inventory){false};
        // 
        std::atomic<std::chrono::seconds> m_last_mempool_req{0s};
        std::chrono::microseconds nNextInvSend{0};
        RecursiveMutex cs_feeFilter;
        // 
        CAmount minFeeFilter GUARDED_BY(cs_feeFilter){0};
        CAmount lastSentFeeFilter{0};
        int64_t nextSendTimeFeeFilter{0};
    };
    // 
    std::unique_ptr<TxRelay> m_tx_relay;
    // 