LCOV - code coverage report
Current view: top level - src/rpc - mining.cpp (source / functions) Hit Total Coverage
Test: fuzz_coverage.info Lines: 221 719 30.7 %
Date: 2023-11-10 23:46:46 Functions: 12 36 33.3 %
Branches: 462 2269 20.4 %

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

Generated by: LCOV version 1.14