LCOV - code coverage report
Current view: top level - src/rpc - mining.cpp (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 767 823 93.2 %
Date: 2022-08-30 15:50:09 Functions: 29 29 100.0 %
Legend: Modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed

Not modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed
Branches: 188 244 77.0 %

           Branch data     Line data    Source code
#       1                 :            : // Copyright (c) 2010 Satoshi Nakamoto
#       2                 :            : // Copyright (c) 2009-2021 The Bitcoin Core developers
#       3                 :            : // Distributed under the MIT software license, see the accompanying
#       4                 :            : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#       5                 :            : 
#       6                 :            : #include <chain.h>
#       7                 :            : #include <chainparams.h>
#       8                 :            : #include <consensus/amount.h>
#       9                 :            : #include <consensus/consensus.h>
#      10                 :            : #include <consensus/merkle.h>
#      11                 :            : #include <consensus/params.h>
#      12                 :            : #include <consensus/validation.h>
#      13                 :            : #include <core_io.h>
#      14                 :            : #include <deploymentinfo.h>
#      15                 :            : #include <deploymentstatus.h>
#      16                 :            : #include <key_io.h>
#      17                 :            : #include <net.h>
#      18                 :            : #include <node/context.h>
#      19                 :            : #include <node/miner.h>
#      20                 :            : #include <pow.h>
#      21                 :            : #include <rpc/blockchain.h>
#      22                 :            : #include <rpc/mining.h>
#      23                 :            : #include <rpc/server.h>
#      24                 :            : #include <rpc/server_util.h>
#      25                 :            : #include <rpc/util.h>
#      26                 :            : #include <script/descriptor.h>
#      27                 :            : #include <script/script.h>
#      28                 :            : #include <script/signingprovider.h>
#      29                 :            : #include <shutdown.h>
#      30                 :            : #include <timedata.h>
#      31                 :            : #include <txmempool.h>
#      32                 :            : #include <univalue.h>
#      33                 :            : #include <util/strencodings.h>
#      34                 :            : #include <util/string.h>
#      35                 :            : #include <util/system.h>
#      36                 :            : #include <util/translation.h>
#      37                 :            : #include <validation.h>
#      38                 :            : #include <validationinterface.h>
#      39                 :            : #include <warnings.h>
#      40                 :            : 
#      41                 :            : #include <memory>
#      42                 :            : #include <stdint.h>
#      43                 :            : 
#      44                 :            : using node::BlockAssembler;
#      45                 :            : using node::CBlockTemplate;
#      46                 :            : using node::NodeContext;
#      47                 :            : using node::RegenerateCommitments;
#      48                 :            : using node::UpdateTime;
#      49                 :            : 
#      50                 :            : /**
#      51                 :            :  * Return average network hashes per second based on the last 'lookup' blocks,
#      52                 :            :  * or from the last difficulty change if 'lookup' is nonpositive.
#      53                 :            :  * If 'height' is nonnegative, compute the estimate at the time when a given block was found.
#      54                 :            :  */
#      55                 :          6 : static UniValue GetNetworkHashPS(int lookup, int height, const CChain& active_chain) {
#      56                 :          6 :     const CBlockIndex* pb = active_chain.Tip();
#      57                 :            : 
#      58 [ -  + ][ #  # ]:          6 :     if (height >= 0 && height < active_chain.Height()) {
#      59                 :          0 :         pb = active_chain[height];
#      60                 :          0 :     }
#      61                 :            : 
#      62 [ -  + ][ +  + ]:          6 :     if (pb == nullptr || !pb->nHeight)
#      63                 :          1 :         return 0;
#      64                 :            : 
#      65                 :            :     // If lookup is -1, then use blocks since last difficulty change.
#      66         [ -  + ]:          5 :     if (lookup <= 0)
#      67                 :          0 :         lookup = pb->nHeight % Params().GetConsensus().DifficultyAdjustmentInterval() + 1;
#      68                 :            : 
#      69                 :            :     // If lookup is larger than chain, then set it to chain length.
#      70         [ -  + ]:          5 :     if (lookup > pb->nHeight)
#      71                 :          0 :         lookup = pb->nHeight;
#      72                 :            : 
#      73                 :          5 :     const CBlockIndex* pb0 = pb;
#      74                 :          5 :     int64_t minTime = pb0->GetBlockTime();
#      75                 :          5 :     int64_t maxTime = minTime;
#      76         [ +  + ]:        605 :     for (int i = 0; i < lookup; i++) {
#      77                 :        600 :         pb0 = pb0->pprev;
#      78                 :        600 :         int64_t time = pb0->GetBlockTime();
#      79                 :        600 :         minTime = std::min(time, minTime);
#      80                 :        600 :         maxTime = std::max(time, maxTime);
#      81                 :        600 :     }
#      82                 :            : 
#      83                 :            :     // In case there's a situation where minTime == maxTime, we don't want a divide by zero exception.
#      84         [ -  + ]:          5 :     if (minTime == maxTime)
#      85                 :          0 :         return 0;
#      86                 :            : 
#      87                 :          5 :     arith_uint256 workDiff = pb->nChainWork - pb0->nChainWork;
#      88                 :          5 :     int64_t timeDiff = maxTime - minTime;
#      89                 :            : 
#      90                 :          5 :     return workDiff.getdouble() / timeDiff;
#      91                 :          5 : }
#      92                 :            : 
#      93                 :            : static RPCHelpMan getnetworkhashps()
#      94                 :       1642 : {
#      95                 :       1642 :     return RPCHelpMan{"getnetworkhashps",
#      96                 :       1642 :                 "\nReturns the estimated network hashes per second based on the last n blocks.\n"
#      97                 :       1642 :                 "Pass in [blocks] to override # of blocks, -1 specifies since last difficulty change.\n"
#      98                 :       1642 :                 "Pass in [height] to estimate the network speed at the time when a certain block was found.\n",
#      99                 :       1642 :                 {
#     100                 :       1642 :                     {"nblocks", RPCArg::Type::NUM, RPCArg::Default{120}, "The number of blocks, or -1 for blocks since last difficulty change."},
#     101                 :       1642 :                     {"height", RPCArg::Type::NUM, RPCArg::Default{-1}, "To estimate at the time of the given height."},
#     102                 :       1642 :                 },
#     103                 :       1642 :                 RPCResult{
#     104                 :       1642 :                     RPCResult::Type::NUM, "", "Hashes per second estimated"},
#     105                 :       1642 :                 RPCExamples{
#     106                 :       1642 :                     HelpExampleCli("getnetworkhashps", "")
#     107                 :       1642 :             + HelpExampleRpc("getnetworkhashps", "")
#     108                 :       1642 :                 },
#     109                 :       1642 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
#     110                 :       1642 : {
#     111                 :          6 :     ChainstateManager& chainman = EnsureAnyChainman(request.context);
#     112                 :          6 :     LOCK(cs_main);
#     113 [ -  + ][ -  + ]:          6 :     return GetNetworkHashPS(!request.params[0].isNull() ? request.params[0].getInt<int>() : 120, !request.params[1].isNull() ? request.params[1].getInt<int>() : -1, chainman.ActiveChain());
#     114                 :          6 : },
#     115                 :       1642 :     };
#     116                 :       1642 : }
#     117                 :            : 
#     118                 :            : static bool GenerateBlock(ChainstateManager& chainman, CBlock& block, uint64_t& max_tries, uint256& block_hash)
#     119                 :      28884 : {
#     120                 :      28884 :     block_hash.SetNull();
#     121                 :      28884 :     block.hashMerkleRoot = BlockMerkleRoot(block);
#     122                 :            : 
#     123 [ +  + ][ +  - ]:    1057720 :     while (max_tries > 0 && block.nNonce < std::numeric_limits<uint32_t>::max() && !CheckProofOfWork(block.GetHash(), block.nBits, chainman.GetConsensus()) && !ShutdownRequested()) {
#         [ +  + ][ +  - ]
#     124                 :    1028836 :         ++block.nNonce;
#     125                 :    1028836 :         --max_tries;
#     126                 :    1028836 :     }
#     127 [ +  + ][ -  + ]:      28884 :     if (max_tries == 0 || ShutdownRequested()) {
#     128                 :          1 :         return false;
#     129                 :          1 :     }
#     130         [ -  + ]:      28883 :     if (block.nNonce == std::numeric_limits<uint32_t>::max()) {
#     131                 :          0 :         return true;
#     132                 :          0 :     }
#     133                 :            : 
#     134                 :      28883 :     std::shared_ptr<const CBlock> shared_pblock = std::make_shared<const CBlock>(block);
#     135         [ -  + ]:      28883 :     if (!chainman.ProcessNewBlock(shared_pblock, /*force_processing=*/true, /*min_pow_checked=*/true, nullptr)) {
#     136                 :          0 :         throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted");
#     137                 :          0 :     }
#     138                 :            : 
#     139                 :      28883 :     block_hash = block.GetHash();
#     140                 :      28883 :     return true;
#     141                 :      28883 : }
#     142                 :            : 
#     143                 :            : static UniValue generateBlocks(ChainstateManager& chainman, const CTxMemPool& mempool, const CScript& coinbase_script, int nGenerate, uint64_t nMaxTries)
#     144                 :       2187 : {
#     145                 :       2187 :     UniValue blockHashes(UniValue::VARR);
#     146 [ +  + ][ +  - ]:      31063 :     while (nGenerate > 0 && !ShutdownRequested()) {
#     147                 :      28877 :         std::unique_ptr<CBlockTemplate> pblocktemplate(BlockAssembler{chainman.ActiveChainstate(), &mempool}.CreateNewBlock(coinbase_script));
#     148         [ -  + ]:      28877 :         if (!pblocktemplate.get())
#     149                 :          0 :             throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block");
#     150                 :      28877 :         CBlock *pblock = &pblocktemplate->block;
#     151                 :            : 
#     152                 :      28877 :         uint256 block_hash;
#     153         [ +  + ]:      28877 :         if (!GenerateBlock(chainman, *pblock, nMaxTries, block_hash)) {
#     154                 :          1 :             break;
#     155                 :          1 :         }
#     156                 :            : 
#     157         [ +  - ]:      28876 :         if (!block_hash.IsNull()) {
#     158                 :      28876 :             --nGenerate;
#     159                 :      28876 :             blockHashes.push_back(block_hash.GetHex());
#     160                 :      28876 :         }
#     161                 :      28876 :     }
#     162                 :       2187 :     return blockHashes;
#     163                 :       2187 : }
#     164                 :            : 
#     165                 :            : static bool getScriptFromDescriptor(const std::string& descriptor, CScript& script, std::string& error)
#     166                 :        446 : {
#     167                 :        446 :     FlatSigningProvider key_provider;
#     168                 :        446 :     const auto desc = Parse(descriptor, key_provider, error, /* require_checksum = */ false);
#     169         [ +  + ]:        446 :     if (desc) {
#     170         [ +  + ]:        438 :         if (desc->IsRange()) {
#     171                 :          1 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Ranged descriptor not accepted. Maybe pass through deriveaddresses first?");
#     172                 :          1 :         }
#     173                 :            : 
#     174                 :        437 :         FlatSigningProvider provider;
#     175                 :        437 :         std::vector<CScript> scripts;
#     176         [ +  + ]:        437 :         if (!desc->Expand(0, key_provider, scripts, provider)) {
#     177                 :          1 :             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Cannot derive script without private keys");
#     178                 :          1 :         }
#     179                 :            : 
#     180                 :            :         // Combo descriptors can have 2 or 4 scripts, so we can't just check scripts.size() == 1
#     181 [ +  - ][ +  - ]:        436 :         CHECK_NONFATAL(scripts.size() > 0 && scripts.size() <= 4);
#     182                 :            : 
#     183         [ +  + ]:        436 :         if (scripts.size() == 1) {
#     184                 :        434 :             script = scripts.at(0);
#     185         [ +  + ]:        434 :         } else if (scripts.size() == 4) {
#     186                 :            :             // For uncompressed keys, take the 3rd script, since it is p2wpkh
#     187                 :          1 :             script = scripts.at(2);
#     188                 :          1 :         } else {
#     189                 :            :             // Else take the 2nd script, since it is p2pkh
#     190                 :          1 :             script = scripts.at(1);
#     191                 :          1 :         }
#     192                 :            : 
#     193                 :        436 :         return true;
#     194                 :        437 :     } else {
#     195                 :          8 :         return false;
#     196                 :          8 :     }
#     197                 :        446 : }
#     198                 :            : 
#     199                 :            : static RPCHelpMan generatetodescriptor()
#     200                 :       2064 : {
#     201                 :       2064 :     return RPCHelpMan{
#     202                 :       2064 :         "generatetodescriptor",
#     203                 :       2064 :         "Mine to a specified descriptor and return the block hashes.",
#     204                 :       2064 :         {
#     205                 :       2064 :             {"num_blocks", RPCArg::Type::NUM, RPCArg::Optional::NO, "How many blocks are generated."},
#     206                 :       2064 :             {"descriptor", RPCArg::Type::STR, RPCArg::Optional::NO, "The descriptor to send the newly generated bitcoin to."},
#     207                 :       2064 :             {"maxtries", RPCArg::Type::NUM, RPCArg::Default{DEFAULT_MAX_TRIES}, "How many iterations to try."},
#     208                 :       2064 :         },
#     209                 :       2064 :         RPCResult{
#     210                 :       2064 :             RPCResult::Type::ARR, "", "hashes of blocks generated",
#     211                 :       2064 :             {
#     212                 :       2064 :                 {RPCResult::Type::STR_HEX, "", "blockhash"},
#     213                 :       2064 :             }
#     214                 :       2064 :         },
#     215                 :       2064 :         RPCExamples{
#     216                 :       2064 :             "\nGenerate 11 blocks to mydesc\n" + HelpExampleCli("generatetodescriptor", "11 \"mydesc\"")},
#     217                 :       2064 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
#     218                 :       2064 : {
#     219                 :        433 :     const int num_blocks{request.params[0].getInt<int>()};
#     220         [ +  - ]:        433 :     const uint64_t max_tries{request.params[2].isNull() ? DEFAULT_MAX_TRIES : request.params[2].getInt<int>()};
#     221                 :            : 
#     222                 :        433 :     CScript coinbase_script;
#     223                 :        433 :     std::string error;
#     224         [ -  + ]:        433 :     if (!getScriptFromDescriptor(request.params[1].get_str(), coinbase_script, error)) {
#     225                 :          0 :         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, error);
#     226                 :          0 :     }
#     227                 :            : 
#     228                 :        433 :     NodeContext& node = EnsureAnyNodeContext(request.context);
#     229                 :        433 :     const CTxMemPool& mempool = EnsureMemPool(node);
#     230                 :        433 :     ChainstateManager& chainman = EnsureChainman(node);
#     231                 :            : 
#     232                 :        433 :     return generateBlocks(chainman, mempool, coinbase_script, num_blocks, max_tries);
#     233                 :        433 : },
#     234                 :       2064 :     };
#     235                 :       2064 : }
#     236                 :            : 
#     237                 :            : static RPCHelpMan generate()
#     238                 :       1633 : {
#     239                 :       1633 :     return RPCHelpMan{"generate", "has been replaced by the -generate cli option. Refer to -help for more information.", {}, {}, RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue {
#     240                 :          1 :         throw JSONRPCError(RPC_METHOD_NOT_FOUND, self.ToString());
#     241                 :          1 :     }};
#     242                 :       1633 : }
#     243                 :            : 
#     244                 :            : static RPCHelpMan generatetoaddress()
#     245                 :       3388 : {
#     246                 :       3388 :     return RPCHelpMan{"generatetoaddress",
#     247                 :       3388 :         "Mine to a specified address and return the block hashes.",
#     248                 :       3388 :          {
#     249                 :       3388 :              {"nblocks", RPCArg::Type::NUM, RPCArg::Optional::NO, "How many blocks are generated."},
#     250                 :       3388 :              {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The address to send the newly generated bitcoin to."},
#     251                 :       3388 :              {"maxtries", RPCArg::Type::NUM, RPCArg::Default{DEFAULT_MAX_TRIES}, "How many iterations to try."},
#     252                 :       3388 :          },
#     253                 :       3388 :          RPCResult{
#     254                 :       3388 :              RPCResult::Type::ARR, "", "hashes of blocks generated",
#     255                 :       3388 :              {
#     256                 :       3388 :                  {RPCResult::Type::STR_HEX, "", "blockhash"},
#     257                 :       3388 :              }},
#     258                 :       3388 :          RPCExamples{
#     259                 :       3388 :             "\nGenerate 11 blocks to myaddress\n"
#     260                 :       3388 :             + HelpExampleCli("generatetoaddress", "11 \"myaddress\"")
#     261                 :       3388 :             + "If you are using the " PACKAGE_NAME " wallet, you can get a new address to send the newly generated bitcoin to with:\n"
#     262                 :       3388 :             + HelpExampleCli("getnewaddress", "")
#     263                 :       3388 :                 },
#     264                 :       3388 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
#     265                 :       3388 : {
#     266                 :       1757 :     const int num_blocks{request.params[0].getInt<int>()};
#     267         [ +  + ]:       1757 :     const uint64_t max_tries{request.params[2].isNull() ? DEFAULT_MAX_TRIES : request.params[2].getInt<int>()};
#     268                 :            : 
#     269                 :       1757 :     CTxDestination destination = DecodeDestination(request.params[1].get_str());
#     270         [ +  + ]:       1757 :     if (!IsValidDestination(destination)) {
#     271                 :          1 :         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Error: Invalid address");
#     272                 :          1 :     }
#     273                 :            : 
#     274                 :       1756 :     NodeContext& node = EnsureAnyNodeContext(request.context);
#     275                 :       1756 :     const CTxMemPool& mempool = EnsureMemPool(node);
#     276                 :       1756 :     ChainstateManager& chainman = EnsureChainman(node);
#     277                 :            : 
#     278                 :       1756 :     CScript coinbase_script = GetScriptForDestination(destination);
#     279                 :            : 
#     280                 :       1756 :     return generateBlocks(chainman, mempool, coinbase_script, num_blocks, max_tries);
#     281                 :       1757 : },
#     282                 :       3388 :     };
#     283                 :       3388 : }
#     284                 :            : 
#     285                 :            : static RPCHelpMan generateblock()
#     286                 :       1644 : {
#     287                 :       1644 :     return RPCHelpMan{"generateblock",
#     288                 :       1644 :         "Mine a set of ordered transactions to a specified address or descriptor and return the block hash.",
#     289                 :       1644 :         {
#     290                 :       1644 :             {"output", RPCArg::Type::STR, RPCArg::Optional::NO, "The address or descriptor to send the newly generated bitcoin to."},
#     291                 :       1644 :             {"transactions", RPCArg::Type::ARR, RPCArg::Optional::NO, "An array of hex strings which are either txids or raw transactions.\n"
#     292                 :       1644 :                 "Txids must reference transactions currently in the mempool.\n"
#     293                 :       1644 :                 "All transactions must be valid and in valid order, otherwise the block will be rejected.",
#     294                 :       1644 :                 {
#     295                 :       1644 :                     {"rawtx/txid", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, ""},
#     296                 :       1644 :                 },
#     297                 :       1644 :             },
#     298                 :       1644 :         },
#     299                 :       1644 :         RPCResult{
#     300                 :       1644 :             RPCResult::Type::OBJ, "", "",
#     301                 :       1644 :             {
#     302                 :       1644 :                 {RPCResult::Type::STR_HEX, "hash", "hash of generated block"},
#     303                 :       1644 :             }
#     304                 :       1644 :         },
#     305                 :       1644 :         RPCExamples{
#     306                 :       1644 :             "\nGenerate a block to myaddress, with txs rawtx and mempool_txid\n"
#     307                 :       1644 :             + HelpExampleCli("generateblock", R"("myaddress" '["rawtx", "mempool_txid"]')")
#     308                 :       1644 :         },
#     309                 :       1644 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
#     310                 :       1644 : {
#     311                 :         13 :     const auto address_or_descriptor = request.params[0].get_str();
#     312                 :         13 :     CScript coinbase_script;
#     313                 :         13 :     std::string error;
#     314                 :            : 
#     315         [ +  + ]:         13 :     if (!getScriptFromDescriptor(address_or_descriptor, coinbase_script, error)) {
#     316                 :          8 :         const auto destination = DecodeDestination(address_or_descriptor);
#     317         [ +  + ]:          8 :         if (!IsValidDestination(destination)) {
#     318                 :          1 :             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Error: Invalid address or descriptor");
#     319                 :          1 :         }
#     320                 :            : 
#     321                 :          7 :         coinbase_script = GetScriptForDestination(destination);
#     322                 :          7 :     }
#     323                 :            : 
#     324                 :         12 :     NodeContext& node = EnsureAnyNodeContext(request.context);
#     325                 :         12 :     const CTxMemPool& mempool = EnsureMemPool(node);
#     326                 :            : 
#     327                 :         12 :     std::vector<CTransactionRef> txs;
#     328                 :         12 :     const auto raw_txs_or_txids = request.params[1].get_array();
#     329         [ +  + ]:         17 :     for (size_t i = 0; i < raw_txs_or_txids.size(); i++) {
#     330                 :          7 :         const auto str(raw_txs_or_txids[i].get_str());
#     331                 :            : 
#     332                 :          7 :         uint256 hash;
#     333                 :          7 :         CMutableTransaction mtx;
#     334         [ +  + ]:          7 :         if (ParseHashStr(str, hash)) {
#     335                 :            : 
#     336                 :          4 :             const auto tx = mempool.get(hash);
#     337         [ +  + ]:          4 :             if (!tx) {
#     338                 :          1 :                 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Transaction %s not in mempool.", str));
#     339                 :          1 :             }
#     340                 :            : 
#     341                 :          3 :             txs.emplace_back(tx);
#     342                 :            : 
#     343         [ +  + ]:          3 :         } else if (DecodeHexTx(mtx, str)) {
#     344                 :          2 :             txs.push_back(MakeTransactionRef(std::move(mtx)));
#     345                 :            : 
#     346                 :          2 :         } else {
#     347                 :          1 :             throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("Transaction decode failed for %s. Make sure the tx has at least one input.", str));
#     348                 :          1 :         }
#     349                 :          7 :     }
#     350                 :            : 
#     351                 :         10 :     CBlock block;
#     352                 :            : 
#     353                 :         10 :     ChainstateManager& chainman = EnsureChainman(node);
#     354                 :         10 :     {
#     355                 :         10 :         LOCK(cs_main);
#     356                 :            : 
#     357                 :         10 :         std::unique_ptr<CBlockTemplate> blocktemplate(BlockAssembler{chainman.ActiveChainstate(), nullptr}.CreateNewBlock(coinbase_script));
#     358         [ -  + ]:         10 :         if (!blocktemplate) {
#     359                 :          0 :             throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block");
#     360                 :          0 :         }
#     361                 :         10 :         block = blocktemplate->block;
#     362                 :         10 :     }
#     363                 :            : 
#     364                 :         10 :     CHECK_NONFATAL(block.vtx.size() == 1);
#     365                 :            : 
#     366                 :            :     // Add transactions
#     367                 :         10 :     block.vtx.insert(block.vtx.end(), txs.begin(), txs.end());
#     368                 :         10 :     RegenerateCommitments(block, chainman);
#     369                 :            : 
#     370                 :         10 :     {
#     371                 :         10 :         LOCK(cs_main);
#     372                 :            : 
#     373                 :         10 :         BlockValidationState state;
#     374         [ +  + ]:         10 :         if (!TestBlockValidity(state, chainman.GetParams(), chainman.ActiveChainstate(), block, chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock), GetAdjustedTime, false, false)) {
#     375                 :          1 :             throw JSONRPCError(RPC_VERIFY_ERROR, strprintf("TestBlockValidity failed: %s", state.ToString()));
#     376                 :          1 :         }
#     377                 :         10 :     }
#     378                 :            : 
#     379                 :          9 :     uint256 block_hash;
#     380                 :          9 :     uint64_t max_tries{DEFAULT_MAX_TRIES};
#     381                 :            : 
#     382 [ +  + ][ -  + ]:          9 :     if (!GenerateBlock(chainman, block, max_tries, block_hash) || block_hash.IsNull()) {
#     383                 :          0 :         throw JSONRPCError(RPC_MISC_ERROR, "Failed to make block.");
#     384                 :          0 :     }
#     385                 :            : 
#     386                 :          9 :     UniValue obj(UniValue::VOBJ);
#     387                 :          9 :     obj.pushKV("hash", block_hash.GetHex());
#     388                 :          9 :     return obj;
#     389                 :          9 : },
#     390                 :       1644 :     };
#     391                 :       1644 : }
#     392                 :            : 
#     393                 :            : static RPCHelpMan getmininginfo()
#     394                 :       1641 : {
#     395                 :       1641 :     return RPCHelpMan{"getmininginfo",
#     396                 :       1641 :                 "\nReturns a json object containing mining-related information.",
#     397                 :       1641 :                 {},
#     398                 :       1641 :                 RPCResult{
#     399                 :       1641 :                     RPCResult::Type::OBJ, "", "",
#     400                 :       1641 :                     {
#     401                 :       1641 :                         {RPCResult::Type::NUM, "blocks", "The current block"},
#     402                 :       1641 :                         {RPCResult::Type::NUM, "currentblockweight", /*optional=*/true, "The block weight of the last assembled block (only present if a block was ever assembled)"},
#     403                 :       1641 :                         {RPCResult::Type::NUM, "currentblocktx", /*optional=*/true, "The number of block transactions of the last assembled block (only present if a block was ever assembled)"},
#     404                 :       1641 :                         {RPCResult::Type::NUM, "difficulty", "The current difficulty"},
#     405                 :       1641 :                         {RPCResult::Type::NUM, "networkhashps", "The network hashes per second"},
#     406                 :       1641 :                         {RPCResult::Type::NUM, "pooledtx", "The size of the mempool"},
#     407                 :       1641 :                         {RPCResult::Type::STR, "chain", "current network name (main, test, signet, regtest)"},
#     408                 :       1641 :                         {RPCResult::Type::STR, "warnings", "any network and blockchain warnings"},
#     409                 :       1641 :                     }},
#     410                 :       1641 :                 RPCExamples{
#     411                 :       1641 :                     HelpExampleCli("getmininginfo", "")
#     412                 :       1641 :             + HelpExampleRpc("getmininginfo", "")
#     413                 :       1641 :                 },
#     414                 :       1641 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
#     415                 :       1641 : {
#     416                 :          5 :     NodeContext& node = EnsureAnyNodeContext(request.context);
#     417                 :          5 :     const CTxMemPool& mempool = EnsureMemPool(node);
#     418                 :          5 :     ChainstateManager& chainman = EnsureChainman(node);
#     419                 :          5 :     LOCK(cs_main);
#     420                 :          5 :     const CChain& active_chain = chainman.ActiveChain();
#     421                 :            : 
#     422                 :          5 :     UniValue obj(UniValue::VOBJ);
#     423                 :          5 :     obj.pushKV("blocks",           active_chain.Height());
#     424         [ +  + ]:          5 :     if (BlockAssembler::m_last_block_weight) obj.pushKV("currentblockweight", *BlockAssembler::m_last_block_weight);
#     425         [ +  + ]:          5 :     if (BlockAssembler::m_last_block_num_txs) obj.pushKV("currentblocktx", *BlockAssembler::m_last_block_num_txs);
#     426                 :          5 :     obj.pushKV("difficulty",       (double)GetDifficulty(active_chain.Tip()));
#     427                 :          5 :     obj.pushKV("networkhashps",    getnetworkhashps().HandleRequest(request));
#     428                 :          5 :     obj.pushKV("pooledtx",         (uint64_t)mempool.size());
#     429                 :          5 :     obj.pushKV("chain", chainman.GetParams().NetworkIDString());
#     430                 :          5 :     obj.pushKV("warnings",         GetWarnings(false).original);
#     431                 :          5 :     return obj;
#     432                 :          5 : },
#     433                 :       1641 :     };
#     434                 :       1641 : }
#     435                 :            : 
#     436                 :            : 
#     437                 :            : // NOTE: Unlike wallet RPC (which use BTC values), mining RPCs follow GBT (BIP 22) in using satoshi amounts
#     438                 :            : static RPCHelpMan prioritisetransaction()
#     439                 :       2342 : {
#     440                 :       2342 :     return RPCHelpMan{"prioritisetransaction",
#     441                 :       2342 :                 "Accepts the transaction into mined blocks at a higher (or lower) priority\n",
#     442                 :       2342 :                 {
#     443                 :       2342 :                     {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id."},
#     444                 :       2342 :                     {"dummy", RPCArg::Type::NUM, RPCArg::Optional::OMITTED_NAMED_ARG, "API-Compatibility for previous API. Must be zero or null.\n"
#     445                 :       2342 :             "                  DEPRECATED. For forward compatibility use named arguments and omit this parameter."},
#     446                 :       2342 :                     {"fee_delta", RPCArg::Type::NUM, RPCArg::Optional::NO, "The fee value (in satoshis) to add (or subtract, if negative).\n"
#     447                 :       2342 :             "                  Note, that this value is not a fee rate. It is a value to modify absolute fee of the TX.\n"
#     448                 :       2342 :             "                  The fee is not actually paid, only the algorithm for selecting transactions into a block\n"
#     449                 :       2342 :             "                  considers the transaction as it would have paid a higher (or lower) fee."},
#     450                 :       2342 :                 },
#     451                 :       2342 :                 RPCResult{
#     452                 :       2342 :                     RPCResult::Type::BOOL, "", "Returns true"},
#     453                 :       2342 :                 RPCExamples{
#     454                 :       2342 :                     HelpExampleCli("prioritisetransaction", "\"txid\" 0.0 10000")
#     455                 :       2342 :             + HelpExampleRpc("prioritisetransaction", "\"txid\", 0.0, 10000")
#     456                 :       2342 :                 },
#     457                 :       2342 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
#     458                 :       2342 : {
#     459                 :        702 :     LOCK(cs_main);
#     460                 :            : 
#     461                 :        702 :     uint256 hash(ParseHashV(request.params[0], "txid"));
#     462                 :        702 :     CAmount nAmount = request.params[2].getInt<int64_t>();
#     463                 :            : 
#     464 [ +  + ][ +  + ]:        702 :     if (!(request.params[1].isNull() || request.params[1].get_real() == 0)) {
#     465                 :          1 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "Priority is no longer supported, dummy argument to prioritisetransaction must be 0.");
#     466                 :          1 :     }
#     467                 :            : 
#     468                 :        701 :     EnsureAnyMemPool(request.context).PrioritiseTransaction(hash, nAmount);
#     469                 :        701 :     return true;
#     470                 :        702 : },
#     471                 :       2342 :     };
#     472                 :       2342 : }
#     473                 :            : 
#     474                 :            : 
#     475                 :            : // NOTE: Assumes a conclusive result; if result is inconclusive, it must be handled by caller
#     476                 :            : static UniValue BIP22ValidationResult(const BlockValidationState& state)
#     477                 :       4116 : {
#     478         [ +  + ]:       4116 :     if (state.IsValid())
#     479                 :       1604 :         return UniValue::VNULL;
#     480                 :            : 
#     481         [ -  + ]:       2512 :     if (state.IsError())
#     482                 :          0 :         throw JSONRPCError(RPC_VERIFY_ERROR, state.ToString());
#     483         [ +  - ]:       2512 :     if (state.IsInvalid())
#     484                 :       2512 :     {
#     485                 :       2512 :         std::string strRejectReason = state.GetRejectReason();
#     486         [ -  + ]:       2512 :         if (strRejectReason.empty())
#     487                 :          0 :             return "rejected";
#     488                 :       2512 :         return strRejectReason;
#     489                 :       2512 :     }
#     490                 :            :     // Should be impossible
#     491                 :          0 :     return "valid?";
#     492                 :       2512 : }
#     493                 :            : 
#     494                 :       4087 : static std::string gbt_vb_name(const Consensus::DeploymentPos pos) {
#     495                 :       4087 :     const struct VBDeploymentInfo& vbinfo = VersionBitsDeploymentInfo[pos];
#     496                 :       4087 :     std::string s = vbinfo.name;
#     497         [ -  + ]:       4087 :     if (!vbinfo.gbt_force) {
#     498                 :          0 :         s.insert(s.begin(), '!');
#     499                 :          0 :     }
#     500                 :       4087 :     return s;
#     501                 :       4087 : }
#     502                 :            : 
#     503                 :            : static RPCHelpMan getblocktemplate()
#     504                 :       3697 : {
#     505                 :       3697 :     return RPCHelpMan{"getblocktemplate",
#     506                 :       3697 :         "\nIf the request parameters include a 'mode' key, that is used to explicitly select between the default 'template' request or a 'proposal'.\n"
#     507                 :       3697 :         "It returns data needed to construct a block to work on.\n"
#     508                 :       3697 :         "For full specification, see BIPs 22, 23, 9, and 145:\n"
#     509                 :       3697 :         "    https://github.com/bitcoin/bips/blob/master/bip-0022.mediawiki\n"
#     510                 :       3697 :         "    https://github.com/bitcoin/bips/blob/master/bip-0023.mediawiki\n"
#     511                 :       3697 :         "    https://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki#getblocktemplate_changes\n"
#     512                 :       3697 :         "    https://github.com/bitcoin/bips/blob/master/bip-0145.mediawiki\n",
#     513                 :       3697 :         {
#     514                 :       3697 :             {"template_request", RPCArg::Type::OBJ, RPCArg::Default{UniValue::VOBJ}, "Format of the template",
#     515                 :       3697 :             {
#     516                 :       3697 :                 {"mode", RPCArg::Type::STR, /* treat as named arg */ RPCArg::Optional::OMITTED_NAMED_ARG, "This must be set to \"template\", \"proposal\" (see BIP 23), or omitted"},
#     517                 :       3697 :                 {"capabilities", RPCArg::Type::ARR, /* treat as named arg */ RPCArg::Optional::OMITTED_NAMED_ARG, "A list of strings",
#     518                 :       3697 :                 {
#     519                 :       3697 :                     {"str", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "client side supported feature, 'longpoll', 'coinbasevalue', 'proposal', 'serverlist', 'workid'"},
#     520                 :       3697 :                 }},
#     521                 :       3697 :                 {"rules", RPCArg::Type::ARR, RPCArg::Optional::NO, "A list of strings",
#     522                 :       3697 :                 {
#     523                 :       3697 :                     {"segwit", RPCArg::Type::STR, RPCArg::Optional::NO, "(literal) indicates client side segwit support"},
#     524                 :       3697 :                     {"str", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "other client side supported softfork deployment"},
#     525                 :       3697 :                 }},
#     526                 :       3697 :             },
#     527                 :       3697 :                         "\"template_request\""},
#     528                 :       3697 :         },
#     529                 :       3697 :         {
#     530                 :       3697 :             RPCResult{"If the proposal was accepted with mode=='proposal'", RPCResult::Type::NONE, "", ""},
#     531                 :       3697 :             RPCResult{"If the proposal was not accepted with mode=='proposal'", RPCResult::Type::STR, "", "According to BIP22"},
#     532                 :       3697 :             RPCResult{"Otherwise", RPCResult::Type::OBJ, "", "",
#     533                 :       3697 :             {
#     534                 :       3697 :                 {RPCResult::Type::NUM, "version", "The preferred block version"},
#     535                 :       3697 :                 {RPCResult::Type::ARR, "rules", "specific block rules that are to be enforced",
#     536                 :       3697 :                 {
#     537                 :       3697 :                     {RPCResult::Type::STR, "", "name of a rule the client must understand to some extent; see BIP 9 for format"},
#     538                 :       3697 :                 }},
#     539                 :       3697 :                 {RPCResult::Type::OBJ_DYN, "vbavailable", "set of pending, supported versionbit (BIP 9) softfork deployments",
#     540                 :       3697 :                 {
#     541                 :       3697 :                     {RPCResult::Type::NUM, "rulename", "identifies the bit number as indicating acceptance and readiness for the named softfork rule"},
#     542                 :       3697 :                 }},
#     543                 :       3697 :                 {RPCResult::Type::ARR, "capabilities", "",
#     544                 :       3697 :                 {
#     545                 :       3697 :                     {RPCResult::Type::STR, "value", "A supported feature, for example 'proposal'"},
#     546                 :       3697 :                 }},
#     547                 :       3697 :                 {RPCResult::Type::NUM, "vbrequired", "bit mask of versionbits the server requires set in submissions"},
#     548                 :       3697 :                 {RPCResult::Type::STR, "previousblockhash", "The hash of current highest block"},
#     549                 :       3697 :                 {RPCResult::Type::ARR, "transactions", "contents of non-coinbase transactions that should be included in the next block",
#     550                 :       3697 :                 {
#     551                 :       3697 :                     {RPCResult::Type::OBJ, "", "",
#     552                 :       3697 :                     {
#     553                 :       3697 :                         {RPCResult::Type::STR_HEX, "data", "transaction data encoded in hexadecimal (byte-for-byte)"},
#     554                 :       3697 :                         {RPCResult::Type::STR_HEX, "txid", "transaction id encoded in little-endian hexadecimal"},
#     555                 :       3697 :                         {RPCResult::Type::STR_HEX, "hash", "hash encoded in little-endian hexadecimal (including witness data)"},
#     556                 :       3697 :                         {RPCResult::Type::ARR, "depends", "array of numbers",
#     557                 :       3697 :                         {
#     558                 :       3697 :                             {RPCResult::Type::NUM, "", "transactions before this one (by 1-based index in 'transactions' list) that must be present in the final block if this one is"},
#     559                 :       3697 :                         }},
#     560                 :       3697 :                         {RPCResult::Type::NUM, "fee", "difference in value between transaction inputs and outputs (in satoshis); for coinbase transactions, this is a negative Number of the total collected block fees (ie, not including the block subsidy); if key is not present, fee is unknown and clients MUST NOT assume there isn't one"},
#     561                 :       3697 :                         {RPCResult::Type::NUM, "sigops", "total SigOps cost, as counted for purposes of block limits; if key is not present, sigop cost is unknown and clients MUST NOT assume it is zero"},
#     562                 :       3697 :                         {RPCResult::Type::NUM, "weight", "total transaction weight, as counted for purposes of block limits"},
#     563                 :       3697 :                     }},
#     564                 :       3697 :                 }},
#     565                 :       3697 :                 {RPCResult::Type::OBJ_DYN, "coinbaseaux", "data that should be included in the coinbase's scriptSig content",
#     566                 :       3697 :                 {
#     567                 :       3697 :                     {RPCResult::Type::STR_HEX, "key", "values must be in the coinbase (keys may be ignored)"},
#     568                 :       3697 :                 }},
#     569                 :       3697 :                 {RPCResult::Type::NUM, "coinbasevalue", "maximum allowable input to coinbase transaction, including the generation award and transaction fees (in satoshis)"},
#     570                 :       3697 :                 {RPCResult::Type::STR, "longpollid", "an id to include with a request to longpoll on an update to this template"},
#     571                 :       3697 :                 {RPCResult::Type::STR, "target", "The hash target"},
#     572                 :       3697 :                 {RPCResult::Type::NUM_TIME, "mintime", "The minimum timestamp appropriate for the next block time, expressed in " + UNIX_EPOCH_TIME},
#     573                 :       3697 :                 {RPCResult::Type::ARR, "mutable", "list of ways the block template may be changed",
#     574                 :       3697 :                 {
#     575                 :       3697 :                     {RPCResult::Type::STR, "value", "A way the block template may be changed, e.g. 'time', 'transactions', 'prevblock'"},
#     576                 :       3697 :                 }},
#     577                 :       3697 :                 {RPCResult::Type::STR_HEX, "noncerange", "A range of valid nonces"},
#     578                 :       3697 :                 {RPCResult::Type::NUM, "sigoplimit", "limit of sigops in blocks"},
#     579                 :       3697 :                 {RPCResult::Type::NUM, "sizelimit", "limit of block size"},
#     580                 :       3697 :                 {RPCResult::Type::NUM, "weightlimit", /*optional=*/true, "limit of block weight"},
#     581                 :       3697 :                 {RPCResult::Type::NUM_TIME, "curtime", "current timestamp in " + UNIX_EPOCH_TIME},
#     582                 :       3697 :                 {RPCResult::Type::STR, "bits", "compressed target of next block"},
#     583                 :       3697 :                 {RPCResult::Type::NUM, "height", "The height of the next block"},
#     584                 :       3697 :                 {RPCResult::Type::STR_HEX, "signet_challenge", /*optional=*/true, "Only on signet"},
#     585                 :       3697 :                 {RPCResult::Type::STR_HEX, "default_witness_commitment", /*optional=*/true, "a valid witness commitment for the unmodified block template"},
#     586                 :       3697 :             }},
#     587                 :       3697 :         },
#     588                 :       3697 :         RPCExamples{
#     589                 :       3697 :                     HelpExampleCli("getblocktemplate", "'{\"rules\": [\"segwit\"]}'")
#     590                 :       3697 :             + HelpExampleRpc("getblocktemplate", "{\"rules\": [\"segwit\"]}")
#     591                 :       3697 :                 },
#     592                 :       3697 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
#     593                 :       3697 : {
#     594                 :       2061 :     NodeContext& node = EnsureAnyNodeContext(request.context);
#     595                 :       2061 :     ChainstateManager& chainman = EnsureChainman(node);
#     596                 :       2061 :     LOCK(cs_main);
#     597                 :            : 
#     598                 :       2061 :     std::string strMode = "template";
#     599                 :       2061 :     UniValue lpval = NullUniValue;
#     600                 :       2061 :     std::set<std::string> setClientRules;
#     601                 :       2061 :     CChainState& active_chainstate = chainman.ActiveChainstate();
#     602                 :       2061 :     CChain& active_chain = active_chainstate.m_chain;
#     603         [ +  + ]:       2061 :     if (!request.params[0].isNull())
#     604                 :       2060 :     {
#     605                 :       2060 :         const UniValue& oparam = request.params[0].get_obj();
#     606                 :       2060 :         const UniValue& modeval = find_value(oparam, "mode");
#     607         [ +  + ]:       2060 :         if (modeval.isStr())
#     608                 :         12 :             strMode = modeval.get_str();
#     609         [ +  - ]:       2048 :         else if (modeval.isNull())
#     610                 :       2048 :         {
#     611                 :            :             /* Do nothing */
#     612                 :       2048 :         }
#     613                 :          0 :         else
#     614                 :          0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode");
#     615                 :       2060 :         lpval = find_value(oparam, "longpollid");
#     616                 :            : 
#     617         [ +  + ]:       2060 :         if (strMode == "proposal")
#     618                 :         12 :         {
#     619                 :         12 :             const UniValue& dataval = find_value(oparam, "data");
#     620         [ -  + ]:         12 :             if (!dataval.isStr())
#     621                 :          0 :                 throw JSONRPCError(RPC_TYPE_ERROR, "Missing data String key for proposal");
#     622                 :            : 
#     623                 :         12 :             CBlock block;
#     624         [ +  + ]:         12 :             if (!DecodeHexBlk(block, dataval.get_str()))
#     625                 :          2 :                 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed");
#     626                 :            : 
#     627                 :         10 :             uint256 hash = block.GetHash();
#     628                 :         10 :             const CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(hash);
#     629         [ -  + ]:         10 :             if (pindex) {
#     630         [ #  # ]:          0 :                 if (pindex->IsValid(BLOCK_VALID_SCRIPTS))
#     631                 :          0 :                     return "duplicate";
#     632         [ #  # ]:          0 :                 if (pindex->nStatus & BLOCK_FAILED_MASK)
#     633                 :          0 :                     return "duplicate-invalid";
#     634                 :          0 :                 return "duplicate-inconclusive";
#     635                 :          0 :             }
#     636                 :            : 
#     637                 :         10 :             CBlockIndex* const pindexPrev = active_chain.Tip();
#     638                 :            :             // TestBlockValidity only supports blocks built on the current Tip
#     639         [ +  + ]:         10 :             if (block.hashPrevBlock != pindexPrev->GetBlockHash())
#     640                 :          1 :                 return "inconclusive-not-best-prevblk";
#     641                 :          9 :             BlockValidationState state;
#     642                 :          9 :             TestBlockValidity(state, chainman.GetParams(), active_chainstate, block, pindexPrev, GetAdjustedTime, false, true);
#     643                 :          9 :             return BIP22ValidationResult(state);
#     644                 :         10 :         }
#     645                 :            : 
#     646                 :       2048 :         const UniValue& aClientRules = find_value(oparam, "rules");
#     647         [ +  - ]:       2048 :         if (aClientRules.isArray()) {
#     648         [ +  + ]:       4098 :             for (unsigned int i = 0; i < aClientRules.size(); ++i) {
#     649                 :       2050 :                 const UniValue& v = aClientRules[i];
#     650                 :       2050 :                 setClientRules.insert(v.get_str());
#     651                 :       2050 :             }
#     652                 :       2048 :         }
#     653                 :       2048 :     }
#     654                 :            : 
#     655         [ -  + ]:       2049 :     if (strMode != "template")
#     656                 :          0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode");
#     657                 :            : 
#     658         [ -  + ]:       2049 :     if (!chainman.GetParams().IsTestChain()) {
#     659                 :          0 :         const CConnman& connman = EnsureConnman(node);
#     660         [ #  # ]:          0 :         if (connman.GetNodeCount(ConnectionDirection::Both) == 0) {
#     661                 :          0 :             throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, PACKAGE_NAME " is not connected!");
#     662                 :          0 :         }
#     663                 :            : 
#     664         [ #  # ]:          0 :         if (active_chainstate.IsInitialBlockDownload()) {
#     665                 :          0 :             throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, PACKAGE_NAME " is in initial sync and waiting for blocks...");
#     666                 :          0 :         }
#     667                 :          0 :     }
#     668                 :            : 
#     669                 :       2049 :     static unsigned int nTransactionsUpdatedLast;
#     670                 :       2049 :     const CTxMemPool& mempool = EnsureMemPool(node);
#     671                 :            : 
#     672         [ +  + ]:       2049 :     if (!lpval.isNull())
#     673                 :          3 :     {
#     674                 :            :         // Wait to respond until either the best block changes, OR a minute has passed and there are more transactions
#     675                 :          3 :         uint256 hashWatchedChain;
#     676                 :          3 :         std::chrono::steady_clock::time_point checktxtime;
#     677                 :          3 :         unsigned int nTransactionsUpdatedLastLP;
#     678                 :            : 
#     679         [ +  - ]:          3 :         if (lpval.isStr())
#     680                 :          3 :         {
#     681                 :            :             // Format: <hashBestChain><nTransactionsUpdatedLast>
#     682                 :          3 :             const std::string& lpstr = lpval.get_str();
#     683                 :            : 
#     684                 :          3 :             hashWatchedChain = ParseHashV(lpstr.substr(0, 64), "longpollid");
#     685                 :          3 :             nTransactionsUpdatedLastLP = LocaleIndependentAtoi<int64_t>(lpstr.substr(64));
#     686                 :          3 :         }
#     687                 :          0 :         else
#     688                 :          0 :         {
#     689                 :            :             // NOTE: Spec does not specify behaviour for non-string longpollid, but this makes testing easier
#     690                 :          0 :             hashWatchedChain = active_chain.Tip()->GetBlockHash();
#     691                 :          0 :             nTransactionsUpdatedLastLP = nTransactionsUpdatedLast;
#     692                 :          0 :         }
#     693                 :            : 
#     694                 :            :         // Release lock while waiting
#     695                 :          3 :         LEAVE_CRITICAL_SECTION(cs_main);
#     696                 :          3 :         {
#     697                 :          3 :             checktxtime = std::chrono::steady_clock::now() + std::chrono::minutes(1);
#     698                 :            : 
#     699                 :          3 :             WAIT_LOCK(g_best_block_mutex, lock);
#     700 [ +  + ][ +  - ]:          5 :             while (g_best_block == hashWatchedChain && IsRPCRunning())
#     701                 :          3 :             {
#     702         [ +  + ]:          3 :                 if (g_best_block_cv.wait_until(lock, checktxtime) == std::cv_status::timeout)
#     703                 :          1 :                 {
#     704                 :            :                     // Timeout: Check transactions for update
#     705                 :            :                     // without holding the mempool lock to avoid deadlocks
#     706         [ +  - ]:          1 :                     if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLastLP)
#     707                 :          1 :                         break;
#     708                 :          0 :                     checktxtime += std::chrono::seconds(10);
#     709                 :          0 :                 }
#     710                 :          3 :             }
#     711                 :          3 :         }
#     712                 :          3 :         ENTER_CRITICAL_SECTION(cs_main);
#     713                 :            : 
#     714         [ -  + ]:          3 :         if (!IsRPCRunning())
#     715                 :          0 :             throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Shutting down");
#     716                 :            :         // TODO: Maybe recheck connections/IBD and (if something wrong) send an expires-immediately template to stop miners?
#     717                 :          3 :     }
#     718                 :            : 
#     719                 :       2049 :     const Consensus::Params& consensusParams = chainman.GetParams().GetConsensus();
#     720                 :            : 
#     721                 :            :     // GBT must be called with 'signet' set in the rules for signet chains
#     722 [ +  + ][ -  + ]:       2049 :     if (consensusParams.signet_blocks && setClientRules.count("signet") != 1) {
#                 [ -  + ]
#     723                 :          0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "getblocktemplate must be called with the signet rule set (call with {\"rules\": [\"segwit\", \"signet\"]})");
#     724                 :          0 :     }
#     725                 :            : 
#     726                 :            :     // GBT must be called with 'segwit' set in the rules
#     727         [ +  + ]:       2049 :     if (setClientRules.count("segwit") != 1) {
#     728                 :          1 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "getblocktemplate must be called with the segwit rule set (call with {\"rules\": [\"segwit\"]})");
#     729                 :          1 :     }
#     730                 :            : 
#     731                 :            :     // Update block
#     732                 :       2048 :     static CBlockIndex* pindexPrev;
#     733                 :       2048 :     static int64_t nStart;
#     734                 :       2048 :     static std::unique_ptr<CBlockTemplate> pblocktemplate;
#     735         [ +  + ]:       2048 :     if (pindexPrev != active_chain.Tip() ||
#     736 [ +  + ][ +  + ]:       2048 :         (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 5))
#     737                 :         41 :     {
#     738                 :            :         // Clear pindexPrev so future calls make a new block, despite any failures from here on
#     739                 :         41 :         pindexPrev = nullptr;
#     740                 :            : 
#     741                 :            :         // Store the pindexBest used before CreateNewBlock, to avoid races
#     742                 :         41 :         nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
#     743                 :         41 :         CBlockIndex* pindexPrevNew = active_chain.Tip();
#     744                 :         41 :         nStart = GetTime();
#     745                 :            : 
#     746                 :            :         // Create new block
#     747                 :         41 :         CScript scriptDummy = CScript() << OP_TRUE;
#     748                 :         41 :         pblocktemplate = BlockAssembler{active_chainstate, &mempool}.CreateNewBlock(scriptDummy);
#     749         [ -  + ]:         41 :         if (!pblocktemplate)
#     750                 :          0 :             throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory");
#     751                 :            : 
#     752                 :            :         // Need to update only after we know CreateNewBlock succeeded
#     753                 :         41 :         pindexPrev = pindexPrevNew;
#     754                 :         41 :     }
#     755                 :       2048 :     CHECK_NONFATAL(pindexPrev);
#     756                 :       2048 :     CBlock* pblock = &pblocktemplate->block; // pointer for convenience
#     757                 :            : 
#     758                 :            :     // Update nTime
#     759                 :       2048 :     UpdateTime(pblock, consensusParams, pindexPrev);
#     760                 :       2048 :     pblock->nNonce = 0;
#     761                 :            : 
#     762                 :            :     // NOTE: If at some point we support pre-segwit miners post-segwit-activation, this needs to take segwit support into consideration
#     763                 :       2048 :     const bool fPreSegWit = !DeploymentActiveAfter(pindexPrev, chainman, Consensus::DEPLOYMENT_SEGWIT);
#     764                 :            : 
#     765                 :       2048 :     UniValue aCaps(UniValue::VARR); aCaps.push_back("proposal");
#     766                 :            : 
#     767                 :       2048 :     UniValue transactions(UniValue::VARR);
#     768                 :       2048 :     std::map<uint256, int64_t> setTxIndex;
#     769                 :       2048 :     int i = 0;
#     770         [ +  + ]:       2097 :     for (const auto& it : pblock->vtx) {
#     771                 :       2097 :         const CTransaction& tx = *it;
#     772                 :       2097 :         uint256 txHash = tx.GetHash();
#     773                 :       2097 :         setTxIndex[txHash] = i++;
#     774                 :            : 
#     775         [ +  + ]:       2097 :         if (tx.IsCoinBase())
#     776                 :       2048 :             continue;
#     777                 :            : 
#     778                 :         49 :         UniValue entry(UniValue::VOBJ);
#     779                 :            : 
#     780                 :         49 :         entry.pushKV("data", EncodeHexTx(tx));
#     781                 :         49 :         entry.pushKV("txid", txHash.GetHex());
#     782                 :         49 :         entry.pushKV("hash", tx.GetWitnessHash().GetHex());
#     783                 :            : 
#     784                 :         49 :         UniValue deps(UniValue::VARR);
#     785         [ +  + ]:         49 :         for (const CTxIn &in : tx.vin)
#     786                 :         71 :         {
#     787         [ +  + ]:         71 :             if (setTxIndex.count(in.prevout.hash))
#     788                 :          6 :                 deps.push_back(setTxIndex[in.prevout.hash]);
#     789                 :         71 :         }
#     790                 :         49 :         entry.pushKV("depends", deps);
#     791                 :            : 
#     792                 :         49 :         int index_in_template = i - 1;
#     793                 :         49 :         entry.pushKV("fee", pblocktemplate->vTxFees[index_in_template]);
#     794                 :         49 :         int64_t nTxSigOps = pblocktemplate->vTxSigOpsCost[index_in_template];
#     795         [ +  + ]:         49 :         if (fPreSegWit) {
#     796                 :          5 :             CHECK_NONFATAL(nTxSigOps % WITNESS_SCALE_FACTOR == 0);
#     797                 :          5 :             nTxSigOps /= WITNESS_SCALE_FACTOR;
#     798                 :          5 :         }
#     799                 :         49 :         entry.pushKV("sigops", nTxSigOps);
#     800                 :         49 :         entry.pushKV("weight", GetTransactionWeight(tx));
#     801                 :            : 
#     802                 :         49 :         transactions.push_back(entry);
#     803                 :         49 :     }
#     804                 :            : 
#     805                 :       2048 :     UniValue aux(UniValue::VOBJ);
#     806                 :            : 
#     807                 :       2048 :     arith_uint256 hashTarget = arith_uint256().SetCompact(pblock->nBits);
#     808                 :            : 
#     809                 :       2048 :     UniValue aMutable(UniValue::VARR);
#     810                 :       2048 :     aMutable.push_back("time");
#     811                 :       2048 :     aMutable.push_back("transactions");
#     812                 :       2048 :     aMutable.push_back("prevblock");
#     813                 :            : 
#     814                 :       2048 :     UniValue result(UniValue::VOBJ);
#     815                 :       2048 :     result.pushKV("capabilities", aCaps);
#     816                 :            : 
#     817                 :       2048 :     UniValue aRules(UniValue::VARR);
#     818                 :       2048 :     aRules.push_back("csv");
#     819         [ +  + ]:       2048 :     if (!fPreSegWit) aRules.push_back("!segwit");
#     820         [ +  + ]:       2048 :     if (consensusParams.signet_blocks) {
#     821                 :            :         // indicate to miner that they must understand signet rules
#     822                 :            :         // when attempting to mine with this template
#     823                 :          2 :         aRules.push_back("!signet");
#     824                 :          2 :     }
#     825                 :            : 
#     826                 :       2048 :     UniValue vbavailable(UniValue::VOBJ);
#     827         [ +  + ]:       6144 :     for (int j = 0; j < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++j) {
#     828                 :       4096 :         Consensus::DeploymentPos pos = Consensus::DeploymentPos(j);
#     829                 :       4096 :         ThresholdState state = chainman.m_versionbitscache.State(pindexPrev, consensusParams, pos);
#     830         [ -  + ]:       4096 :         switch (state) {
#     831         [ +  + ]:          7 :             case ThresholdState::DEFINED:
#     832         [ +  + ]:          9 :             case ThresholdState::FAILED:
#     833                 :            :                 // Not exposed to GBT at all
#     834                 :          9 :                 break;
#     835         [ +  + ]:          8 :             case ThresholdState::LOCKED_IN:
#     836                 :            :                 // Ensure bit is set in block version
#     837                 :          8 :                 pblock->nVersion |= chainman.m_versionbitscache.Mask(consensusParams, pos);
#     838                 :          8 :                 [[fallthrough]];
#     839         [ +  + ]:         39 :             case ThresholdState::STARTED:
#     840                 :         39 :             {
#     841                 :         39 :                 const struct VBDeploymentInfo& vbinfo = VersionBitsDeploymentInfo[pos];
#     842                 :         39 :                 vbavailable.pushKV(gbt_vb_name(pos), consensusParams.vDeployments[pos].bit);
#     843         [ +  - ]:         39 :                 if (setClientRules.find(vbinfo.name) == setClientRules.end()) {
#     844         [ -  + ]:         39 :                     if (!vbinfo.gbt_force) {
#     845                 :            :                         // If the client doesn't support this, don't indicate it in the [default] version
#     846                 :          0 :                         pblock->nVersion &= ~chainman.m_versionbitscache.Mask(consensusParams, pos);
#     847                 :          0 :                     }
#     848                 :         39 :                 }
#     849                 :         39 :                 break;
#     850                 :          8 :             }
#     851         [ +  + ]:       4048 :             case ThresholdState::ACTIVE:
#     852                 :       4048 :             {
#     853                 :            :                 // Add to rules only
#     854                 :       4048 :                 const struct VBDeploymentInfo& vbinfo = VersionBitsDeploymentInfo[pos];
#     855                 :       4048 :                 aRules.push_back(gbt_vb_name(pos));
#     856         [ +  - ]:       4048 :                 if (setClientRules.find(vbinfo.name) == setClientRules.end()) {
#     857                 :            :                     // Not supported by the client; make sure it's safe to proceed
#     858         [ -  + ]:       4048 :                     if (!vbinfo.gbt_force) {
#     859                 :          0 :                         throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Support for '%s' rule requires explicit client support", vbinfo.name));
#     860                 :          0 :                     }
#     861                 :       4048 :                 }
#     862                 :       4048 :                 break;
#     863                 :       4048 :             }
#     864                 :       4096 :         }
#     865                 :       4096 :     }
#     866                 :       2048 :     result.pushKV("version", pblock->nVersion);
#     867                 :       2048 :     result.pushKV("rules", aRules);
#     868                 :       2048 :     result.pushKV("vbavailable", vbavailable);
#     869                 :       2048 :     result.pushKV("vbrequired", int(0));
#     870                 :            : 
#     871                 :       2048 :     result.pushKV("previousblockhash", pblock->hashPrevBlock.GetHex());
#     872                 :       2048 :     result.pushKV("transactions", transactions);
#     873                 :       2048 :     result.pushKV("coinbaseaux", aux);
#     874                 :       2048 :     result.pushKV("coinbasevalue", (int64_t)pblock->vtx[0]->vout[0].nValue);
#     875                 :       2048 :     result.pushKV("longpollid", active_chain.Tip()->GetBlockHash().GetHex() + ToString(nTransactionsUpdatedLast));
#     876                 :       2048 :     result.pushKV("target", hashTarget.GetHex());
#     877                 :       2048 :     result.pushKV("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1);
#     878                 :       2048 :     result.pushKV("mutable", aMutable);
#     879                 :       2048 :     result.pushKV("noncerange", "00000000ffffffff");
#     880                 :       2048 :     int64_t nSigOpLimit = MAX_BLOCK_SIGOPS_COST;
#     881                 :       2048 :     int64_t nSizeLimit = MAX_BLOCK_SERIALIZED_SIZE;
#     882         [ +  + ]:       2048 :     if (fPreSegWit) {
#     883                 :          4 :         CHECK_NONFATAL(nSigOpLimit % WITNESS_SCALE_FACTOR == 0);
#     884                 :          4 :         nSigOpLimit /= WITNESS_SCALE_FACTOR;
#     885                 :          4 :         CHECK_NONFATAL(nSizeLimit % WITNESS_SCALE_FACTOR == 0);
#     886                 :          4 :         nSizeLimit /= WITNESS_SCALE_FACTOR;
#     887                 :          4 :     }
#     888                 :       2048 :     result.pushKV("sigoplimit", nSigOpLimit);
#     889                 :       2048 :     result.pushKV("sizelimit", nSizeLimit);
#     890         [ +  + ]:       2048 :     if (!fPreSegWit) {
#     891                 :       2044 :         result.pushKV("weightlimit", (int64_t)MAX_BLOCK_WEIGHT);
#     892                 :       2044 :     }
#     893                 :       2048 :     result.pushKV("curtime", pblock->GetBlockTime());
#     894                 :       2048 :     result.pushKV("bits", strprintf("%08x", pblock->nBits));
#     895                 :       2048 :     result.pushKV("height", (int64_t)(pindexPrev->nHeight+1));
#     896                 :            : 
#     897         [ +  + ]:       2048 :     if (consensusParams.signet_blocks) {
#     898                 :          2 :         result.pushKV("signet_challenge", HexStr(consensusParams.signet_challenge));
#     899                 :          2 :     }
#     900                 :            : 
#     901         [ +  - ]:       2048 :     if (!pblocktemplate->vchCoinbaseCommitment.empty()) {
#     902                 :       2048 :         result.pushKV("default_witness_commitment", HexStr(pblocktemplate->vchCoinbaseCommitment));
#     903                 :       2048 :     }
#     904                 :            : 
#     905                 :       2048 :     return result;
#     906                 :       2048 : },
#     907                 :       3697 :     };
#     908                 :       3697 : }
#     909                 :            : 
#     910                 :            : class submitblock_StateCatcher final : public CValidationInterface
#     911                 :            : {
#     912                 :            : public:
#     913                 :            :     uint256 hash;
#     914                 :            :     bool found{false};
#     915                 :            :     BlockValidationState state;
#     916                 :            : 
#     917                 :       4126 :     explicit submitblock_StateCatcher(const uint256 &hashIn) : hash(hashIn), state() {}
#     918                 :            : 
#     919                 :            : protected:
#     920                 :       4110 :     void BlockChecked(const CBlock& block, const BlockValidationState& stateIn) override {
#     921         [ +  + ]:       4110 :         if (block.GetHash() != hash)
#     922                 :          3 :             return;
#     923                 :       4107 :         found = true;
#     924                 :       4107 :         state = stateIn;
#     925                 :       4107 :     }
#     926                 :            : };
#     927                 :            : 
#     928                 :            : static RPCHelpMan submitblock()
#     929                 :       5857 : {
#     930                 :            :     // We allow 2 arguments for compliance with BIP22. Argument 2 is ignored.
#     931                 :       5857 :     return RPCHelpMan{"submitblock",
#     932                 :       5857 :         "\nAttempts to submit new block to network.\n"
#     933                 :       5857 :         "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.\n",
#     934                 :       5857 :         {
#     935                 :       5857 :             {"hexdata", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hex-encoded block data to submit"},
#     936                 :       5857 :             {"dummy", RPCArg::Type::STR, RPCArg::DefaultHint{"ignored"}, "dummy value, for compatibility with BIP22. This value is ignored."},
#     937                 :       5857 :         },
#     938                 :       5857 :         {
#     939                 :       5857 :             RPCResult{"If the block was accepted", RPCResult::Type::NONE, "", ""},
#     940                 :       5857 :             RPCResult{"Otherwise", RPCResult::Type::STR, "", "According to BIP22"},
#     941                 :       5857 :         },
#     942                 :       5857 :         RPCExamples{
#     943                 :       5857 :                     HelpExampleCli("submitblock", "\"mydata\"")
#     944                 :       5857 :             + HelpExampleRpc("submitblock", "\"mydata\"")
#     945                 :       5857 :                 },
#     946                 :       5857 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
#     947                 :       5857 : {
#     948                 :       4221 :     std::shared_ptr<CBlock> blockptr = std::make_shared<CBlock>();
#     949                 :       4221 :     CBlock& block = *blockptr;
#     950         [ +  + ]:       4221 :     if (!DecodeHexBlk(block, request.params[0].get_str())) {
#     951                 :          1 :         throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed");
#     952                 :          1 :     }
#     953                 :            : 
#     954 [ -  + ][ +  + ]:       4220 :     if (block.vtx.empty() || !block.vtx[0]->IsCoinBase()) {
#     955                 :          1 :         throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block does not start with a coinbase");
#     956                 :          1 :     }
#     957                 :            : 
#     958                 :       4219 :     ChainstateManager& chainman = EnsureAnyChainman(request.context);
#     959                 :       4219 :     uint256 hash = block.GetHash();
#     960                 :       4219 :     {
#     961                 :       4219 :         LOCK(cs_main);
#     962                 :       4219 :         const CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(hash);
#     963         [ +  + ]:       4219 :         if (pindex) {
#     964         [ +  + ]:         98 :             if (pindex->IsValid(BLOCK_VALID_SCRIPTS)) {
#     965                 :         90 :                 return "duplicate";
#     966                 :         90 :             }
#     967         [ +  + ]:          8 :             if (pindex->nStatus & BLOCK_FAILED_MASK) {
#     968                 :          3 :                 return "duplicate-invalid";
#     969                 :          3 :             }
#     970                 :          8 :         }
#     971                 :       4219 :     }
#     972                 :            : 
#     973                 :       4126 :     {
#     974                 :       4126 :         LOCK(cs_main);
#     975                 :       4126 :         const CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock);
#     976         [ +  + ]:       4126 :         if (pindex) {
#     977                 :       4123 :             chainman.UpdateUncommittedBlockStructures(block, pindex);
#     978                 :       4123 :         }
#     979                 :       4126 :     }
#     980                 :            : 
#     981                 :       4126 :     bool new_block;
#     982                 :       4126 :     auto sc = std::make_shared<submitblock_StateCatcher>(block.GetHash());
#     983                 :       4126 :     RegisterSharedValidationInterface(sc);
#     984                 :       4126 :     bool accepted = chainman.ProcessNewBlock(blockptr, /*force_processing=*/true, /*min_pow_checked=*/true, /*new_block=*/&new_block);
#     985                 :       4126 :     UnregisterSharedValidationInterface(sc);
#     986 [ +  + ][ +  + ]:       4126 :     if (!new_block && accepted) {
#     987                 :          1 :         return "duplicate";
#     988                 :          1 :     }
#     989         [ +  + ]:       4125 :     if (!sc->found) {
#     990                 :         18 :         return "inconclusive";
#     991                 :         18 :     }
#     992                 :       4107 :     return BIP22ValidationResult(sc->state);
#     993                 :       4125 : },
#     994                 :       5857 :     };
#     995                 :       5857 : }
#     996                 :            : 
#     997                 :            : static RPCHelpMan submitheader()
#     998                 :       1649 : {
#     999                 :       1649 :     return RPCHelpMan{"submitheader",
#    1000                 :       1649 :                 "\nDecode the given hexdata as a header and submit it as a candidate chain tip if valid."
#    1001                 :       1649 :                 "\nThrows when the header is invalid.\n",
#    1002                 :       1649 :                 {
#    1003                 :       1649 :                     {"hexdata", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hex-encoded block header data"},
#    1004                 :       1649 :                 },
#    1005                 :       1649 :                 RPCResult{
#    1006                 :       1649 :                     RPCResult::Type::NONE, "", "None"},
#    1007                 :       1649 :                 RPCExamples{
#    1008                 :       1649 :                     HelpExampleCli("submitheader", "\"aabbcc\"") +
#    1009                 :       1649 :                     HelpExampleRpc("submitheader", "\"aabbcc\"")
#    1010                 :       1649 :                 },
#    1011                 :       1649 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
#    1012                 :       1649 : {
#    1013                 :         13 :     CBlockHeader h;
#    1014         [ +  + ]:         13 :     if (!DecodeHexBlockHeader(h, request.params[0].get_str())) {
#    1015                 :          2 :         throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block header decode failed");
#    1016                 :          2 :     }
#    1017                 :         11 :     ChainstateManager& chainman = EnsureAnyChainman(request.context);
#    1018                 :         11 :     {
#    1019                 :         11 :         LOCK(cs_main);
#    1020         [ +  + ]:         11 :         if (!chainman.m_blockman.LookupBlockIndex(h.hashPrevBlock)) {
#    1021                 :          1 :             throw JSONRPCError(RPC_VERIFY_ERROR, "Must submit previous header (" + h.hashPrevBlock.GetHex() + ") first");
#    1022                 :          1 :         }
#    1023                 :         11 :     }
#    1024                 :            : 
#    1025                 :         10 :     BlockValidationState state;
#    1026                 :         10 :     chainman.ProcessNewBlockHeaders({h}, /*min_pow_checked=*/true, state);
#    1027         [ +  + ]:         10 :     if (state.IsValid()) return UniValue::VNULL;
#    1028         [ -  + ]:          4 :     if (state.IsError()) {
#    1029                 :          0 :         throw JSONRPCError(RPC_VERIFY_ERROR, state.ToString());
#    1030                 :          0 :     }
#    1031                 :          4 :     throw JSONRPCError(RPC_VERIFY_ERROR, state.GetRejectReason());
#    1032                 :          4 : },
#    1033                 :       1649 :     };
#    1034                 :       1649 : }
#    1035                 :            : 
#    1036                 :            : void RegisterMiningRPCCommands(CRPCTable& t)
#    1037                 :       1022 : {
#    1038                 :       1022 :     static const CRPCCommand commands[]{
#    1039                 :       1022 :         {"mining", &getnetworkhashps},
#    1040                 :       1022 :         {"mining", &getmininginfo},
#    1041                 :       1022 :         {"mining", &prioritisetransaction},
#    1042                 :       1022 :         {"mining", &getblocktemplate},
#    1043                 :       1022 :         {"mining", &submitblock},
#    1044                 :       1022 :         {"mining", &submitheader},
#    1045                 :            : 
#    1046                 :       1022 :         {"hidden", &generatetoaddress},
#    1047                 :       1022 :         {"hidden", &generatetodescriptor},
#    1048                 :       1022 :         {"hidden", &generateblock},
#    1049                 :       1022 :         {"hidden", &generate},
#    1050                 :       1022 :     };
#    1051         [ +  + ]:      10220 :     for (const auto& c : commands) {
#    1052                 :      10220 :         t.appendCommand(c.name, &c);
#    1053                 :      10220 :     }
#    1054                 :       1022 : }

Generated by: LCOV version 0-eol-96201-ge66f56f4af6a