`getblock` is slow on verbosity, it's happened because `LOCK(cs_main)` applied for whole function including JSON generation
https://github.com/bitcoin/bitcoin/blob/ef70f9b52b851c7997a9f1a0834714e3eebc1fd8/src/rpc/blockchain.cpp#L810

I added few lines which print spent time:
```cpp
    LOCK(cs_main);
    auto t1 = std::chrono::high_resolution_clock::now();
...
    auto t2 = std::chrono::high_resolution_clock::now();
    auto ret = blockToJSON(block, pblockindex, verbosity >= 2);
    auto t3 = std::chrono::high_resolution_clock::now();
    std::cout << "blockToJSON " << pblockindex->nHeight << ": " << std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1).count() << " " << std::chrono::duration_cast<std::chrono::microseconds>(t3 - t1).count() << std::endl;
    return ret;
```

and numbers looks like:
```
blockToJSON 570019: 14727 201870
blockToJSON 570022: 16049 225224
blockToJSON 570021: 33776 217398
blockToJSON 570020: 21754 191669
blockToJSON 570023: 30949 236941
blockToJSON 570025: 23346 223673
blockToJSON 570024: 18732 203002
blockToJSON 570026: 17467 216213
blockToJSON 570027: 16658 217395
blockToJSON 570028: 19015 219183
```

i.e. everything before JSON generation takes 15-30ms, while JSON takes minimum 190ms and lock `cs_main` for all this time. As result it's possible extract only ~5 blocks per second.

Looking on the code I think it's possible copy data from `CBlockIndex` to extra structure, so in this case `cs_main` can be unlocked right after `GetBlockChecked`.
https://github.com/bitcoin/bitcoin/blob/ef70f9b52b851c7997a9f1a0834714e3eebc1fd8/src/rpc/blockchain.cpp#L828
As result `getblock` in verbosity mode should be much faster (in case if `-rpcthreads` will be adjusted too).

Does this make sense?
totalfee += txfee;
            
            CAmount feerate = weight ? (txfee * WITNESS_SCALE_FACTOR) / weight : 0;
            if (do_feerate_percentiles) {
                feerate_array.emplace_back(std::make_pair(feerate, weight));
            }
            maxfeerate = std::max(maxfeerate, feerate);
            minfeerate = std::min(minfeerate, feerate);
        }
    }
    CAmount feerate_percentiles[NUM_GETBLOCKSTATS_PERCENTILES] = { 0 };
    CalculatePercentilesByWeight(feerate_percentiles, feerate_array, total_weight);
    UniValue feerates_res(UniValue::VARR);
    for (int64_t i = 0; i < NUM_GETBLOCKSTATS_PERCENTILES; i++) {
        feerates_res.push_back(feerate_percentiles[i]);
    }
    UniValue ret_all(UniValue::VOBJ);
    ret_all.pushKV("avgfee", (block.vtx.size() > 1) ? totalfee / (block.vtx.size() - 1) : 0);
    ret_all.pushKV("avgfeerate", total_weight ? (totalfee * WITNESS_SCALE_FACTOR) / total_weight : 0); 
    ret_all.pushKV("avgtxsize", (block.vtx.size() > 1) ? total_size / (block.vtx.size() - 1) : 0);
    ret_all.pushKV("blockhash", pindex->GetBlockHash().GetHex());
    ret_all.pushKV("feerate_percentiles", feerates_res);
    ret_all.pushKV("height", (int64_t)pindex->nHeight);
    ret_all.pushKV("ins", inputs);
    ret_all.pushKV("maxfee", maxfee);
    ret_all.pushKV("maxfeerate", maxfeerate);
    ret_all.pushKV("maxtxsize", maxtxsize);
    ret_all.pushKV("medianfee", CalculateTruncatedMedian(fee_array));
    ret_all.pushKV("mediantime", pindex->GetMedianTimePast());
    ret_all.pushKV("mediantxsize", CalculateTruncatedMedian(txsize_array));