`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?
{ "blockchain",         "getblockheader",         &getblockheader,         {"blockhash","verbose"} },
    { "blockchain",         "getchaintips",           &getchaintips,           {} },
    { "blockchain",         "getdifficulty",          &getdifficulty,          {} },
    { "blockchain",         "getmempoolancestors",    &getmempoolancestors,    {"txid","verbose"} },
    { "blockchain",         "getmempooldescendants",  &getmempooldescendants,  {"txid","verbose"} },
    { "blockchain",         "getmempoolentry",        &getmempoolentry,        {"txid"} },
    { "blockchain",         "getmempoolinfo",         &getmempoolinfo,         {} },
    { "blockchain",         "getrawmempool",          &getrawmempool,          {"verbose"} },
    { "blockchain",         "gettxout",               &gettxout,               {"txid","n","include_mempool"} },
    { "blockchain",         "gettxoutsetinfo",        &gettxoutsetinfo,        {} },
    { "blockchain",         "pruneblockchain",        &pruneblockchain,        {"height"} },
    { "blockchain",         "savemempool",            &savemempool,            {} },
    { "blockchain",         "verifychain",            &verifychain,            {"checklevel","nblocks"} },
    { "blockchain",         "preciousblock",          &preciousblock,          {"blockhash"} },
    { "blockchain",         "scantxoutset",           &scantxoutset,           {"action", "scanobjects"} },
    { "blockchain",         "getblockfilter",         &getblockfilter,         {"blockhash", "filtertype"} },
    
    { "hidden",             "invalidateblock",        &invalidateblock,        {"blockhash"} },
    { "hidden",             "reconsiderblock",        &reconsiderblock,        {"blockhash"} },
    { "hidden",             "waitfornewblock",        &waitfornewblock,        {"timeout"} },
    { "hidden",             "waitforblock",           &waitforblock,           {"blockhash","timeout"} },
    { "hidden",             "waitforblockheight",     &waitforblockheight,     {"height","timeout"} },
    { "hidden",             "syncwithvalidationinterfacequeue", &syncwithvalidationinterfacequeue, {} },
};
void RegisterBlockchainRPCCommands(CRPCTable &t)
{
    for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
        t.appendCommand(commands[vcidx].name, &commands[vcidx]);
}