When the mempool fills the verbose `getrawmempool` RPC call gets really slow.  It can take minutes for >100k transactions in the mempool.

The culprit is the univalue library.  Objects are implemented as a big list, but the library checks for duplicate keys.  So inserting n key-value pairs into an object takes O(n^2).

Possible fixes:

- Improve univalue library by using linked hash maps.
- change the RPC output format of getrawmempool to use a list of objects, instead of an object of objects.  But this breaks existing code.
- hack the library to be able to skip the duplicate check.

{
    UniValue rv(UniValue::VOBJ);
    rv.pushKV("id", name);
    rv.pushKV("version", version);
    rv.pushKV("reject", SoftForkMajorityDesc(version, pindex, consensusParams));
    return rv;
}
static UniValue BIP9SoftForkDesc(const Consensus::Params& consensusParams, Consensus::DeploymentPos id)
{
    UniValue rv(UniValue::VOBJ);
    const ThresholdState thresholdState = VersionBitsTipState(consensusParams, id);
    switch (thresholdState) {
    case ThresholdState::DEFINED: rv.pushKV("status", "defined"); break;
    case ThresholdState::STARTED: rv.pushKV("status", "started"); break;
    case ThresholdState::LOCKED_IN: rv.pushKV("status", "locked_in"); break;
    case ThresholdState::ACTIVE: rv.pushKV("status", "active"); break;
    case ThresholdState::FAILED: rv.pushKV("status", "failed"); break;
    }
    if (ThresholdState::STARTED == thresholdState)
    {
        rv.pushKV("bit", consensusParams.vDeployments[id].bit);
    }
    rv.pushKV("startTime", consensusParams.vDeployments[id].nStartTime);
    rv.pushKV("timeout", consensusParams.vDeployments[id].nTimeout);
    rv.pushKV("since", VersionBitsTipStateSinceHeight(consensusParams, id));
    if (ThresholdState::STARTED == thresholdState)
    {