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.


Id m_node_id; // 
    mutable CHash256 hasher;
    mutable uint256 data_hash;
    bool in_data;                   // 
    CDataStream hdrbuf;             // 
    CMessageHeader hdr;             // 
    CDataStream vRecv;              // 
    unsigned int nHdrPos;
    unsigned int nDataPos;
    const uint256& GetMessageHash() const;
    int readHeader(Span<const uint8_t> msg_bytes);
    int readData(Span<const uint8_t> msg_bytes);
    void Reset() {
        vRecv.clear();
        hdrbuf.clear();
        hdrbuf.resize(24);
        in_data = false;
        nHdrPos = 0;
        nDataPos = 0;
        data_hash.SetNull();
        hasher.Reset();
    }
public:
    V1TransportDeserializer(const CChainParams& chain_params, const NodeId node_id, int nTypeIn, int nVersionIn)
        : m_chain_params(chain_params),
          m_node_id(node_id),
          hdrbuf(nTypeIn, nVersionIn),
          vRecv(nTypeIn, nVersionIn)
    {
        Reset();
    }
    bool Complete() const override
    {
        if (in_data)
            return false;
        return (hdr.nMessageSize == nDataPos);
    }
    void SetVersion(int nVersionIn) override
    {
        hdrbuf.SetVersion(nVersionIn);
        vRecv.SetVersion(nVersionIn);
    }
    int Read(Span<const uint8_t>& msg_bytes) override
    {
        int ret = in_data ? readData(msg_bytes) : readHeader(msg_bytes);
        if (ret < 0) {
            Reset();
        } else {
            msg_bytes = msg_bytes.subspan(ret);
        }
        return ret;
    }
    Optional<CNetMessage> GetMessage(std::chrono::microseconds time, uint32_t& out_err_raw_size) override;
};
/** The TransportSerializer prepares messages for the network transport
 */
class TransportSerializer {
public:
    // 
    virtual void prepareForTransport(CSerializedNetMsg& msg, std::vector<unsigned char>& header) = 0;
    virtual ~TransportSerializer() {}
};
class V1TransportSerializer  : public TransportSerializer {
public:
    void prepareForTransport(CSerializedNetMsg& msg, std