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