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