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