Line data Source code
1 : // Copyright (c) 2010 Satoshi Nakamoto
2 : // Copyright (c) 2009-2014 The Bitcoin developers
3 : // Copyright (c) 2014-2015 The Dash developers
4 : // Copyright (c) 2015-2022 The PIVX Core developers
5 : // Distributed under the MIT software license, see the accompanying
6 : // file COPYING or https://www.opensource.org/licenses/mit-license.php.
7 :
8 : #include "budget/budgetmanager.h"
9 : #include "chainparams.h"
10 : #include "checkpoints.h"
11 : #include "clientversion.h"
12 : #include "consensus/upgrades.h"
13 : #include "core_io.h"
14 : #include "hash.h"
15 : #include "kernel.h"
16 : #include "key_io.h"
17 : #include "llmq/quorums_chainlocks.h"
18 : #include "masternodeman.h"
19 : #include "policy/feerate.h"
20 : #include "policy/policy.h"
21 : #include "rpc/server.h"
22 : #include "script/descriptor.h"
23 : #include "sync.h"
24 : #include "txdb.h"
25 : #include "util/system.h"
26 : #include "utilmoneystr.h"
27 : #include "utilstrencodings.h"
28 : #include "validation.h"
29 : #include "validationinterface.h"
30 : #include "wallet/wallet.h"
31 : #include "warnings.h"
32 :
33 : #include <stdint.h>
34 : #include <univalue.h>
35 : #include <numeric>
36 : #include <condition_variable>
37 :
38 : #include <boost/thread/thread.hpp> // boost::thread::interrupt
39 :
40 :
41 8 : struct CUpdatedBlock
42 : {
43 : uint256 hash;
44 : int height;
45 : };
46 : static std::mutex cs_blockchange;
47 : static std::condition_variable cond_blockchange;
48 : static CUpdatedBlock latestblock;
49 :
50 : extern void TxToJSON(CWallet* const pwallet, const CTransaction& tx, const CBlockIndex* tip, const CBlockIndex* blockindex, UniValue& entry);
51 :
52 2223 : UniValue syncwithvalidationinterfacequeue(const JSONRPCRequest& request)
53 : {
54 2223 : if (request.fHelp || request.params.size() > 0) {
55 0 : throw std::runtime_error(
56 : "syncwithvalidationinterfacequeue\n"
57 : "\nWaits for the validation interface queue to catch up on everything that was there when we entered this function.\n"
58 : "\nExamples:\n"
59 0 : + HelpExampleCli("syncwithvalidationinterfacequeue","")
60 0 : + HelpExampleRpc("syncwithvalidationinterfacequeue","")
61 0 : );
62 : }
63 2223 : SyncWithValidationInterfaceQueue();
64 2223 : return NullUniValue;
65 : }
66 :
67 400 : double GetDifficulty(const CBlockIndex* blockindex)
68 : {
69 : // Floating point number that is a multiple of the minimum difficulty,
70 : // minimum difficulty = 1.0.
71 400 : if (blockindex == nullptr) {
72 19 : const CBlockIndex* pChainTip = GetChainTip();
73 19 : if (!pChainTip)
74 : return 1.0;
75 : else
76 : blockindex = pChainTip;
77 : }
78 :
79 400 : int nShift = (blockindex->nBits >> 24) & 0xff;
80 :
81 400 : double dDiff =
82 400 : (double)0x0000ffff / (double)(blockindex->nBits & 0x00ffffff);
83 :
84 400 : while (nShift < 29) {
85 0 : dDiff *= 256.0;
86 0 : nShift++;
87 : }
88 1600 : while (nShift > 29) {
89 1200 : dDiff /= 256.0;
90 1200 : nShift--;
91 : }
92 :
93 : return dDiff;
94 : }
95 :
96 38 : static UniValue ValuePoolDesc(
97 : const Optional<CAmount> chainValue,
98 : const Optional<CAmount> valueDelta)
99 : {
100 38 : UniValue rv(UniValue::VOBJ);
101 76 : rv.pushKV("chainValue", ValueFromAmount(chainValue ? *chainValue : 0));
102 76 : rv.pushKV("valueDelta", ValueFromAmount(valueDelta ? *valueDelta : 0));
103 38 : return rv;
104 : }
105 :
106 1247 : int ComputeNextBlockAndDepth(const CBlockIndex* tip, const CBlockIndex* blockindex, const CBlockIndex*& next)
107 : {
108 1247 : next = tip->GetAncestor(blockindex->nHeight + 1);
109 1247 : if (next && next->pprev == blockindex) {
110 986 : return tip->nHeight - blockindex->nHeight + 1;
111 : }
112 261 : next = nullptr;
113 261 : return blockindex == tip ? 1 : -1;
114 : }
115 :
116 8 : UniValue blockheaderToJSON(const CBlockIndex* tip, const CBlockIndex* blockindex)
117 : {
118 8 : UniValue result(UniValue::VOBJ);
119 16 : result.pushKV("hash", blockindex->GetBlockHash().GetHex());
120 8 : const CBlockIndex* pnext;
121 8 : int confirmations = ComputeNextBlockAndDepth(tip, blockindex, pnext);
122 8 : result.pushKV("confirmations", confirmations);
123 8 : result.pushKV("height", blockindex->nHeight);
124 8 : result.pushKV("version", blockindex->nVersion);
125 16 : result.pushKV("merkleroot", blockindex->hashMerkleRoot.GetHex());
126 8 : result.pushKV("time", (int64_t)blockindex->nTime);
127 8 : result.pushKV("mediantime", (int64_t)blockindex->GetMedianTimePast());
128 8 : result.pushKV("nonce", (uint64_t)blockindex->nNonce);
129 16 : result.pushKV("bits", strprintf("%08x", blockindex->nBits));
130 8 : result.pushKV("difficulty", GetDifficulty(blockindex));
131 16 : result.pushKV("chainwork", blockindex->nChainWork.GetHex());
132 16 : result.pushKV("acc_checkpoint", blockindex->nAccumulatorCheckpoint.GetHex());
133 : // Sapling shield pool value
134 16 : result.pushKV("shield_pool_value", ValuePoolDesc(blockindex->nChainSaplingValue, blockindex->nSaplingValue));
135 8 : if (blockindex->pprev)
136 24 : result.pushKV("previousblockhash", blockindex->pprev->GetBlockHash().GetHex());
137 8 : if (pnext)
138 18 : result.pushKV("nextblockhash", pnext->GetBlockHash().GetHex());
139 8 : result.pushKV("chainlock", llmq::chainLocksHandler->HasChainLock(blockindex->nHeight, blockindex->GetBlockHash()));
140 8 : return result;
141 : }
142 :
143 373 : UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, bool txDetails = false)
144 : {
145 373 : UniValue result(UniValue::VOBJ);
146 746 : result.pushKV("hash", block.GetHash().GetHex());
147 373 : const CBlockIndex* pnext;
148 373 : int confirmations = ComputeNextBlockAndDepth(tip, blockindex, pnext);
149 373 : result.pushKV("confirmations", confirmations);
150 373 : result.pushKV("size", (int)::GetSerializeSize(block, PROTOCOL_VERSION));
151 373 : result.pushKV("height", blockindex->nHeight);
152 373 : result.pushKV("version", block.nVersion);
153 746 : result.pushKV("merkleroot", block.hashMerkleRoot.GetHex());
154 746 : result.pushKV("acc_checkpoint", block.nAccumulatorCheckpoint.GetHex());
155 746 : result.pushKV("finalsaplingroot", block.hashFinalSaplingRoot.GetHex());
156 373 : UniValue txs(UniValue::VARR);
157 5109 : for (const auto& txIn : block.vtx) {
158 4736 : const CTransaction& tx = *txIn;
159 4736 : if (txDetails) {
160 14 : UniValue objTx(UniValue::VOBJ);
161 7 : TxToJSON(nullptr, tx, nullptr, nullptr, objTx);
162 7 : txs.push_back(objTx);
163 : } else
164 9458 : txs.push_back(tx.GetHash().GetHex());
165 : }
166 373 : result.pushKV("tx", txs);
167 373 : result.pushKV("time", block.GetBlockTime());
168 373 : result.pushKV("mediantime", (int64_t)blockindex->GetMedianTimePast());
169 373 : result.pushKV("nonce", (uint64_t)block.nNonce);
170 746 : result.pushKV("bits", strprintf("%08x", block.nBits));
171 373 : result.pushKV("difficulty", GetDifficulty(blockindex));
172 746 : result.pushKV("chainwork", blockindex->nChainWork.GetHex());
173 :
174 373 : if (blockindex->pprev)
175 1110 : result.pushKV("previousblockhash", blockindex->pprev->GetBlockHash().GetHex());
176 373 : if (pnext)
177 714 : result.pushKV("nextblockhash", pnext->GetBlockHash().GetHex());
178 :
179 : //////////
180 : ////////// Coin stake data ////////////////
181 : /////////
182 373 : if (block.IsProofOfStake()) {
183 44 : uint256 hashProofOfStakeRet{UINT256_ZERO};
184 44 : if (blockindex->pprev && !GetStakeKernelHash(hashProofOfStakeRet, block, blockindex->pprev))
185 0 : throw JSONRPCError(RPC_INTERNAL_ERROR, "Cannot get proof of stake hash");
186 :
187 44 : std::string stakeModifier = (Params().GetConsensus().NetworkUpgradeActive(blockindex->nHeight, Consensus::UPGRADE_V3_4) ?
188 43 : blockindex->GetStakeModifierV2().GetHex() :
189 131 : strprintf("%016x", blockindex->GetStakeModifierV1()));
190 44 : result.pushKV("stakeModifier", stakeModifier);
191 132 : result.pushKV("hashProofOfStake", hashProofOfStakeRet.GetHex());
192 : }
193 373 : result.pushKV("chainlock", llmq::chainLocksHandler->HasChainLock(blockindex->nHeight, blockindex->GetBlockHash()));
194 :
195 373 : return result;
196 : }
197 :
198 889 : UniValue getblockcount(const JSONRPCRequest& request)
199 : {
200 889 : if (request.fHelp || request.params.size() != 0)
201 0 : throw std::runtime_error(
202 : "getblockcount\n"
203 : "\nReturns the number of blocks in the longest block chain.\n"
204 :
205 : "\nResult:\n"
206 : "n (numeric) The current block count\n"
207 :
208 0 : "\nExamples:\n" +
209 0 : HelpExampleCli("getblockcount", "") + HelpExampleRpc("getblockcount", ""));
210 :
211 889 : LOCK(cs_main);
212 1778 : return chainActive.Height();
213 : }
214 :
215 10086 : UniValue getbestblockhash(const JSONRPCRequest& request)
216 : {
217 10086 : if (request.fHelp || request.params.size() != 0)
218 0 : throw std::runtime_error(
219 : "getbestblockhash\n"
220 : "\nReturns the hash of the best (tip) block in the longest block chain.\n"
221 :
222 : "\nResult\n"
223 : "\"hex\" (string) the block hash hex encoded\n"
224 :
225 0 : "\nExamples\n" +
226 0 : HelpExampleCli("getbestblockhash", "") + HelpExampleRpc("getbestblockhash", ""));
227 :
228 10086 : LOCK(cs_main);
229 40344 : return chainActive.Tip()->GetBlockHash().GetHex();
230 : }
231 :
232 2 : UniValue getbestsaplinganchor(const JSONRPCRequest& request)
233 : {
234 2 : if (request.fHelp || request.params.size() != 0)
235 0 : throw std::runtime_error(
236 : "getbestsaplinganchor\n"
237 : "\nReturns the most recent SaplingMerkleTree root.\n"
238 :
239 : "\nResult\n"
240 : "\"hex\" (string) the sapling anchor hex encoded\n"
241 :
242 0 : "\nExamples\n" +
243 0 : HelpExampleCli("getbestsaplinganchor", "") + HelpExampleRpc("getbestsaplinganchor", ""));
244 :
245 4 : return pcoinsTip->GetBestAnchor().ToString();
246 : }
247 :
248 0 : UniValue getbestchainlock(const JSONRPCRequest& request)
249 : {
250 0 : if (request.fHelp || request.params.size() != 0)
251 0 : throw std::runtime_error(
252 : "getbestchainlock\n"
253 : "\nReturns the block hash of the best chainlock. Throws an error if there is no known chainlock yet.\n"
254 : "\nResult:\n"
255 : "{\n"
256 : " \"blockhash\" : \"hash\", (string) The block hash hex encoded\n"
257 : " \"height\" : n, (numeric) The block height or index\n"
258 : " \"known_block\" : true|false (boolean) True if the block is known by our node\n"
259 : "}\n"
260 0 : "\nExamples:\n" +
261 0 : HelpExampleCli("getbestchainlock", "") + HelpExampleRpc("getbestchainlock", ""));
262 0 : UniValue result(UniValue::VOBJ);
263 0 : llmq::CChainLockSig clsig = llmq::chainLocksHandler->GetBestChainLock();
264 0 : if (clsig.IsNull()) {
265 0 : throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to find any chainlock");
266 : }
267 0 : result.pushKV("blockhash", clsig.blockHash.GetHex());
268 0 : result.pushKV("height", clsig.nHeight);
269 0 : LOCK(cs_main);
270 0 : result.pushKV("known_block", mapBlockIndex.count(clsig.blockHash) > 0);
271 0 : return result;
272 : }
273 :
274 39326 : void RPCNotifyBlockChange(bool fInitialDownload, const CBlockIndex* pindex)
275 : {
276 39326 : if(pindex) {
277 77902 : std::lock_guard<std::mutex> lock(cs_blockchange);
278 38951 : latestblock.hash = pindex->GetBlockHash();
279 38951 : latestblock.height = pindex->nHeight;
280 : }
281 39326 : cond_blockchange.notify_all();
282 39326 : }
283 :
284 1 : UniValue waitfornewblock(const JSONRPCRequest& request)
285 : {
286 1 : if (request.fHelp || request.params.size() > 1)
287 0 : throw std::runtime_error(
288 : "waitfornewblock ( timeout )\n"
289 : "\nWaits for a specific new block and returns useful info about it.\n"
290 : "\nReturns the current block on timeout or exit.\n"
291 :
292 : "\nArguments:\n"
293 : "1. timeout (numeric, optional, default=0) Time in milliseconds to wait for a response. 0 indicates no timeout.\n"
294 :
295 : "\nResult:\n"
296 : "{ (json object)\n"
297 : " \"hash\": \"hash\", (string) The blockhash\n"
298 : " \"height\": n (numeric) Block height\n"
299 : "}\n"
300 :
301 : "\nExamples:\n"
302 0 : + HelpExampleCli("waitfornewblock", "1000")
303 0 : + HelpExampleRpc("waitfornewblock", "1000")
304 0 : );
305 1 : int timeout = 0;
306 1 : if (request.params.size() > 0)
307 0 : timeout = request.params[0].get_int();
308 :
309 1 : CUpdatedBlock block;
310 1 : {
311 1 : std::unique_lock<std::mutex> lock(cs_blockchange);
312 1 : block = latestblock;
313 1 : if(timeout)
314 0 : cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&block]{return latestblock.height != block.height || latestblock.hash != block.hash || !IsRPCRunning(); });
315 : else
316 4 : cond_blockchange.wait(lock, [&block]{return latestblock.height != block.height || latestblock.hash != block.hash || !IsRPCRunning(); });
317 1 : block = latestblock;
318 : }
319 1 : UniValue ret(UniValue::VOBJ);
320 2 : ret.pushKV("hash", block.hash.GetHex());
321 1 : ret.pushKV("height", block.height);
322 1 : return ret;
323 : }
324 :
325 3 : UniValue waitforblock(const JSONRPCRequest& request)
326 : {
327 3 : if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
328 0 : throw std::runtime_error(
329 : "waitforblock blockhash ( timeout )\n"
330 : "\nWaits for a specific new block and returns useful info about it.\n"
331 : "\nReturns the current block on timeout or exit.\n"
332 :
333 : "\nArguments:\n"
334 : "1. \"blockhash\" (string, required) Block hash to wait for.\n"
335 : "2. timeout (numeric, optional, default=0) Time in milliseconds to wait for a response. 0 indicates no timeout.\n"
336 :
337 : "\nResult:\n"
338 : "{ (json object)\n"
339 : " \"hash\": \"hash\", (string) The blockhash\n"
340 : " \"height\": n (numeric) Block height\n"
341 : "}\n"
342 :
343 : "\nExamples:\n"
344 0 : + HelpExampleCli("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\", 1000")
345 0 : + HelpExampleRpc("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\", 1000")
346 0 : );
347 3 : int timeout = 0;
348 :
349 3 : uint256 hash(ParseHashV(request.params[0], "blockhash"));
350 :
351 3 : if (request.params.size() > 1)
352 0 : timeout = request.params[1].get_int();
353 :
354 3 : CUpdatedBlock block;
355 3 : {
356 3 : std::unique_lock<std::mutex> lock(cs_blockchange);
357 3 : if(timeout)
358 0 : cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&hash]{return latestblock.hash == hash || !IsRPCRunning();});
359 : else
360 9 : cond_blockchange.wait(lock, [&hash]{return latestblock.hash == hash || !IsRPCRunning(); });
361 3 : block = latestblock;
362 : }
363 :
364 3 : UniValue ret(UniValue::VOBJ);
365 6 : ret.pushKV("hash", block.hash.GetHex());
366 3 : ret.pushKV("height", block.height);
367 3 : return ret;
368 : }
369 :
370 0 : UniValue waitforblockheight(const JSONRPCRequest& request)
371 : {
372 0 : if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
373 0 : throw std::runtime_error(
374 : "waitforblockheight height ( timeout )\n"
375 : "\nWaits for (at least) block height and returns the height and hash\n"
376 : "of the current tip.\n"
377 : "\nReturns the current block on timeout or exit.\n"
378 :
379 : "\nArguments:\n"
380 : "1. height (numeric, required) Block height to wait for\n"
381 : "2. timeout (numeric, optional, default=0) Time in milliseconds to wait for a response. 0 indicates no timeout.\n"
382 :
383 : "\nResult:\n"
384 : "{ (json object)\n"
385 : " \"hash\": \"hash\", (string) The blockhash\n"
386 : " \"height\": n (int) Block height\n"
387 : "}\n"
388 :
389 : "\nExamples:\n"
390 0 : + HelpExampleCli("waitforblockheight", "\"100\", 1000")
391 0 : + HelpExampleRpc("waitforblockheight", "\"100\", 1000")
392 0 : );
393 0 : int timeout = 0;
394 :
395 0 : int height = request.params[0].get_int();
396 :
397 0 : if (request.params.size() > 1)
398 0 : timeout = request.params[1].get_int();
399 :
400 0 : CUpdatedBlock block;
401 0 : {
402 0 : std::unique_lock<std::mutex> lock(cs_blockchange);
403 0 : if(timeout)
404 0 : cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&height]{return latestblock.height >= height || !IsRPCRunning();});
405 : else
406 0 : cond_blockchange.wait(lock, [&height]{return latestblock.height >= height || !IsRPCRunning(); });
407 0 : block = latestblock;
408 : }
409 0 : UniValue ret(UniValue::VOBJ);
410 0 : ret.pushKV("hash", block.hash.GetHex());
411 0 : ret.pushKV("height", block.height);
412 0 : return ret;
413 : }
414 :
415 0 : UniValue getdifficulty(const JSONRPCRequest& request)
416 : {
417 0 : if (request.fHelp || request.params.size() != 0)
418 0 : throw std::runtime_error(
419 : "getdifficulty\n"
420 : "\nReturns the proof-of-work difficulty as a multiple of the minimum difficulty.\n"
421 :
422 : "\nResult:\n"
423 : "n.nnn (numeric) the proof-of-work difficulty as a multiple of the minimum difficulty.\n"
424 :
425 0 : "\nExamples:\n" +
426 0 : HelpExampleCli("getdifficulty", "") + HelpExampleRpc("getdifficulty", ""));
427 :
428 0 : LOCK(cs_main);
429 0 : return GetDifficulty();
430 : }
431 :
432 0 : static std::string EntryDescriptionString()
433 : {
434 0 : return " \"size\" : n, (numeric) transaction size in bytes\n"
435 0 : " \"fee\" : n, (numeric) transaction fee in " + CURRENCY_UNIT + "\n"
436 : " \"modifiedfee\" : n, (numeric) transaction fee with fee deltas used for mining priority\n"
437 : " \"time\" : n, (numeric) local time transaction entered pool in seconds since 1 Jan 1970 GMT\n"
438 : " \"height\" : n, (numeric) block height when transaction entered pool\n"
439 : " \"descendantcount\" : n, (numeric) number of in-mempool descendant transactions (including this one)\n"
440 : " \"descendantsize\" : n, (numeric) size of in-mempool descendants (including this one)\n"
441 : " \"descendantfees\" : n, (numeric) modified fees (see above) of in-mempool descendants (including this one)\n"
442 : " \"depends\" : [ (array) unconfirmed transactions used as inputs for this transaction\n"
443 : " \"transactionid\", (string) parent transaction id\n"
444 0 : " ... ]\n";
445 : }
446 :
447 151 : static void entryToJSON(UniValue &info, const CTxMemPoolEntry &e)
448 : {
449 151 : AssertLockHeld(mempool.cs);
450 :
451 151 : info.pushKV("size", (int)e.GetTxSize());
452 302 : info.pushKV("fee", ValueFromAmount(e.GetFee()));
453 302 : info.pushKV("modifiedfee", ValueFromAmount(e.GetModifiedFee()));
454 151 : info.pushKV("time", e.GetTime());
455 151 : info.pushKV("height", (int)e.GetHeight());
456 151 : info.pushKV("descendantcount", e.GetCountWithDescendants());
457 151 : info.pushKV("descendantsize", e.GetSizeWithDescendants());
458 151 : info.pushKV("descendantfees", e.GetModFeesWithDescendants());
459 151 : const CTransaction& tx = e.GetTx();
460 151 : std::set<std::string> setDepends;
461 319 : for (const CTxIn& txin : tx.vin) {
462 168 : if (mempool.exists(txin.prevout.hash))
463 244 : setDepends.insert(txin.prevout.hash.ToString());
464 : }
465 :
466 302 : UniValue depends(UniValue::VARR);
467 273 : for (const std::string& dep : setDepends) {
468 122 : depends.push_back(dep);
469 : }
470 :
471 302 : info.pushKV("depends", depends);
472 151 : }
473 :
474 11104 : UniValue mempoolToJSON(bool fVerbose = false)
475 : {
476 11104 : if (fVerbose) {
477 42 : LOCK(mempool.cs);
478 42 : UniValue o(UniValue::VOBJ);
479 344 : for (const CTxMemPoolEntry& e : mempool.mapTx) {
480 151 : const uint256& hash = e.GetTx().GetHash();
481 151 : UniValue info(UniValue::VOBJ);
482 151 : entryToJSON(info, e);
483 302 : o.pushKV(hash.ToString(), info);
484 : }
485 21 : return o;
486 : } else {
487 22166 : std::vector<uint256> vtxid;
488 11083 : mempool.queryHashes(vtxid);
489 :
490 22166 : UniValue a(UniValue::VARR);
491 2568980 : for (const uint256& hash : vtxid)
492 5115800 : a.push_back(hash.ToString());
493 :
494 11083 : return a;
495 : }
496 : }
497 :
498 11103 : UniValue getrawmempool(const JSONRPCRequest& request)
499 : {
500 11103 : if (request.fHelp || request.params.size() > 1)
501 0 : throw std::runtime_error(
502 : "getrawmempool ( verbose )\n"
503 : "\nReturns all transaction ids in memory pool as a json array of string transaction ids.\n"
504 :
505 : "\nArguments:\n"
506 : "1. verbose (boolean, optional, default=false) True for a json object, false for array of transaction ids\n"
507 :
508 : "\nResult: (for verbose = false):\n"
509 : "[ (json array of string)\n"
510 : " \"transactionid\" (string) The transaction id\n"
511 : " ,...\n"
512 : "]\n"
513 :
514 : "\nResult: (for verbose = true):\n"
515 : "{ (json object)\n"
516 : " \"transactionid\" : { (json object)\n"
517 0 : + EntryDescriptionString()
518 0 : + " }, ...\n"
519 : "}\n"
520 0 : "\nExamples\n" +
521 0 : HelpExampleCli("getrawmempool", "true") + HelpExampleRpc("getrawmempool", "true"));
522 :
523 11103 : LOCK(cs_main);
524 :
525 11103 : bool fVerbose = false;
526 11103 : if (request.params.size() > 0)
527 20 : fVerbose = request.params[0].get_bool();
528 :
529 22206 : return mempoolToJSON(fVerbose);
530 : }
531 :
532 2868 : UniValue getblockhash(const JSONRPCRequest& request)
533 : {
534 2868 : if (request.fHelp || request.params.size() != 1)
535 0 : throw std::runtime_error(
536 : "getblockhash height\n"
537 : "\nReturns hash of block in best-block-chain at height provided.\n"
538 :
539 : "\nArguments:\n"
540 : "1. height (numeric, required) The height index\n"
541 :
542 : "\nResult:\n"
543 : "\"hash\" (string) The block hash\n"
544 :
545 0 : "\nExamples:\n" +
546 0 : HelpExampleCli("getblockhash", "1000") + HelpExampleRpc("getblockhash", "1000"));
547 :
548 2868 : LOCK(cs_main);
549 :
550 2868 : int nHeight = request.params[0].get_int();
551 2868 : if (nHeight < 0 || nHeight > chainActive.Height())
552 0 : throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");
553 :
554 2868 : CBlockIndex* pblockindex = chainActive[nHeight];
555 8604 : return pblockindex->GetBlockHash().GetHex();
556 : }
557 :
558 3068 : UniValue getblock(const JSONRPCRequest& request)
559 : {
560 3068 : if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
561 0 : throw std::runtime_error(
562 : "getblock \"blockhash\" ( verbosity )\n"
563 : "\nIf verbosity is 0, returns a string that is serialized, hex-encoded data for block 'hash'.\n"
564 : "If verbosity is 1, returns an Object with information about block <hash>.\n"
565 : "If verbosity is 2, returns an Object with information about block <hash> and information about each transaction.\n"
566 :
567 : "\nArguments:\n"
568 : "1. \"blockhash\" (string, required) The block hash\n"
569 : "2. verbosity (numeric, optional, default=1) 0 for hex encoded data, 1 for a json object, and 2 for json object with transaction data\n"
570 :
571 : "\nResult (for verbosity = 0):\n"
572 : "\"data\" (string) A string that is serialized, hex-encoded data for block 'hash'.\n"
573 :
574 : "\nResult (for verbosity = 1):\n"
575 : "{\n"
576 : " \"hash\" : \"hash\", (string) the block hash (same as provided)\n"
577 : " \"confirmations\" : n, (numeric) The number of confirmations, or -1 if the block is not on the main chain\n"
578 : " \"size\" : n, (numeric) The block size\n"
579 : " \"height\" : n, (numeric) The block height or index\n"
580 : " \"version\" : n, (numeric) The block version\n"
581 : " \"merkleroot\" : \"xxxx\", (string) The merkle root\n"
582 : " \"finalsaplingroot\" : \"xxxx\", (string) The root of the Sapling commitment tree after applying this block\n"
583 : " \"tx\" : [ (array of string) The transaction ids\n"
584 : " \"transactionid\" (string) The transaction id\n"
585 : " ,...\n"
586 : " ],\n"
587 : " \"time\" : ttt, (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\n"
588 : " \"mediantime\" : ttt, (numeric) The median block time in seconds since epoch (Jan 1 1970 GMT)\n"
589 : " \"nonce\" : n, (numeric) The nonce\n"
590 : " \"bits\" : \"1d00ffff\", (string) The bits\n"
591 : " \"difficulty\" : x.xxx, (numeric) The difficulty\n"
592 : " \"previousblockhash\" : \"hash\", (string) The hash of the previous block\n"
593 : " \"nextblockhash\" : \"hash\" (string) The hash of the next block\n"
594 : " \"stakeModifier\" : \"xxx\", (string) Proof of Stake modifier\n"
595 : " \"hashProofOfStake\" : \"hash\", (string) Proof of Stake hash\n"
596 : " }\n"
597 : "}\n"
598 :
599 : "\nResult (for verbosity = 2):\n"
600 : "{\n"
601 : " ..., Same output as verbosity = 1.\n"
602 : " \"tx\" : [ (array of Objects) The transactions in the format of the getrawtransaction RPC. Different from verbosity = 1 \"tx\" result.\n"
603 : " ,...\n"
604 : " ],\n"
605 : " ,... Same output as verbosity = 1.\n"
606 : "}\n"
607 :
608 0 : "\nExamples:\n" +
609 0 : HelpExampleCli("getblock", "\"00000000000fd08c2fb661d2fcb0d49abb3a91e5f27082ce64feed3b4dede2e2\"") +
610 0 : HelpExampleRpc("getblock", "\"00000000000fd08c2fb661d2fcb0d49abb3a91e5f27082ce64feed3b4dede2e2\""));
611 :
612 6121 : LOCK(cs_main);
613 :
614 3068 : uint256 hash(ParseHashV(request.params[0], "blockhash"));
615 :
616 3068 : int verbosity = 1;
617 3068 : if (!request.params[1].isNull()) {
618 2769 : if(request.params[1].isNum())
619 3 : verbosity = request.params[1].get_int();
620 : else
621 2766 : verbosity = request.params[1].get_bool() ? 1 : 0;
622 : }
623 :
624 3068 : CBlockIndex* pblockindex = LookupBlockIndex(hash);
625 3068 : if (pblockindex == nullptr)
626 16 : throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
627 :
628 6120 : CBlock block;
629 3060 : if (!ReadBlockFromDisk(block, pblockindex))
630 14 : throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk");
631 :
632 3053 : if (verbosity <= 0) {
633 5366 : CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION);
634 2683 : ssBlock << block;
635 5366 : std::string strHex = HexStr(ssBlock);
636 2683 : return strHex;
637 : }
638 :
639 740 : return blockToJSON(block, chainActive.Tip(), pblockindex, verbosity >= 2);
640 : }
641 :
642 3 : UniValue getblockheader(const JSONRPCRequest& request)
643 : {
644 3 : if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
645 0 : throw std::runtime_error(
646 : "getblockheader \"blockhash\" ( verbose )\n"
647 : "\nIf verbose is false, returns a string that is serialized, hex-encoded data for block 'hash' header.\n"
648 : "If verbose is true, returns an Object with information about block <hash> header.\n"
649 :
650 : "\nArguments:\n"
651 : "1. \"blockhash\" (string, required) The block hash\n"
652 : "2. verbose (boolean, optional, default=true) True for a json object, false for the hex encoded data\n"
653 :
654 : "\nResult (for verbose = true):\n"
655 : "{\n"
656 : " \"version\" : n, (numeric) The block version\n"
657 : " \"previousblockhash\" : \"hash\", (string) The hash of the previous block\n"
658 : " \"merkleroot\" : \"xxxx\", (string) The merkle root\n"
659 : " \"time\" : ttt, (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\n"
660 : " \"mediantime\" : ttt, (numeric) The median block time in seconds since epoch (Jan 1 1970 GMT)\n"
661 : " \"nonce\" : n, (numeric) The nonce\n"
662 : " \"bits\" : \"1d00ffff\", (string) The bits\n"
663 : " \"shield_pool_value\": (object) Block shield pool value\n"
664 : " {\n"
665 : " \"chainValue\": (numeric) Total value held by the Sapling circuit up to and including this block\n"
666 : " \"valueDelta\": (numeric) Change in value held by the Sapling circuit over this block\n"
667 : " }\n"
668 : "}"
669 : "}\n"
670 :
671 : "\nResult (for verbose=false):\n"
672 : "\"data\" (string) A string that is serialized, hex-encoded data for block 'hash' header.\n"
673 :
674 0 : "\nExamples:\n" +
675 0 : HelpExampleCli("getblockheader", "\"00000000000fd08c2fb661d2fcb0d49abb3a91e5f27082ce64feed3b4dede2e2\"") +
676 0 : HelpExampleRpc("getblockheader", "\"00000000000fd08c2fb661d2fcb0d49abb3a91e5f27082ce64feed3b4dede2e2\""));
677 :
678 :
679 4 : uint256 hash(ParseHashV(request.params[0], "blockhash"));
680 :
681 2 : bool fVerbose = true;
682 2 : if (request.params.size() > 1)
683 0 : fVerbose = request.params[1].get_bool();
684 :
685 4 : LOCK(cs_main);
686 :
687 2 : CBlockIndex* pblockindex = LookupBlockIndex(hash);
688 2 : if (pblockindex == nullptr)
689 0 : throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
690 :
691 2 : if (!fVerbose) {
692 0 : CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION);
693 0 : ssBlock << pblockindex->GetBlockHeader();
694 0 : std::string strHex = HexStr(ssBlock);
695 0 : return strHex;
696 : }
697 :
698 4 : return blockheaderToJSON(chainActive.Tip(), pblockindex);
699 : }
700 :
701 12 : UniValue getsupplyinfo(const JSONRPCRequest& request)
702 : {
703 12 : if (request.fHelp || request.params.size() > 1)
704 0 : throw std::runtime_error(
705 : "getsupplyinfo ( force_update )\n"
706 : "\nIf force_update=false (default if no argument is given): return the last cached money supply"
707 : "\n(sum of spendable transaction outputs) and the height of the chain when it was last updated"
708 : "\n(it is updated periodically, whenever the chainstate is flushed)."
709 : "\n"
710 : "\nIf force_update=true: Flush the chainstate to disk and return the money supply updated to"
711 : "\nthe current chain height.\n"
712 :
713 : "\nArguments:\n"
714 : "1. force_update (boolean, optional, default=false) flush chainstate to disk and update cache\n"
715 :
716 : "\nResult:\n"
717 : "{\n"
718 : " \"updateheight\" : n, (numeric) The chain height when the transparent supply was updated\n"
719 : " \"transparentsupply\" : n (numeric) The sum of all spendable transaction outputs at height updateheight\n"
720 : " \"shieldsupply\": n (numeric) Chain tip shield pool value\n"
721 : " \"totalsupply\": n (numeric) The sum of transparentsupply and shieldsupply\n"
722 : "}\n"
723 :
724 0 : "\nExamples:\n" +
725 0 : HelpExampleCli("getsupplyinfo", "") + HelpExampleCli("getsupplyinfo", "true") +
726 0 : HelpExampleRpc("getsupplyinfo", ""));
727 :
728 12 : const bool fForceUpdate = request.params.size() > 0 ? request.params[0].get_bool() : false;
729 :
730 6 : if (fForceUpdate) {
731 : // Flush state to disk (which updates the cached supply)
732 6 : FlushStateToDisk();
733 : }
734 :
735 12 : UniValue ret(UniValue::VOBJ);
736 12 : const CAmount tSupply = MoneySupply.Get();
737 12 : ret.pushKV("updateheight", MoneySupply.GetCacheHeight());
738 24 : ret.pushKV("transparentsupply", ValueFromAmount(tSupply));
739 24 : Optional<CAmount> shieldedPoolValue = WITH_LOCK(cs_main, return (chainActive.Tip() ? chainActive.Tip()->nChainSaplingValue : nullopt); );
740 24 : ret.pushKV("shieldsupply", ValuePoolDesc(shieldedPoolValue, nullopt)["chainValue"]);
741 12 : const CAmount totalSupply = tSupply + (shieldedPoolValue ? *shieldedPoolValue : 0);
742 24 : ret.pushKV("totalsupply", ValueFromAmount(totalSupply));
743 :
744 12 : return ret;
745 : }
746 :
747 49 : struct CCoinsStats
748 : {
749 : int nHeight{0};
750 : uint256 hashBlock{UINT256_ZERO};
751 : uint64_t nTransactions{0};
752 : uint64_t nTransactionOutputs{0};
753 : uint256 hashSerialized{UINT256_ZERO};
754 : uint64_t nDiskSize{0};
755 : CAmount nTotalAmount{0};
756 : };
757 :
758 1488900 : static void ApplyStats(CCoinsStats &stats, CHashWriter& ss, const uint256& hash, const std::map<uint32_t, Coin>& outputs)
759 : {
760 1488900 : assert(!outputs.empty());
761 1488900 : ss << hash;
762 1488900 : const Coin& coin = outputs.begin()->second;
763 4453940 : ss << VARINT(coin.nHeight * 4 + (coin.fCoinBase ? 2u : 0u) + (coin.fCoinStake ? 1u : 0u));
764 1488900 : stats.nTransactions++;
765 4273780 : for (const auto& output : outputs) {
766 2784880 : ss << VARINT(output.first + 1);
767 2784880 : ss << output.second.out.scriptPubKey;
768 2784880 : ss << VARINT_MODE(output.second.out.nValue, VarIntMode::NONNEGATIVE_SIGNED);
769 2784880 : stats.nTransactionOutputs++;
770 2784880 : stats.nTotalAmount += output.second.out.nValue;
771 : }
772 1488900 : ss << VARINT(0u);
773 1488900 : }
774 :
775 : //! Calculate statistics about the unspent transaction output set
776 49 : static bool GetUTXOStats(CCoinsView *view, CCoinsStats &stats)
777 : {
778 98 : std::unique_ptr<CCoinsViewCursor> pcursor(view->Cursor());
779 49 : assert(pcursor);
780 :
781 49 : CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
782 49 : stats.hashBlock = pcursor->GetBestBlock();
783 49 : {
784 49 : LOCK(cs_main);
785 49 : stats.nHeight = LookupBlockIndex(stats.hashBlock)->nHeight;
786 : }
787 49 : ss << stats.hashBlock;
788 49 : uint256 prevkey;
789 98 : std::map<uint32_t, Coin> outputs;
790 2784930 : while (pcursor->Valid()) {
791 2784880 : boost::this_thread::interruption_point();
792 2784880 : COutPoint key;
793 5569770 : Coin coin;
794 2784880 : if (pcursor->GetKey(key) && pcursor->GetValue(coin)) {
795 2784880 : if (!outputs.empty() && key.hash != prevkey) {
796 1488850 : ApplyStats(stats, ss, prevkey, outputs);
797 1488850 : outputs.clear();
798 : }
799 2784880 : prevkey = key.hash;
800 2784880 : outputs[key.n] = std::move(coin);
801 : } else {
802 0 : return error("%s: unable to read value", __func__);
803 : }
804 2784880 : pcursor->Next();
805 : }
806 49 : if (!outputs.empty()) {
807 49 : ApplyStats(stats, ss, prevkey, outputs);
808 : }
809 49 : stats.hashSerialized = ss.GetHash();
810 49 : stats.nDiskSize = view->EstimateSize();
811 49 : return true;
812 : }
813 :
814 49 : UniValue gettxoutsetinfo(const JSONRPCRequest& request)
815 : {
816 49 : if (request.fHelp || request.params.size() != 0)
817 0 : throw std::runtime_error(
818 : "gettxoutsetinfo\n"
819 : "\nReturns statistics about the unspent transaction output set.\n"
820 : "Note this call may take some time.\n"
821 :
822 : "\nResult:\n"
823 : "{\n"
824 : " \"height\":n, (numeric) The current block height (index)\n"
825 : " \"bestblock\": \"hex\", (string) the best block hash hex\n"
826 : " \"transactions\": n, (numeric) The number of transactions\n"
827 : " \"txouts\": n, (numeric) The number of output transactions\n"
828 : " \"hash_serialized_2\": \"hash\", (string) The serialized hash\n"
829 : " \"disk_size\": n, (numeric) The estimated size of the chainstate on disk\n"
830 : " \"total_amount\": x.xxx (numeric) The total amount\n"
831 : "}\n"
832 :
833 0 : "\nExamples:\n" +
834 0 : HelpExampleCli("gettxoutsetinfo", "") + HelpExampleRpc("gettxoutsetinfo", ""));
835 :
836 49 : UniValue ret(UniValue::VOBJ);
837 :
838 49 : CCoinsStats stats;
839 49 : FlushStateToDisk();
840 49 : if (GetUTXOStats(pcoinsTip.get(), stats)) {
841 49 : ret.pushKV("height", (int64_t)stats.nHeight);
842 98 : ret.pushKV("bestblock", stats.hashBlock.GetHex());
843 49 : ret.pushKV("transactions", (int64_t)stats.nTransactions);
844 49 : ret.pushKV("txouts", (int64_t)stats.nTransactionOutputs);
845 98 : ret.pushKV("hash_serialized_2", stats.hashSerialized.GetHex());
846 98 : ret.pushKV("total_amount", ValueFromAmount(stats.nTotalAmount));
847 98 : ret.pushKV("disk_size", stats.nDiskSize);
848 : }
849 49 : return ret;
850 : }
851 :
852 0 : UniValue gettxout(const JSONRPCRequest& request)
853 : {
854 0 : if (request.fHelp || request.params.size() < 2 || request.params.size() > 3)
855 0 : throw std::runtime_error(
856 : "gettxout \"txid\" n ( include_mempool )\n"
857 : "\nReturns details about an unspent transaction output.\n"
858 :
859 : "\nArguments:\n"
860 : "1. \"txid\" (string, required) The transaction id\n"
861 : "2. n (numeric, required) vout value\n"
862 : "3. include_mempool (boolean, optional) Whether to included the mem pool\n"
863 :
864 : "\nResult:\n"
865 : "{\n"
866 : " \"bestblock\" : \"hash\", (string) the block hash\n"
867 : " \"confirmations\" : n, (numeric) The number of confirmations\n"
868 : " \"value\" : x.xxx, (numeric) The transaction value in PIV\n"
869 : " \"scriptPubKey\" : { (json object)\n"
870 : " \"asm\" : \"code\", (string) \n"
871 : " \"hex\" : \"hex\", (string) \n"
872 : " \"reqSigs\" : n, (numeric) Number of required signatures\n"
873 : " \"type\" : \"pubkeyhash\", (string) The type, eg pubkeyhash\n"
874 : " \"addresses\" : [ (array of string) array of pivx addresses\n"
875 : " \"pivxaddress\" (string) pivx address\n"
876 : " ,...\n"
877 : " ]\n"
878 : " },\n"
879 : " \"coinbase\" : true|false (boolean) Coinbase or not\n"
880 : "}\n"
881 :
882 : "\nExamples:\n"
883 0 : "\nGet unspent transactions\n" +
884 0 : HelpExampleCli("listunspent", "") +
885 0 : "\nView the details\n" +
886 0 : HelpExampleCli("gettxout", "\"txid\" 1") +
887 0 : "\nAs a json rpc call\n" +
888 0 : HelpExampleRpc("gettxout", "\"txid\", 1"));
889 :
890 0 : LOCK(cs_main);
891 :
892 0 : UniValue ret(UniValue::VOBJ);
893 0 : uint256 hash(ParseHashV(request.params[0], "txid"));
894 0 : int n = request.params[1].get_int();
895 0 : COutPoint out(hash, n);
896 0 : bool fMempool = true;
897 0 : if (request.params.size() > 2)
898 0 : fMempool = request.params[2].get_bool();
899 :
900 0 : Coin coin;
901 0 : if (fMempool) {
902 0 : LOCK(mempool.cs);
903 0 : CCoinsViewMemPool view(pcoinsTip.get(), mempool);
904 0 : if (!view.GetCoin(out, coin) || mempool.isSpent(out)) {// TODO: filtering spent coins should be done by the CCoinsViewMemPool
905 0 : return NullUniValue;
906 : }
907 : } else {
908 0 : if (!pcoinsTip->GetCoin(out, coin)) {
909 0 : return NullUniValue;
910 : }
911 : }
912 :
913 0 : CBlockIndex* pindex = LookupBlockIndex(pcoinsTip->GetBestBlock());
914 0 : assert(pindex != nullptr);
915 0 : ret.pushKV("bestblock", pindex->GetBlockHash().GetHex());
916 0 : if (coin.nHeight == MEMPOOL_HEIGHT) {
917 0 : ret.pushKV("confirmations", 0);
918 : } else {
919 0 : ret.pushKV("confirmations", (int64_t)(pindex->nHeight - coin.nHeight + 1));
920 : }
921 0 : ret.pushKV("value", ValueFromAmount(coin.out.nValue));
922 0 : UniValue o(UniValue::VOBJ);
923 0 : ScriptPubKeyToUniv(coin.out.scriptPubKey, o, true);
924 0 : ret.pushKV("scriptPubKey", o);
925 0 : ret.pushKV("coinbase", (bool)coin.fCoinBase);
926 :
927 0 : return ret;
928 : }
929 :
930 1 : UniValue verifychain(const JSONRPCRequest& request)
931 : {
932 1 : if (request.fHelp || request.params.size() > 1)
933 0 : throw std::runtime_error(
934 : "verifychain ( nblocks )\n"
935 : "\nVerifies blockchain database.\n"
936 :
937 : "\nArguments:\n"
938 : "1. nblocks (numeric, optional, default=288, 0=all) The number of blocks to check.\n"
939 :
940 : "\nResult:\n"
941 : "true|false (boolean) Verified or not\n"
942 :
943 0 : "\nExamples:\n" +
944 0 : HelpExampleCli("verifychain", "") + HelpExampleRpc("verifychain", ""));
945 :
946 1 : LOCK(cs_main);
947 :
948 1 : int nCheckLevel = gArgs.GetArg("-checklevel", DEFAULT_CHECKLEVEL);
949 1 : int nCheckDepth = gArgs.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS);
950 1 : if (request.params.size() > 0)
951 1 : nCheckDepth = request.params[0].get_int();
952 :
953 2 : return CVerifyDB().VerifyDB(pcoinsTip.get(), nCheckLevel, nCheckDepth);
954 : }
955 :
956 : /** Implementation of IsSuperMajority with better feedback */
957 18 : static UniValue SoftForkMajorityDesc(int version, const CBlockIndex* pindex, const Consensus::Params& consensusParams)
958 : {
959 18 : UniValue rv(UniValue::VOBJ);
960 18 : Consensus::UpgradeIndex idx;
961 18 : switch(version) {
962 : case 1:
963 : case 2:
964 : case 3:
965 : idx = Consensus::BASE_NETWORK;
966 : break;
967 0 : case 4:
968 0 : idx = Consensus::UPGRADE_ZC;
969 0 : break;
970 18 : case 5:
971 18 : idx = Consensus::UPGRADE_BIP65;
972 18 : break;
973 0 : case 6:
974 0 : idx = Consensus::UPGRADE_V3_4;
975 0 : break;
976 0 : case 7:
977 0 : idx = Consensus::UPGRADE_V4_0;
978 0 : break;
979 0 : default:
980 0 : rv.pushKV("status", false);
981 0 : return rv;
982 : }
983 18 : rv.pushKV("status", pindex && consensusParams.NetworkUpgradeActive(pindex->nHeight, idx));
984 18 : return rv;
985 : }
986 :
987 18 : static UniValue SoftForkDesc(const std::string &name, int version, const CBlockIndex* pindex)
988 : {
989 18 : const Consensus::Params& consensus = Params().GetConsensus();
990 18 : UniValue rv(UniValue::VOBJ);
991 18 : rv.pushKV("id", name);
992 18 : rv.pushKV("version", version);
993 36 : rv.pushKV("reject", SoftForkMajorityDesc(version, pindex, consensus));
994 18 : return rv;
995 : }
996 :
997 234 : static UniValue NetworkUpgradeDesc(const Consensus::Params& consensusParams, Consensus::UpgradeIndex idx, int height)
998 : {
999 234 : UniValue rv(UniValue::VOBJ);
1000 234 : auto upgrade = NetworkUpgradeInfo[idx];
1001 234 : rv.pushKV("activationheight", consensusParams.vUpgrades[idx].nActivationHeight);
1002 234 : switch (NetworkUpgradeState(height, consensusParams, idx)) {
1003 0 : case UPGRADE_DISABLED: rv.pushKV("status", "disabled"); break;
1004 314 : case UPGRADE_PENDING: rv.pushKV("status", "pending"); break;
1005 154 : case UPGRADE_ACTIVE: rv.pushKV("status", "active"); break;
1006 : }
1007 234 : rv.pushKV("info", upgrade.strInfo);
1008 234 : return rv;
1009 : }
1010 :
1011 270 : void NetworkUpgradeDescPushBack(
1012 : UniValue& networkUpgrades,
1013 : const Consensus::Params& consensusParams,
1014 : Consensus::UpgradeIndex idx,
1015 : int height)
1016 : {
1017 : // Network upgrades with an activation height of NO_ACTIVATION_HEIGHT are
1018 : // hidden. This is used when network upgrade implementations are merged
1019 : // without specifying the activation height.
1020 270 : if (consensusParams.vUpgrades[idx].nActivationHeight != Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT) {
1021 468 : std::string name = NetworkUpgradeInfo[idx].strName;
1022 234 : std::replace(name.begin(), name.end(), '_', ' '); // Beautify the name
1023 234 : networkUpgrades.pushKV(name, NetworkUpgradeDesc(consensusParams, idx, height));
1024 : }
1025 270 : }
1026 :
1027 19 : UniValue getblockchaininfo(const JSONRPCRequest& request)
1028 : {
1029 19 : if (request.fHelp || request.params.size() != 0)
1030 1 : throw std::runtime_error(
1031 : "getblockchaininfo\n"
1032 : "Returns an object containing various state info regarding block chain processing.\n"
1033 :
1034 : "\nResult:\n"
1035 : "{\n"
1036 : " \"chain\": \"xxxx\", (string) current network name (main, test, regtest)\n"
1037 : " \"blocks\": xxxxxx, (numeric) the current number of blocks processed in the server\n"
1038 : " \"headers\": xxxxxx, (numeric) the current number of headers we have validated\n"
1039 : " \"bestblockhash\": \"...\", (string) the hash of the currently best block\n"
1040 : " \"difficulty\": xxxxxx, (numeric) the current difficulty\n"
1041 : " \"verificationprogress\": xxxx, (numeric) estimate of verification progress [0..1]\n"
1042 : " \"chainwork\": \"xxxx\" (string) total amount of work in active chain, in hexadecimal\n"
1043 : " \"shield_pool_value\": { (object) Chain tip shield pool value\n"
1044 : " \"chainValue\": (numeric) Total value held by the Sapling circuit up to and including the chain tip\n"
1045 : " \"valueDelta\": (numeric) Change in value held by the Sapling circuit over the chain tip block\n"
1046 : " },\n"
1047 : " \"initial_block_downloading\": true|false, (boolean) whether the node is in initial block downloading state or not\n"
1048 : " \"softforks\": [ (array) status of softforks in progress\n"
1049 : " {\n"
1050 : " \"id\": \"xxxx\", (string) name of softfork\n"
1051 : " \"version\": xx, (numeric) block version\n"
1052 : " \"reject\": { (object) progress toward rejecting pre-softfork blocks\n"
1053 : " \"status\": xx, (boolean) true if threshold reached\n"
1054 : " },\n"
1055 : " }, ...\n"
1056 : " ],\n"
1057 : " \"upgrades\": { (object) status of network upgrades\n"
1058 : " \"name\" : { (string) name of upgrade\n"
1059 : " \"activationheight\": xxxxxx, (numeric) block height of activation\n"
1060 : " \"status\": \"xxxx\", (string) status of upgrade\n"
1061 : " \"info\": \"xxxx\", (string) additional information about upgrade\n"
1062 : " }, ...\n"
1063 : "}\n"
1064 : " \"warnings\" : \"...\", (string) any network and blockchain warnings.\n"
1065 :
1066 2 : "\nExamples:\n" +
1067 7 : HelpExampleCli("getblockchaininfo", "") + HelpExampleRpc("getblockchaininfo", ""));
1068 :
1069 18 : LOCK(cs_main);
1070 :
1071 18 : const Consensus::Params& consensusParams = Params().GetConsensus();
1072 18 : const CBlockIndex* pChainTip = chainActive.Tip();
1073 18 : int nTipHeight = pChainTip ? pChainTip->nHeight : -1;
1074 :
1075 18 : UniValue obj(UniValue::VOBJ);
1076 54 : obj.pushKV("chain", Params().NetworkIDString());
1077 18 : obj.pushKV("blocks", nTipHeight);
1078 18 : obj.pushKV("headers", pindexBestHeader ? pindexBestHeader->nHeight : -1);
1079 36 : obj.pushKV("bestblockhash", pChainTip ? pChainTip->GetBlockHash().GetHex() : "");
1080 18 : obj.pushKV("difficulty", (double)GetDifficulty());
1081 18 : obj.pushKV("verificationprogress", Checkpoints::GuessVerificationProgress(pChainTip));
1082 36 : obj.pushKV("chainwork", pChainTip ? pChainTip->nChainWork.GetHex() : "");
1083 : // Sapling shield pool value
1084 36 : obj.pushKV("shield_pool_value", pChainTip ? ValuePoolDesc(pChainTip->nChainSaplingValue, pChainTip->nSaplingValue) : 0);
1085 18 : obj.pushKV("initial_block_downloading", IsInitialBlockDownload());
1086 36 : UniValue softforks(UniValue::VARR);
1087 18 : softforks.push_back(SoftForkDesc("bip65", 5, pChainTip));
1088 18 : obj.pushKV("softforks", softforks);
1089 18 : UniValue upgrades(UniValue::VOBJ);
1090 288 : for (int i = Consensus::BASE_NETWORK + 1; i < (int) Consensus::MAX_NETWORK_UPGRADES; i++) {
1091 270 : NetworkUpgradeDescPushBack(upgrades, consensusParams, Consensus::UpgradeIndex(i), nTipHeight);
1092 : }
1093 18 : obj.pushKV("upgrades", upgrades);
1094 54 : obj.pushKV("warnings", GetWarnings("statusbar"));
1095 36 : return obj;
1096 : }
1097 :
1098 : /** Comparison function for sorting the getchaintips heads. */
1099 : struct CompareBlocksByHeight {
1100 7560 : bool operator()(const CBlockIndex* a, const CBlockIndex* b) const
1101 : {
1102 : /* Make sure that unequal blocks with the same height do not compare
1103 : equal. Use the pointers themselves to make a distinction. */
1104 :
1105 7560 : if (a->nHeight != b->nHeight)
1106 6756 : return (a->nHeight > b->nHeight);
1107 :
1108 804 : return a < b;
1109 : }
1110 : };
1111 :
1112 2 : UniValue getchaintips(const JSONRPCRequest& request)
1113 : {
1114 2 : if (request.fHelp || request.params.size() != 0)
1115 0 : throw std::runtime_error(
1116 : "getchaintips\n"
1117 : "Return information about all known tips in the block tree,"
1118 : " including the main chain as well as orphaned branches.\n"
1119 :
1120 : "\nResult:\n"
1121 : "[\n"
1122 : " {\n"
1123 : " \"height\": xxxx, (numeric) height of the chain tip\n"
1124 : " \"hash\": \"xxxx\", (string) block hash of the tip\n"
1125 : " \"branchlen\": 0 (numeric) zero for main chain\n"
1126 : " \"status\": \"active\" (string) \"active\" for the main chain\n"
1127 : " },\n"
1128 : " {\n"
1129 : " \"height\": n, (numeric) height of the chain tip\n"
1130 : " \"hash\": \"hash\", (string) block hash of the tip\n"
1131 : " \"branchlen\": n, (numeric) length of branch connecting the tip to the main chain\n"
1132 : " \"status\": \"xxxx\" (string) status of the chain (active, valid-fork, valid-headers, headers-only, invalid)\n"
1133 : " }\n"
1134 : " ,...\n"
1135 : "]\n"
1136 :
1137 : "Possible values for status:\n"
1138 : "1. \"invalid\" This branch contains at least one invalid block\n"
1139 : "2. \"headers-only\" Not all blocks for this branch are available, but the headers are valid\n"
1140 : "3. \"valid-headers\" All blocks are available for this branch, but they were never fully validated\n"
1141 : "4. \"valid-fork\" This branch is not part of the active chain, but is fully validated\n"
1142 : "5. \"active\" This is the tip of the active main chain, which is certainly valid\n"
1143 :
1144 0 : "\nExamples:\n" +
1145 0 : HelpExampleCli("getchaintips", "") + HelpExampleRpc("getchaintips", ""));
1146 :
1147 2 : LOCK(cs_main);
1148 :
1149 : /* Build up a list of chain tips. We start with the list of all
1150 : known blocks, and successively remove blocks that appear as pprev
1151 : of another block. */
1152 4 : std::set<const CBlockIndex*, CompareBlocksByHeight> setTips;
1153 404 : for (const std::pair<const uint256, CBlockIndex*> & item : mapBlockIndex)
1154 402 : setTips.insert(item.second);
1155 404 : for (const std::pair<const uint256, CBlockIndex*> & item : mapBlockIndex) {
1156 402 : const CBlockIndex* pprev = item.second->pprev;
1157 402 : if (pprev)
1158 402 : setTips.erase(pprev);
1159 : }
1160 :
1161 : // Always report the currently active tip.
1162 4 : setTips.insert(chainActive.Tip());
1163 :
1164 : /* Construct the output array. */
1165 2 : UniValue res(UniValue::VARR);
1166 4 : for (const CBlockIndex* block : setTips) {
1167 2 : UniValue obj(UniValue::VOBJ);
1168 2 : obj.pushKV("height", block->nHeight);
1169 4 : obj.pushKV("hash", block->phashBlock->GetHex());
1170 :
1171 2 : const int branchLen = block->nHeight - chainActive.FindFork(block)->nHeight;
1172 2 : obj.pushKV("branchlen", branchLen);
1173 :
1174 4 : std::string status;
1175 4 : if (chainActive.Contains(block)) {
1176 : // This block is part of the currently active chain.
1177 2 : status = "active";
1178 0 : } else if (block->nStatus & BLOCK_FAILED_MASK) {
1179 : // This block or one of its ancestors is invalid.
1180 0 : status = "invalid";
1181 0 : } else if (block->nChainTx == 0) {
1182 : // This block cannot be connected because full block data for it or one of its parents is missing.
1183 0 : status = "headers-only";
1184 0 : } else if (block->IsValid(BLOCK_VALID_SCRIPTS)) {
1185 : // This block is fully validated, but no longer part of the active chain. It was probably the active block once, but was reorganized.
1186 0 : status = "valid-fork";
1187 0 : } else if (block->IsValid(BLOCK_VALID_TREE)) {
1188 : // The headers for this block are valid, but it has not been validated. It was probably never part of the most-work chain.
1189 0 : status = "valid-headers";
1190 : } else {
1191 : // No clue.
1192 0 : status = "unknown";
1193 : }
1194 2 : obj.pushKV("status", status);
1195 :
1196 2 : res.push_back(obj);
1197 : }
1198 :
1199 4 : return res;
1200 : }
1201 :
1202 378 : UniValue mempoolInfoToJSON()
1203 : {
1204 378 : UniValue ret(UniValue::VOBJ);
1205 378 : ret.pushKV("loaded", mempool.IsLoaded());
1206 378 : ret.pushKV("size", (int64_t) mempool.size());
1207 378 : ret.pushKV("bytes", (int64_t) mempool.GetTotalTxSize());
1208 378 : ret.pushKV("usage", (int64_t) mempool.DynamicMemoryUsage());
1209 378 : size_t maxmempool = gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;
1210 1134 : ret.pushKV("mempoolminfee", ValueFromAmount(std::max(mempool.GetMinFee(maxmempool), ::minRelayTxFee).GetFeePerK()));
1211 756 : ret.pushKV("minrelaytxfee", ValueFromAmount(::minRelayTxFee.GetFeePerK()));
1212 :
1213 378 : return ret;
1214 : }
1215 :
1216 377 : UniValue getmempoolinfo(const JSONRPCRequest& request)
1217 : {
1218 377 : if (request.fHelp || request.params.size() != 0)
1219 0 : throw std::runtime_error(
1220 : "getmempoolinfo\n"
1221 : "\nReturns details on the active state of the TX memory pool.\n"
1222 :
1223 : "\nResult:\n"
1224 : "{\n"
1225 : " \"loaded\": true|false (boolean) True if the mempool is fully loaded\n"
1226 : " \"size\": xxxxx (numeric) Current tx count\n"
1227 : " \"bytes\": xxxxx (numeric) Sum of all tx sizes\n"
1228 : " \"usage\": xxxxx (numeric) Total memory usage for the mempool\n"
1229 : " \"maxmempool\": xxxxx, (numeric) Maximum memory usage for the mempool\n"
1230 0 : " \"mempoolminfee\": xxxxx (numeric) Minimum fee rate in " + CURRENCY_UNIT + "/kB for tx to be accepted. Is the maximum of minrelaytxfee and minimum mempool fee\n"
1231 : " \"minrelaytxfee\": xxxxx (numeric) Current minimum relay fee for transactions\n"
1232 : "}\n"
1233 :
1234 0 : "\nExamples:\n" +
1235 0 : HelpExampleCli("getmempoolinfo", "") + HelpExampleRpc("getmempoolinfo", ""));
1236 :
1237 377 : return mempoolInfoToJSON();
1238 : }
1239 :
1240 29 : UniValue invalidateblock(const JSONRPCRequest& request)
1241 : {
1242 29 : if (request.fHelp || request.params.size() != 1)
1243 0 : throw std::runtime_error(
1244 : "invalidateblock \"blockhash\"\n"
1245 : "\nPermanently marks a block as invalid, as if it violated a consensus rule. Note: it might take up to some minutes and after calling it's recommended to run recover transactions. \n"
1246 :
1247 : "\nArguments:\n"
1248 : "1. blockhash (string, required) the hash of the block to mark as invalid\n"
1249 :
1250 0 : "\nExamples:\n" +
1251 0 : HelpExampleCli("invalidateblock", "\"blockhash\"") + HelpExampleRpc("invalidateblock", "\"blockhash\""));
1252 :
1253 29 : uint256 hash(ParseHashV(request.params[0], "blockhash"));
1254 58 : CValidationState state;
1255 :
1256 29 : {
1257 29 : LOCK(cs_main);
1258 29 : if (mapBlockIndex.count(hash) == 0)
1259 0 : throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
1260 :
1261 29 : CBlockIndex* pblockindex = mapBlockIndex[hash];
1262 : // For each wallet in your wallet list
1263 58 : std::string errString = "";
1264 58 : for (auto* pwallet : vpwallets) {
1265 : //Do we need to recreate the witnesscache or is the current one enough?
1266 29 : if (pwallet->GetSaplingScriptPubKeyMan()->nWitnessCacheSize <= (chainActive.Height() - pblockindex->nHeight + 1)) {
1267 5 : if (!pwallet->GetSaplingScriptPubKeyMan()->BuildWitnessChain(pblockindex, Params().GetConsensus(), errString)) {
1268 0 : throw JSONRPCError(RPC_DATABASE_ERROR, errString);
1269 : }
1270 : }
1271 : }
1272 29 : InvalidateBlock(state, Params(), pblockindex);
1273 : }
1274 :
1275 29 : if (state.IsValid()) {
1276 29 : ActivateBestChain(state);
1277 58 : int nHeight = WITH_LOCK(cs_main, return chainActive.Height(); );
1278 29 : g_budgetman.SetBestHeight(nHeight);
1279 29 : mnodeman.SetBestHeight(nHeight);
1280 : }
1281 :
1282 29 : if (!state.IsValid()) {
1283 0 : throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason());
1284 : }
1285 :
1286 58 : return NullUniValue;
1287 : }
1288 :
1289 10 : UniValue reconsiderblock(const JSONRPCRequest& request)
1290 : {
1291 10 : if (request.fHelp || request.params.size() != 1)
1292 0 : throw std::runtime_error(
1293 : "reconsiderblock \"blockhash\"\n"
1294 : "\nRemoves invalidity status of a block and its descendants, reconsider them for activation.\n"
1295 : "This can be used to undo the effects of invalidateblock.\n"
1296 :
1297 : "\nArguments:\n"
1298 : "1. blockhash (string, required) the hash of the block to reconsider\n"
1299 :
1300 0 : "\nExamples:\n" +
1301 0 : HelpExampleCli("reconsiderblock", "\"blockhash\"") + HelpExampleRpc("reconsiderblock", "\"blockhash\""));
1302 :
1303 10 : uint256 hash(ParseHashV(request.params[0], "blockhash"));
1304 20 : CValidationState state;
1305 :
1306 10 : {
1307 10 : LOCK(cs_main);
1308 10 : if (mapBlockIndex.count(hash) == 0)
1309 0 : throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
1310 :
1311 10 : CBlockIndex* pblockindex = mapBlockIndex[hash];
1312 10 : ReconsiderBlock(state, pblockindex);
1313 : }
1314 :
1315 10 : if (state.IsValid()) {
1316 10 : ActivateBestChain(state);
1317 20 : int nHeight = WITH_LOCK(cs_main, return chainActive.Height(); );
1318 10 : g_budgetman.SetBestHeight(nHeight);
1319 10 : mnodeman.SetBestHeight(nHeight);
1320 : }
1321 :
1322 10 : if (!state.IsValid()) {
1323 0 : throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason());
1324 : }
1325 :
1326 20 : return NullUniValue;
1327 : }
1328 :
1329 1 : void validaterange(const UniValue& params, int& heightStart, int& heightEnd, int minHeightStart = 1)
1330 : {
1331 1 : if (params.size() < 2) {
1332 0 : throw JSONRPCError(RPC_INVALID_PARAMETER, "Not enough parameters in validaterange");
1333 : }
1334 :
1335 1 : int nBestHeight;
1336 1 : {
1337 1 : LOCK(cs_main);
1338 1 : nBestHeight = chainActive.Height();
1339 : }
1340 :
1341 1 : heightStart = params[0].get_int();
1342 1 : if (heightStart > nBestHeight) {
1343 0 : throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid starting block (%d). Out of range.", heightStart));
1344 : }
1345 :
1346 1 : const int range = params[1].get_int();
1347 1 : if (range < 1) {
1348 0 : throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid block range. Must be strictly positive.");
1349 : }
1350 :
1351 1 : heightEnd = heightStart + range - 1;
1352 :
1353 1 : if (heightStart < minHeightStart && heightEnd >= minHeightStart) {
1354 0 : heightStart = minHeightStart;
1355 : }
1356 :
1357 1 : if (heightEnd > nBestHeight) {
1358 0 : throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid ending block (%d). Out of range.", heightEnd));
1359 : }
1360 1 : }
1361 :
1362 1 : UniValue getblockindexstats(const JSONRPCRequest& request) {
1363 1 : if (request.fHelp || request.params.size() != 2)
1364 0 : throw std::runtime_error(
1365 : "getblockindexstats height range\n"
1366 : "\nReturns aggregated BlockIndex data for blocks "
1367 : "\n[height, height+1, height+2, ..., height+range-1]\n"
1368 :
1369 : "\nArguments:\n"
1370 : "1. height (numeric, required) block height where the search starts.\n"
1371 : "2. range (numeric, required) number of blocks to include.\n"
1372 :
1373 : "\nResult:\n"
1374 : "{\n"
1375 : " \"first_block\": \"x\" (integer) First counted block\n"
1376 : " \"last_block\": \"x\" (integer) Last counted block\n"
1377 : " \"txcount\": xxxxx (numeric) tx count (excluding coinbase/coinstake)\n"
1378 : " \"txcount_all\": xxxxx (numeric) tx count (including coinbase/coinstake)\n"
1379 : " \"txbytes\": xxxxx (numeric) Sum of the size of all txes over block range\n"
1380 : " \"ttlfee\": xxxxx (numeric) Sum of the fee amount of all txes over block range\n"
1381 : " \"feeperkb\": xxxxx (numeric) Average fee per kb (excluding zc txes)\n"
1382 : "}\n"
1383 :
1384 0 : "\nExamples:\n" +
1385 0 : HelpExampleCli("getblockindexstats", "1200000 1000") +
1386 0 : HelpExampleRpc("getblockindexstats", "1200000, 1000"));
1387 :
1388 1 : int heightStart, heightEnd;
1389 1 : validaterange(request.params, heightStart, heightEnd);
1390 : // return object
1391 1 : UniValue ret(UniValue::VOBJ);
1392 1 : ret.pushKV("Starting block", heightStart);
1393 1 : ret.pushKV("Ending block", heightEnd);
1394 :
1395 1 : CAmount nFees = 0;
1396 1 : int64_t nBytes = 0;
1397 1 : int64_t nTxCount = 0;
1398 1 : int64_t nTxCount_all = 0;
1399 :
1400 3 : const CBlockIndex* pindex = WITH_LOCK(cs_main, return chainActive[heightEnd]);
1401 1 : if (!pindex)
1402 0 : throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid block height");
1403 :
1404 31 : while (pindex && pindex->nHeight >= heightStart) {
1405 30 : CBlock block;
1406 30 : if (!ReadBlockFromDisk(block, pindex)) {
1407 0 : throw JSONRPCError(RPC_DATABASE_ERROR, "failed to read block from disk");
1408 : }
1409 :
1410 30 : CAmount nValueIn = 0;
1411 30 : CAmount nValueOut = 0;
1412 30 : const int ntx = block.vtx.size();
1413 30 : const int firstTxIndex = block.IsProofOfStake() ? 2 : 1;
1414 30 : nTxCount_all += ntx;
1415 30 : nTxCount = nTxCount + ntx - firstTxIndex;
1416 :
1417 : // loop through each tx in block and save size and fee (except for coinbase/coinstake)
1418 60 : for (int idx = firstTxIndex; idx < ntx; idx++) {
1419 30 : const CTransaction& tx = *(block.vtx[idx]);
1420 :
1421 : // zerocoin txes have fixed fee, don't count them here.
1422 30 : if (tx.ContainsZerocoins())
1423 0 : continue;
1424 :
1425 : // Transaction size
1426 30 : nBytes += GetSerializeSize(tx, CLIENT_VERSION);
1427 :
1428 : // Transparent inputs
1429 79 : for (unsigned int j = 0; j < tx.vin.size(); j++) {
1430 49 : COutPoint prevout = tx.vin[j].prevout;
1431 49 : CTransactionRef txPrev;
1432 49 : uint256 hashBlock;
1433 49 : if(!GetTransaction(prevout.hash, txPrev, hashBlock, true))
1434 0 : throw JSONRPCError(RPC_DATABASE_ERROR, "failed to read tx from disk");
1435 49 : nValueIn += txPrev->vout[prevout.n].nValue;
1436 : }
1437 : // Shield inputs
1438 30 : nValueIn += tx.GetShieldedValueIn();
1439 :
1440 : // Transparent/Shield outputs
1441 30 : nValueOut += tx.GetValueOut();
1442 :
1443 : // update fee
1444 30 : nFees += nValueIn - nValueOut;
1445 : }
1446 30 : pindex = pindex->pprev;
1447 : }
1448 :
1449 : // get fee rate
1450 1 : CFeeRate nFeeRate = CFeeRate(nFees, nBytes);
1451 :
1452 : // return UniValue object
1453 1 : ret.pushKV("txcount", (int64_t)nTxCount);
1454 1 : ret.pushKV("txcount_all", (int64_t)nTxCount_all);
1455 1 : ret.pushKV("txbytes", (int64_t)nBytes);
1456 2 : ret.pushKV("ttlfee", FormatMoney(nFees));
1457 2 : ret.pushKV("feeperkb", FormatMoney(nFeeRate.GetFeePerK()));
1458 :
1459 1 : return ret;
1460 : }
1461 :
1462 0 : UniValue getfeeinfo(const JSONRPCRequest& request)
1463 : {
1464 0 : if (request.fHelp || request.params.size() != 1)
1465 0 : throw std::runtime_error(
1466 : "getfeeinfo blocks\n"
1467 : "\nReturns details of transaction fees over the last n blocks.\n"
1468 :
1469 : "\nArguments:\n"
1470 : "1. blocks (int, required) the number of blocks to get transaction data from\n"
1471 :
1472 : "\nResult:\n"
1473 : "{\n"
1474 : " \"txcount\": xxxxx (numeric) Current tx count\n"
1475 : " \"txbytes\": xxxxx (numeric) Sum of all tx sizes\n"
1476 : " \"ttlfee\": xxxxx (numeric) Sum of all fees\n"
1477 : " \"feeperkb\": xxxxx (numeric) Average fee per kb over the block range\n"
1478 : " \"rec_highpriorityfee_perkb\": xxxxx (numeric) Recommended fee per kb to use for a high priority tx\n"
1479 : "}\n"
1480 :
1481 0 : "\nExamples:\n" +
1482 0 : HelpExampleCli("getfeeinfo", "5") + HelpExampleRpc("getfeeinfo", "5"));
1483 :
1484 0 : int nBlocks = request.params[0].get_int();
1485 0 : int nBestHeight;
1486 0 : {
1487 0 : LOCK(cs_main);
1488 0 : nBestHeight = chainActive.Height();
1489 : }
1490 0 : int nStartHeight = nBestHeight - nBlocks;
1491 0 : if (nBlocks < 0 || nStartHeight <= 0)
1492 0 : throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid start height");
1493 :
1494 0 : JSONRPCRequest newRequest;
1495 0 : UniValue newParams(UniValue::VARR);
1496 0 : newParams.push_back(UniValue(nStartHeight));
1497 0 : newParams.push_back(UniValue(nBlocks));
1498 0 : newRequest.params = newParams;
1499 :
1500 0 : return getblockindexstats(newRequest);
1501 : }
1502 :
1503 : //! Search for a given set of pubkey scripts
1504 29 : bool FindScriptPubKey(std::atomic<int>& scan_progress, const std::atomic<bool>& should_abort, int64_t& count, CCoinsViewCursor* cursor, const std::set<CScript>& needles, std::map<COutPoint, Coin>& out_results) {
1505 29 : scan_progress = 0;
1506 29 : count = 0;
1507 6873 : while (cursor->Valid()) {
1508 6844 : COutPoint key;
1509 13688 : Coin coin;
1510 6844 : if (!cursor->GetKey(key) || !cursor->GetValue(coin)) return false;
1511 6844 : if (++count % 8192 == 0) {
1512 0 : boost::this_thread::interruption_point();
1513 0 : if (should_abort) {
1514 : // allow to abort the scan via the abort reference
1515 : return false;
1516 : }
1517 : }
1518 6844 : if (count % 256 == 0) {
1519 : // update progress reference every 256 item
1520 0 : uint32_t high = 0x100 * *key.hash.begin() + *(key.hash.begin() + 1);
1521 0 : scan_progress = (int)(high * 100.0 / 65536.0 + 0.5);
1522 : }
1523 13636 : if (needles.count(coin.out.scriptPubKey)) {
1524 52 : out_results.emplace(key, coin);
1525 : }
1526 6844 : cursor->Next();
1527 : }
1528 29 : scan_progress = 100;
1529 29 : return true;
1530 : }
1531 :
1532 : /** RAII object to prevent concurrency issue when scanning the txout set */
1533 : static std::mutex g_utxosetscan;
1534 : static std::atomic<int> g_scan_progress;
1535 : static std::atomic<bool> g_scan_in_progress;
1536 : static std::atomic<bool> g_should_abort_scan;
1537 : class CoinsViewScanReserver
1538 : {
1539 : private:
1540 : bool m_could_reserve;
1541 : public:
1542 29 : explicit CoinsViewScanReserver() : m_could_reserve(false) {}
1543 :
1544 29 : bool reserve() {
1545 29 : assert (!m_could_reserve);
1546 29 : std::lock_guard<std::mutex> lock(g_utxosetscan);
1547 29 : if (g_scan_in_progress) {
1548 : return false;
1549 : }
1550 29 : g_scan_in_progress = true;
1551 29 : m_could_reserve = true;
1552 29 : return true;
1553 : }
1554 :
1555 58 : ~CoinsViewScanReserver() {
1556 29 : if (m_could_reserve) {
1557 58 : std::lock_guard<std::mutex> lock(g_utxosetscan);
1558 29 : g_scan_in_progress = false;
1559 : }
1560 29 : }
1561 : };
1562 :
1563 29 : UniValue scantxoutset(const JSONRPCRequest& request)
1564 : {
1565 29 : if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
1566 0 : throw std::runtime_error(
1567 : "scantxoutset <action> ( <scanobjects> )\n"
1568 : "\nEXPERIMENTAL warning: this call may be removed or changed in future releases.\n"
1569 : "\nScans the unspent transaction output set for entries that match certain output descriptors.\n"
1570 : "Examples of output descriptors are:\n"
1571 : " addr(<address>) Outputs whose scriptPubKey corresponds to the specified address (does not include P2PK)\n"
1572 : " raw(<hex script>) Outputs whose scriptPubKey equals the specified hex scripts\n"
1573 : " combo(<pubkey>) P2PK and P2PKH outputs for the given pubkey\n"
1574 : " pkh(<pubkey>) P2PKH outputs for the given pubkey\n"
1575 : " sh(multi(<n>,<pubkey>,<pubkey>,...)) P2SH-multisig outputs for the given threshold and pubkeys\n"
1576 : "\nIn the above, <pubkey> either refers to a fixed public key in hexadecimal notation, or to an DRKV/DRKP optionally followed by one\n"
1577 : "or more path elements separated by \"/\", and optionally ending in \"/*\" (unhardened), or \"/*'\" or \"/*h\" (hardened) to specify all\n"
1578 : "unhardened or hardened child keys.\n"
1579 : "In the latter case, a range needs to be specified by below if different from 1000.\n"
1580 : "For more information on output descriptors, see the documentation in the doc/descriptors.md file.\n"
1581 : "\nArguments:\n"
1582 : "1. \"action\" (string, required) The action to execute\n"
1583 : " \"start\" for starting a scan\n"
1584 : " \"abort\" for aborting the current scan (returns true when abort was successful)\n"
1585 : " \"status\" for progress report (in %) of the current scan\n"
1586 : "2. \"scanobjects\" (array, required) Array of scan objects\n"
1587 : " [ Every scan object is either a string descriptor or an object:\n"
1588 : " \"descriptor\", (string, optional) An output descriptor\n"
1589 : " { (object, optional) An object with output descriptor and metadata\n"
1590 : " \"desc\": \"descriptor\", (string, required) An output descriptor\n"
1591 : " \"range\": n, (numeric, optional) Up to what child index HD chains should be explored (default: 1000)\n"
1592 : " },\n"
1593 : " ...\n"
1594 : " ]\n"
1595 : "\nResult:\n"
1596 : "{\n"
1597 : " \"unspents\": [\n"
1598 : " {\n"
1599 : " \"txid\" : \"transactionid\", (string) The transaction id\n"
1600 : " \"vout\": n, (numeric) the vout value\n"
1601 : " \"scriptPubKey\" : \"script\", (string) the script key\n"
1602 0 : " \"amount\" : x.xxx, (numeric) The total amount in " + CURRENCY_UNIT + " of the unspent output\n"
1603 : " \"height\" : n, (numeric) Height of the unspent transaction output\n"
1604 : " }\n"
1605 : " ,...], \n"
1606 0 : " \"total_amount\" : x.xxx, (numeric) The total amount of all found unspent outputs in " + CURRENCY_UNIT + "\n"
1607 : "]\n"
1608 0 : );
1609 :
1610 29 : RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR});
1611 :
1612 58 : UniValue result(UniValue::VOBJ);
1613 29 : if (request.params[0].get_str() == "status") {
1614 0 : CoinsViewScanReserver reserver;
1615 0 : if (reserver.reserve()) {
1616 : // no scan in progress
1617 0 : return NullUniValue;
1618 : }
1619 0 : result.pushKV("progress", g_scan_progress);
1620 0 : return result;
1621 29 : } else if (request.params[0].get_str() == "abort") {
1622 0 : CoinsViewScanReserver reserver;
1623 0 : if (reserver.reserve()) {
1624 : // reserve was possible which means no scan was running
1625 0 : return false;
1626 : }
1627 : // set the abort flag
1628 0 : g_should_abort_scan = true;
1629 0 : return true;
1630 29 : } else if (request.params[0].get_str() == "start") {
1631 0 : CoinsViewScanReserver reserver;
1632 29 : if (!reserver.reserve()) {
1633 0 : throw JSONRPCError(RPC_INVALID_PARAMETER, "Scan already in progress, use action \"abort\" or \"status\"");
1634 : }
1635 58 : std::set<CScript> needles;
1636 29 : CAmount total_in = 0;
1637 :
1638 : // loop through the scan objects
1639 66 : for (const UniValue& scanobject : request.params[1].get_array().getValues()) {
1640 74 : std::string desc_str;
1641 37 : int range = 1000;
1642 37 : if (scanobject.isStr()) {
1643 27 : desc_str = scanobject.get_str();
1644 10 : } else if (scanobject.isObject()) {
1645 20 : UniValue desc_uni = find_value(scanobject, "desc");
1646 10 : if (desc_uni.isNull()) throw JSONRPCError(RPC_INVALID_PARAMETER, "Descriptor needs to be provided in scan object");
1647 10 : desc_str = desc_uni.get_str();
1648 20 : UniValue range_uni = find_value(scanobject, "range");
1649 10 : if (!range_uni.isNull()) {
1650 10 : range = range_uni.get_int();
1651 10 : if (range < 0 || range > 1000000) throw JSONRPCError(RPC_INVALID_PARAMETER, "range out of range");
1652 : }
1653 : } else {
1654 0 : throw JSONRPCError(RPC_INVALID_PARAMETER, "Scan object needs to be either a string or an object");
1655 : }
1656 :
1657 74 : FlatSigningProvider provider;
1658 74 : auto desc = Parse(desc_str, provider);
1659 37 : if (!desc) {
1660 0 : throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Invalid descriptor '%s'", desc_str));
1661 : }
1662 37 : if (!desc->IsRange()) range = 0;
1663 15069 : for (int i = 0; i <= range; ++i) {
1664 15032 : std::vector<CScript> scripts;
1665 15032 : if (!desc->Expand(i, provider, scripts, provider)) {
1666 0 : throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Cannot derive script without private keys: '%s'", desc_str));
1667 : }
1668 15032 : needles.insert(scripts.begin(), scripts.end());
1669 : }
1670 : }
1671 :
1672 : // Scan the unspent transaction output set for inputs
1673 58 : UniValue unspents(UniValue::VARR);
1674 29 : std::vector<CTxOut> input_txos;
1675 58 : std::map<COutPoint, Coin> coins;
1676 29 : g_should_abort_scan = false;
1677 29 : g_scan_progress = 0;
1678 29 : int64_t count = 0;
1679 29 : std::unique_ptr<CCoinsViewCursor> pcursor;
1680 29 : {
1681 29 : LOCK(cs_main);
1682 29 : FlushStateToDisk();
1683 29 : pcursor = std::unique_ptr<CCoinsViewCursor>(pcoinsdbview->Cursor());
1684 29 : assert(pcursor);
1685 : }
1686 29 : bool res = FindScriptPubKey(g_scan_progress, g_should_abort_scan, count, pcursor.get(), needles, coins);
1687 29 : result.pushKV("success", res);
1688 29 : result.pushKV("searched_items", count);
1689 :
1690 81 : for (const auto& it : coins) {
1691 52 : const COutPoint& outpoint = it.first;
1692 52 : const Coin& coin = it.second;
1693 52 : const CTxOut& txo = coin.out;
1694 52 : input_txos.push_back(txo);
1695 52 : total_in += txo.nValue;
1696 :
1697 104 : UniValue unspent(UniValue::VOBJ);
1698 104 : unspent.pushKV("txid", outpoint.hash.GetHex());
1699 52 : unspent.pushKV("vout", (int32_t)outpoint.n);
1700 156 : unspent.pushKV("scriptPubKey", HexStr(txo.scriptPubKey));
1701 104 : unspent.pushKV("amount", ValueFromAmount(txo.nValue));
1702 52 : unspent.pushKV("height", (int32_t)coin.nHeight);
1703 :
1704 52 : unspents.push_back(unspent);
1705 : }
1706 29 : result.pushKV("unspents", unspents);
1707 58 : result.pushKV("total_amount", ValueFromAmount(total_in));
1708 : } else {
1709 0 : throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid command");
1710 : }
1711 29 : return result;
1712 : }
1713 :
1714 : // clang-format off
1715 : static const CRPCCommand commands[] =
1716 : { // category name actor (function) okSafe argNames
1717 : // --------------------- ------------------------ ----------------------- ------ --------
1718 : { "blockchain", "getbestblockhash", &getbestblockhash, true, {} },
1719 : { "blockchain", "getbestsaplinganchor", &getbestsaplinganchor, true, {} },
1720 : { "blockchain", "getblock", &getblock, true, {"blockhash","verbose|verbosity"} },
1721 : { "blockchain", "getblockchaininfo", &getblockchaininfo, true, {} },
1722 : { "blockchain", "getbestchainlock", &getbestchainlock, true, {} },
1723 : { "blockchain", "getblockcount", &getblockcount, true, {} },
1724 : { "blockchain", "getblockhash", &getblockhash, true, {"height"} },
1725 : { "blockchain", "getblockheader", &getblockheader, false, {"blockhash","verbose"} },
1726 : { "blockchain", "getblockindexstats", &getblockindexstats, true, {"height","range"} },
1727 : { "blockchain", "getchaintips", &getchaintips, true, {} },
1728 : { "blockchain", "getdifficulty", &getdifficulty, true, {} },
1729 : { "blockchain", "getfeeinfo", &getfeeinfo, true, {"blocks"} },
1730 : { "blockchain", "getmempoolinfo", &getmempoolinfo, true, {} },
1731 : { "blockchain", "getrawmempool", &getrawmempool, true, {"verbose"} },
1732 : { "blockchain", "getsupplyinfo", &getsupplyinfo, true, {"force_update"} },
1733 : { "blockchain", "gettxout", &gettxout, true, {"txid","n","include_mempool"} },
1734 : { "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, true, {} },
1735 : { "blockchain", "scantxoutset", &scantxoutset, true, {"action", "scanobjects"} },
1736 : { "blockchain", "verifychain", &verifychain, true, {"nblocks"} },
1737 :
1738 : /* Not shown in help */
1739 : { "hidden", "invalidateblock", &invalidateblock, true, {"blockhash"} },
1740 : { "hidden", "reconsiderblock", &reconsiderblock, true, {"blockhash"} },
1741 : { "hidden", "waitforblock", &waitforblock, true, {"blockhash","timeout"} },
1742 : { "hidden", "waitforblockheight", &waitforblockheight, true, {"height","timeout"} },
1743 : { "hidden", "waitfornewblock", &waitfornewblock, true, {"timeout"} },
1744 : { "hidden", "syncwithvalidationinterfacequeue", &syncwithvalidationinterfacequeue, true, {} },
1745 : };
1746 : // clang-format on
1747 :
1748 494 : void RegisterBlockchainRPCCommands(CRPCTable &tableRPC)
1749 : {
1750 12844 : for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
1751 12350 : tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
1752 494 : }
|