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