LCOV - code coverage report
Current view: top level - src/rpc - mining.cpp (source / functions) Hit Total Coverage
Test: test_dash_coverage.info Lines: 216 692 31.2 %
Date: 2026-06-25 07:23:51 Functions: 12 33 36.4 %

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

Generated by: LCOV version 1.16