LCOV - code coverage report
Current view: top level - src/rpc - mining.cpp (source / functions) Hit Total Coverage
Test: fuzz_coverage.info Lines: 1 720 0.1 %
Date: 2024-01-03 14:57:27 Functions: 0 33 0.0 %
Branches: 0 2283 0.0 %

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

Generated by: LCOV version 1.14