1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2020 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 <rpc/blockchain.h>
7 
8 #include <amount.h>
9 #include <blockfilter.h>
10 #include <chain.h>
11 #include <chainparams.h>
12 #include <coins.h>
13 #include <consensus/params.h>
14 #include <consensus/validation.h>
15 #include <core_io.h>
16 #include <deploymentinfo.h>
17 #include <deploymentstatus.h>
18 #include <hash.h>
19 #include <index/blockfilterindex.h>
20 #include <index/coinstatsindex.h>
21 #include <node/blockstorage.h>
22 #include <node/coinstats.h>
23 #include <node/context.h>
24 #include <node/utxo_snapshot.h>
25 #include <policy/feerate.h>
26 #include <policy/fees.h>
27 #include <policy/policy.h>
28 #include <policy/rbf.h>
29 #include <primitives/transaction.h>
30 #include <rpc/server.h>
31 #include <rpc/util.h>
32 #include <script/descriptor.h>
33 #include <streams.h>
34 #include <sync.h>
35 #include <txdb.h>
36 #include <txmempool.h>
37 #include <undo.h>
38 #include <util/strencodings.h>
39 #include <util/system.h>
40 #include <util/translation.h>
41 #include <validation.h>
42 #include <validationinterface.h>
43 #include <versionbits.h>
44 #include <warnings.h>
45 
46 #include <stdint.h>
47 
48 #include <univalue.h>
49 
50 #include <condition_variable>
51 #include <memory>
52 #include <mutex>
53 
54 struct CUpdatedBlock
55 {
56     uint256 hash;
57     int height;
58 };
59 
60 static Mutex cs_blockchange;
61 static std::condition_variable cond_blockchange;
62 static CUpdatedBlock latestblock GUARDED_BY(cs_blockchange);
63 
EnsureAnyNodeContext(const std::any & context)64 NodeContext& EnsureAnyNodeContext(const std::any& context)
65 {
66     auto node_context = util::AnyPtr<NodeContext>(context);
67     if (!node_context) {
68         throw JSONRPCError(RPC_INTERNAL_ERROR, "Node context not found");
69     }
70     return *node_context;
71 }
72 
EnsureMemPool(const NodeContext & node)73 CTxMemPool& EnsureMemPool(const NodeContext& node)
74 {
75     if (!node.mempool) {
76         throw JSONRPCError(RPC_CLIENT_MEMPOOL_DISABLED, "Mempool disabled or instance not found");
77     }
78     return *node.mempool;
79 }
80 
EnsureAnyMemPool(const std::any & context)81 CTxMemPool& EnsureAnyMemPool(const std::any& context)
82 {
83     return EnsureMemPool(EnsureAnyNodeContext(context));
84 }
85 
EnsureChainman(const NodeContext & node)86 ChainstateManager& EnsureChainman(const NodeContext& node)
87 {
88     if (!node.chainman) {
89         throw JSONRPCError(RPC_INTERNAL_ERROR, "Node chainman not found");
90     }
91     return *node.chainman;
92 }
93 
EnsureAnyChainman(const std::any & context)94 ChainstateManager& EnsureAnyChainman(const std::any& context)
95 {
96     return EnsureChainman(EnsureAnyNodeContext(context));
97 }
98 
EnsureFeeEstimator(const NodeContext & node)99 CBlockPolicyEstimator& EnsureFeeEstimator(const NodeContext& node)
100 {
101     if (!node.fee_estimator) {
102         throw JSONRPCError(RPC_INTERNAL_ERROR, "Fee estimation disabled");
103     }
104     return *node.fee_estimator;
105 }
106 
EnsureAnyFeeEstimator(const std::any & context)107 CBlockPolicyEstimator& EnsureAnyFeeEstimator(const std::any& context)
108 {
109     return EnsureFeeEstimator(EnsureAnyNodeContext(context));
110 }
111 
112 /* Calculate the difficulty for a given block index.
113  */
GetDifficulty(const CBlockIndex * blockindex)114 double GetDifficulty(const CBlockIndex* blockindex)
115 {
116     CHECK_NONFATAL(blockindex);
117 
118     int nShift = (blockindex->nBits >> 24) & 0xff;
119     double dDiff =
120         (double)0x0000ffff / (double)(blockindex->nBits & 0x00ffffff);
121 
122     while (nShift < 29)
123     {
124         dDiff *= 256.0;
125         nShift++;
126     }
127     while (nShift > 29)
128     {
129         dDiff /= 256.0;
130         nShift--;
131     }
132 
133     return dDiff;
134 }
135 
ComputeNextBlockAndDepth(const CBlockIndex * tip,const CBlockIndex * blockindex,const CBlockIndex * & next)136 static int ComputeNextBlockAndDepth(const CBlockIndex* tip, const CBlockIndex* blockindex, const CBlockIndex*& next)
137 {
138     next = tip->GetAncestor(blockindex->nHeight + 1);
139     if (next && next->pprev == blockindex) {
140         return tip->nHeight - blockindex->nHeight + 1;
141     }
142     next = nullptr;
143     return blockindex == tip ? 1 : -1;
144 }
145 
ParseHashOrHeight(const UniValue & param,ChainstateManager & chainman)146 CBlockIndex* ParseHashOrHeight(const UniValue& param, ChainstateManager& chainman) {
147     LOCK(::cs_main);
148     CChain& active_chain = chainman.ActiveChain();
149 
150     if (param.isNum()) {
151         const int height{param.get_int()};
152         if (height < 0) {
153             throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Target block height %d is negative", height));
154         }
155         const int current_tip{active_chain.Height()};
156         if (height > current_tip) {
157             throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Target block height %d after current tip %d", height, current_tip));
158         }
159 
160         return active_chain[height];
161     } else {
162         const uint256 hash{ParseHashV(param, "hash_or_height")};
163         CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(hash);
164 
165         if (!pindex) {
166             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
167         }
168 
169         return pindex;
170     }
171 }
172 
blockheaderToJSON(const CBlockIndex * tip,const CBlockIndex * blockindex)173 UniValue blockheaderToJSON(const CBlockIndex* tip, const CBlockIndex* blockindex)
174 {
175     // Serialize passed information without accessing chain state of the active chain!
176     AssertLockNotHeld(cs_main); // For performance reasons
177 
178     UniValue result(UniValue::VOBJ);
179     result.pushKV("hash", blockindex->GetBlockHash().GetHex());
180     const CBlockIndex* pnext;
181     int confirmations = ComputeNextBlockAndDepth(tip, blockindex, pnext);
182     result.pushKV("confirmations", confirmations);
183     result.pushKV("height", blockindex->nHeight);
184     result.pushKV("version", blockindex->nVersion);
185     result.pushKV("versionHex", strprintf("%08x", blockindex->nVersion));
186     result.pushKV("merkleroot", blockindex->hashMerkleRoot.GetHex());
187     result.pushKV("time", (int64_t)blockindex->nTime);
188     result.pushKV("mediantime", (int64_t)blockindex->GetMedianTimePast());
189     result.pushKV("nonce", (uint64_t)blockindex->nNonce);
190     result.pushKV("bits", strprintf("%08x", blockindex->nBits));
191     result.pushKV("difficulty", GetDifficulty(blockindex));
192     result.pushKV("chainwork", blockindex->nChainWork.GetHex());
193     result.pushKV("nTx", (uint64_t)blockindex->nTx);
194 
195     if (blockindex->pprev)
196         result.pushKV("previousblockhash", blockindex->pprev->GetBlockHash().GetHex());
197     if (pnext)
198         result.pushKV("nextblockhash", pnext->GetBlockHash().GetHex());
199     return result;
200 }
201 
blockToJSON(const CBlock & block,const CBlockIndex * tip,const CBlockIndex * blockindex,bool txDetails)202 UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, bool txDetails)
203 {
204     UniValue result = blockheaderToJSON(tip, blockindex);
205 
206     result.pushKV("strippedsize", (int)::GetSerializeSize(block, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS));
207     result.pushKV("size", (int)::GetSerializeSize(block, PROTOCOL_VERSION));
208     result.pushKV("weight", (int)::GetBlockWeight(block));
209     UniValue txs(UniValue::VARR);
210     if (txDetails) {
211         CBlockUndo blockUndo;
212         const bool have_undo = !IsBlockPruned(blockindex) && UndoReadFromDisk(blockUndo, blockindex);
213         for (size_t i = 0; i < block.vtx.size(); ++i) {
214             const CTransactionRef& tx = block.vtx.at(i);
215             // coinbase transaction (i == 0) doesn't have undo data
216             const CTxUndo* txundo = (have_undo && i) ? &blockUndo.vtxundo.at(i - 1) : nullptr;
217             UniValue objTx(UniValue::VOBJ);
218             TxToUniv(*tx, uint256(), objTx, true, RPCSerializationFlags(), txundo);
219             txs.push_back(objTx);
220         }
221     } else {
222         for (const CTransactionRef& tx : block.vtx) {
223             txs.push_back(tx->GetHash().GetHex());
224         }
225     }
226     result.pushKV("tx", txs);
227 
228     return result;
229 }
230 
getblockcount()231 static RPCHelpMan getblockcount()
232 {
233     return RPCHelpMan{"getblockcount",
234                 "\nReturns the height of the most-work fully-validated chain.\n"
235                 "The genesis block has height 0.\n",
236                 {},
237                 RPCResult{
238                     RPCResult::Type::NUM, "", "The current block count"},
239                 RPCExamples{
240                     HelpExampleCli("getblockcount", "")
241             + HelpExampleRpc("getblockcount", "")
242                 },
243         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
244 {
245     ChainstateManager& chainman = EnsureAnyChainman(request.context);
246     LOCK(cs_main);
247     return chainman.ActiveChain().Height();
248 },
249     };
250 }
251 
getbestblockhash()252 static RPCHelpMan getbestblockhash()
253 {
254     return RPCHelpMan{"getbestblockhash",
255                 "\nReturns the hash of the best (tip) block in the most-work fully-validated chain.\n",
256                 {},
257                 RPCResult{
258                     RPCResult::Type::STR_HEX, "", "the block hash, hex-encoded"},
259                 RPCExamples{
260                     HelpExampleCli("getbestblockhash", "")
261             + HelpExampleRpc("getbestblockhash", "")
262                 },
263         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
264 {
265     ChainstateManager& chainman = EnsureAnyChainman(request.context);
266     LOCK(cs_main);
267     return chainman.ActiveChain().Tip()->GetBlockHash().GetHex();
268 },
269     };
270 }
271 
RPCNotifyBlockChange(const CBlockIndex * pindex)272 void RPCNotifyBlockChange(const CBlockIndex* pindex)
273 {
274     if(pindex) {
275         LOCK(cs_blockchange);
276         latestblock.hash = pindex->GetBlockHash();
277         latestblock.height = pindex->nHeight;
278     }
279     cond_blockchange.notify_all();
280 }
281 
waitfornewblock()282 static RPCHelpMan waitfornewblock()
283 {
284     return RPCHelpMan{"waitfornewblock",
285                 "\nWaits for a specific new block and returns useful info about it.\n"
286                 "\nReturns the current block on timeout or exit.\n",
287                 {
288                     {"timeout", RPCArg::Type::NUM, RPCArg::Default{0}, "Time in milliseconds to wait for a response. 0 indicates no timeout."},
289                 },
290                 RPCResult{
291                     RPCResult::Type::OBJ, "", "",
292                     {
293                         {RPCResult::Type::STR_HEX, "hash", "The blockhash"},
294                         {RPCResult::Type::NUM, "height", "Block height"},
295                     }},
296                 RPCExamples{
297                     HelpExampleCli("waitfornewblock", "1000")
298             + HelpExampleRpc("waitfornewblock", "1000")
299                 },
300         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
301 {
302     int timeout = 0;
303     if (!request.params[0].isNull())
304         timeout = request.params[0].get_int();
305 
306     CUpdatedBlock block;
307     {
308         WAIT_LOCK(cs_blockchange, lock);
309         block = latestblock;
310         if(timeout)
311             cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&block]() EXCLUSIVE_LOCKS_REQUIRED(cs_blockchange) {return latestblock.height != block.height || latestblock.hash != block.hash || !IsRPCRunning(); });
312         else
313             cond_blockchange.wait(lock, [&block]() EXCLUSIVE_LOCKS_REQUIRED(cs_blockchange) {return latestblock.height != block.height || latestblock.hash != block.hash || !IsRPCRunning(); });
314         block = latestblock;
315     }
316     UniValue ret(UniValue::VOBJ);
317     ret.pushKV("hash", block.hash.GetHex());
318     ret.pushKV("height", block.height);
319     return ret;
320 },
321     };
322 }
323 
waitforblock()324 static RPCHelpMan waitforblock()
325 {
326     return RPCHelpMan{"waitforblock",
327                 "\nWaits for a specific new block and returns useful info about it.\n"
328                 "\nReturns the current block on timeout or exit.\n",
329                 {
330                     {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "Block hash to wait for."},
331                     {"timeout", RPCArg::Type::NUM, RPCArg::Default{0}, "Time in milliseconds to wait for a response. 0 indicates no timeout."},
332                 },
333                 RPCResult{
334                     RPCResult::Type::OBJ, "", "",
335                     {
336                         {RPCResult::Type::STR_HEX, "hash", "The blockhash"},
337                         {RPCResult::Type::NUM, "height", "Block height"},
338                     }},
339                 RPCExamples{
340                     HelpExampleCli("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\" 1000")
341             + HelpExampleRpc("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\", 1000")
342                 },
343         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
344 {
345     int timeout = 0;
346 
347     uint256 hash(ParseHashV(request.params[0], "blockhash"));
348 
349     if (!request.params[1].isNull())
350         timeout = request.params[1].get_int();
351 
352     CUpdatedBlock block;
353     {
354         WAIT_LOCK(cs_blockchange, lock);
355         if(timeout)
356             cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&hash]() EXCLUSIVE_LOCKS_REQUIRED(cs_blockchange) {return latestblock.hash == hash || !IsRPCRunning();});
357         else
358             cond_blockchange.wait(lock, [&hash]() EXCLUSIVE_LOCKS_REQUIRED(cs_blockchange) {return latestblock.hash == hash || !IsRPCRunning(); });
359         block = latestblock;
360     }
361 
362     UniValue ret(UniValue::VOBJ);
363     ret.pushKV("hash", block.hash.GetHex());
364     ret.pushKV("height", block.height);
365     return ret;
366 },
367     };
368 }
369 
waitforblockheight()370 static RPCHelpMan waitforblockheight()
371 {
372     return RPCHelpMan{"waitforblockheight",
373                 "\nWaits for (at least) block height and returns the height and hash\n"
374                 "of the current tip.\n"
375                 "\nReturns the current block on timeout or exit.\n",
376                 {
377                     {"height", RPCArg::Type::NUM, RPCArg::Optional::NO, "Block height to wait for."},
378                     {"timeout", RPCArg::Type::NUM, RPCArg::Default{0}, "Time in milliseconds to wait for a response. 0 indicates no timeout."},
379                 },
380                 RPCResult{
381                     RPCResult::Type::OBJ, "", "",
382                     {
383                         {RPCResult::Type::STR_HEX, "hash", "The blockhash"},
384                         {RPCResult::Type::NUM, "height", "Block height"},
385                     }},
386                 RPCExamples{
387                     HelpExampleCli("waitforblockheight", "100 1000")
388             + HelpExampleRpc("waitforblockheight", "100, 1000")
389                 },
390         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
391 {
392     int timeout = 0;
393 
394     int height = request.params[0].get_int();
395 
396     if (!request.params[1].isNull())
397         timeout = request.params[1].get_int();
398 
399     CUpdatedBlock block;
400     {
401         WAIT_LOCK(cs_blockchange, lock);
402         if(timeout)
403             cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&height]() EXCLUSIVE_LOCKS_REQUIRED(cs_blockchange) {return latestblock.height >= height || !IsRPCRunning();});
404         else
405             cond_blockchange.wait(lock, [&height]() EXCLUSIVE_LOCKS_REQUIRED(cs_blockchange) {return latestblock.height >= height || !IsRPCRunning(); });
406         block = latestblock;
407     }
408     UniValue ret(UniValue::VOBJ);
409     ret.pushKV("hash", block.hash.GetHex());
410     ret.pushKV("height", block.height);
411     return ret;
412 },
413     };
414 }
415 
syncwithvalidationinterfacequeue()416 static RPCHelpMan syncwithvalidationinterfacequeue()
417 {
418     return RPCHelpMan{"syncwithvalidationinterfacequeue",
419                 "\nWaits for the validation interface queue to catch up on everything that was there when we entered this function.\n",
420                 {},
421                 RPCResult{RPCResult::Type::NONE, "", ""},
422                 RPCExamples{
423                     HelpExampleCli("syncwithvalidationinterfacequeue","")
424             + HelpExampleRpc("syncwithvalidationinterfacequeue","")
425                 },
426         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
427 {
428     SyncWithValidationInterfaceQueue();
429     return NullUniValue;
430 },
431     };
432 }
433 
getdifficulty()434 static RPCHelpMan getdifficulty()
435 {
436     return RPCHelpMan{"getdifficulty",
437                 "\nReturns the proof-of-work difficulty as a multiple of the minimum difficulty.\n",
438                 {},
439                 RPCResult{
440                     RPCResult::Type::NUM, "", "the proof-of-work difficulty as a multiple of the minimum difficulty."},
441                 RPCExamples{
442                     HelpExampleCli("getdifficulty", "")
443             + HelpExampleRpc("getdifficulty", "")
444                 },
445         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
446 {
447     ChainstateManager& chainman = EnsureAnyChainman(request.context);
448     LOCK(cs_main);
449     return GetDifficulty(chainman.ActiveChain().Tip());
450 },
451     };
452 }
453 
MempoolEntryDescription()454 static std::vector<RPCResult> MempoolEntryDescription() { return {
455     RPCResult{RPCResult::Type::NUM, "vsize", "virtual transaction size as defined in BIP 141. This is different from actual serialized size for witness transactions as witness data is discounted."},
456     RPCResult{RPCResult::Type::NUM, "weight", "transaction weight as defined in BIP 141."},
457     RPCResult{RPCResult::Type::STR_AMOUNT, "fee", "transaction fee in " + CURRENCY_UNIT + " (DEPRECATED)"},
458     RPCResult{RPCResult::Type::STR_AMOUNT, "modifiedfee", "transaction fee with fee deltas used for mining priority (DEPRECATED)"},
459     RPCResult{RPCResult::Type::NUM_TIME, "time", "local time transaction entered pool in seconds since 1 Jan 1970 GMT"},
460     RPCResult{RPCResult::Type::NUM, "height", "block height when transaction entered pool"},
461     RPCResult{RPCResult::Type::NUM, "descendantcount", "number of in-mempool descendant transactions (including this one)"},
462     RPCResult{RPCResult::Type::NUM, "descendantsize", "virtual transaction size of in-mempool descendants (including this one)"},
463     RPCResult{RPCResult::Type::STR_AMOUNT, "descendantfees", "modified fees (see above) of in-mempool descendants (including this one) (DEPRECATED)"},
464     RPCResult{RPCResult::Type::NUM, "ancestorcount", "number of in-mempool ancestor transactions (including this one)"},
465     RPCResult{RPCResult::Type::NUM, "ancestorsize", "virtual transaction size of in-mempool ancestors (including this one)"},
466     RPCResult{RPCResult::Type::STR_AMOUNT, "ancestorfees", "modified fees (see above) of in-mempool ancestors (including this one) (DEPRECATED)"},
467     RPCResult{RPCResult::Type::STR_HEX, "wtxid", "hash of serialized transaction, including witness data"},
468     RPCResult{RPCResult::Type::OBJ, "fees", "",
469         {
470             RPCResult{RPCResult::Type::STR_AMOUNT, "base", "transaction fee in " + CURRENCY_UNIT},
471             RPCResult{RPCResult::Type::STR_AMOUNT, "modified", "transaction fee with fee deltas used for mining priority in " + CURRENCY_UNIT},
472             RPCResult{RPCResult::Type::STR_AMOUNT, "ancestor", "modified fees (see above) of in-mempool ancestors (including this one) in " + CURRENCY_UNIT},
473             RPCResult{RPCResult::Type::STR_AMOUNT, "descendant", "modified fees (see above) of in-mempool descendants (including this one) in " + CURRENCY_UNIT},
474         }},
475     RPCResult{RPCResult::Type::ARR, "depends", "unconfirmed transactions used as inputs for this transaction",
476         {RPCResult{RPCResult::Type::STR_HEX, "transactionid", "parent transaction id"}}},
477     RPCResult{RPCResult::Type::ARR, "spentby", "unconfirmed transactions spending outputs from this transaction",
478         {RPCResult{RPCResult::Type::STR_HEX, "transactionid", "child transaction id"}}},
479     RPCResult{RPCResult::Type::BOOL, "bip125-replaceable", "Whether this transaction could be replaced due to BIP125 (replace-by-fee)"},
480     RPCResult{RPCResult::Type::BOOL, "unbroadcast", "Whether this transaction is currently unbroadcast (initial broadcast not yet acknowledged by any peers)"},
481 };}
482 
entryToJSON(const CTxMemPool & pool,UniValue & info,const CTxMemPoolEntry & e)483 static void entryToJSON(const CTxMemPool& pool, UniValue& info, const CTxMemPoolEntry& e) EXCLUSIVE_LOCKS_REQUIRED(pool.cs)
484 {
485     AssertLockHeld(pool.cs);
486 
487     UniValue fees(UniValue::VOBJ);
488     fees.pushKV("base", ValueFromAmount(e.GetFee()));
489     fees.pushKV("modified", ValueFromAmount(e.GetModifiedFee()));
490     fees.pushKV("ancestor", ValueFromAmount(e.GetModFeesWithAncestors()));
491     fees.pushKV("descendant", ValueFromAmount(e.GetModFeesWithDescendants()));
492     info.pushKV("fees", fees);
493 
494     info.pushKV("vsize", (int)e.GetTxSize());
495     info.pushKV("weight", (int)e.GetTxWeight());
496     info.pushKV("fee", ValueFromAmount(e.GetFee()));
497     info.pushKV("modifiedfee", ValueFromAmount(e.GetModifiedFee()));
498     info.pushKV("time", count_seconds(e.GetTime()));
499     info.pushKV("height", (int)e.GetHeight());
500     info.pushKV("descendantcount", e.GetCountWithDescendants());
501     info.pushKV("descendantsize", e.GetSizeWithDescendants());
502     info.pushKV("descendantfees", e.GetModFeesWithDescendants());
503     info.pushKV("ancestorcount", e.GetCountWithAncestors());
504     info.pushKV("ancestorsize", e.GetSizeWithAncestors());
505     info.pushKV("ancestorfees", e.GetModFeesWithAncestors());
506     info.pushKV("wtxid", pool.vTxHashes[e.vTxHashesIdx].first.ToString());
507     const CTransaction& tx = e.GetTx();
508     std::set<std::string> setDepends;
509     for (const CTxIn& txin : tx.vin)
510     {
511         if (pool.exists(txin.prevout.hash))
512             setDepends.insert(txin.prevout.hash.ToString());
513     }
514 
515     UniValue depends(UniValue::VARR);
516     for (const std::string& dep : setDepends)
517     {
518         depends.push_back(dep);
519     }
520 
521     info.pushKV("depends", depends);
522 
523     UniValue spent(UniValue::VARR);
524     const CTxMemPool::txiter& it = pool.mapTx.find(tx.GetHash());
525     const CTxMemPoolEntry::Children& children = it->GetMemPoolChildrenConst();
526     for (const CTxMemPoolEntry& child : children) {
527         spent.push_back(child.GetTx().GetHash().ToString());
528     }
529 
530     info.pushKV("spentby", spent);
531 
532     // Add opt-in RBF status
533     bool rbfStatus = false;
534     RBFTransactionState rbfState = IsRBFOptIn(tx, pool);
535     if (rbfState == RBFTransactionState::UNKNOWN) {
536         throw JSONRPCError(RPC_MISC_ERROR, "Transaction is not in mempool");
537     } else if (rbfState == RBFTransactionState::REPLACEABLE_BIP125) {
538         rbfStatus = true;
539     }
540 
541     info.pushKV("bip125-replaceable", rbfStatus);
542     info.pushKV("unbroadcast", pool.IsUnbroadcastTx(tx.GetHash()));
543 }
544 
MempoolToJSON(const CTxMemPool & pool,bool verbose,bool include_mempool_sequence)545 UniValue MempoolToJSON(const CTxMemPool& pool, bool verbose, bool include_mempool_sequence)
546 {
547     if (verbose) {
548         if (include_mempool_sequence) {
549             throw JSONRPCError(RPC_INVALID_PARAMETER, "Verbose results cannot contain mempool sequence values.");
550         }
551         LOCK(pool.cs);
552         UniValue o(UniValue::VOBJ);
553         for (const CTxMemPoolEntry& e : pool.mapTx) {
554             const uint256& hash = e.GetTx().GetHash();
555             UniValue info(UniValue::VOBJ);
556             entryToJSON(pool, info, e);
557             // Mempool has unique entries so there is no advantage in using
558             // UniValue::pushKV, which checks if the key already exists in O(N).
559             // UniValue::__pushKV is used instead which currently is O(1).
560             o.__pushKV(hash.ToString(), info);
561         }
562         return o;
563     } else {
564         uint64_t mempool_sequence;
565         std::vector<uint256> vtxid;
566         {
567             LOCK(pool.cs);
568             pool.queryHashes(vtxid);
569             mempool_sequence = pool.GetSequence();
570         }
571         UniValue a(UniValue::VARR);
572         for (const uint256& hash : vtxid)
573             a.push_back(hash.ToString());
574 
575         if (!include_mempool_sequence) {
576             return a;
577         } else {
578             UniValue o(UniValue::VOBJ);
579             o.pushKV("txids", a);
580             o.pushKV("mempool_sequence", mempool_sequence);
581             return o;
582         }
583     }
584 }
585 
getrawmempool()586 static RPCHelpMan getrawmempool()
587 {
588     return RPCHelpMan{"getrawmempool",
589                 "\nReturns all transaction ids in memory pool as a json array of string transaction ids.\n"
590                 "\nHint: use getmempoolentry to fetch a specific transaction from the mempool.\n",
591                 {
592                     {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "True for a json object, false for array of transaction ids"},
593                     {"mempool_sequence", RPCArg::Type::BOOL, RPCArg::Default{false}, "If verbose=false, returns a json object with transaction list and mempool sequence number attached."},
594                 },
595                 {
596                     RPCResult{"for verbose = false",
597                         RPCResult::Type::ARR, "", "",
598                         {
599                             {RPCResult::Type::STR_HEX, "", "The transaction id"},
600                         }},
601                     RPCResult{"for verbose = true",
602                         RPCResult::Type::OBJ_DYN, "", "",
603                         {
604                             {RPCResult::Type::OBJ, "transactionid", "", MempoolEntryDescription()},
605                         }},
606                     RPCResult{"for verbose = false and mempool_sequence = true",
607                         RPCResult::Type::OBJ, "", "",
608                         {
609                             {RPCResult::Type::ARR, "txids", "",
610                             {
611                                 {RPCResult::Type::STR_HEX, "", "The transaction id"},
612                             }},
613                             {RPCResult::Type::NUM, "mempool_sequence", "The mempool sequence value."},
614                         }},
615                 },
616                 RPCExamples{
617                     HelpExampleCli("getrawmempool", "true")
618             + HelpExampleRpc("getrawmempool", "true")
619                 },
620         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
621 {
622     bool fVerbose = false;
623     if (!request.params[0].isNull())
624         fVerbose = request.params[0].get_bool();
625 
626     bool include_mempool_sequence = false;
627     if (!request.params[1].isNull()) {
628         include_mempool_sequence = request.params[1].get_bool();
629     }
630 
631     return MempoolToJSON(EnsureAnyMemPool(request.context), fVerbose, include_mempool_sequence);
632 },
633     };
634 }
635 
getmempoolancestors()636 static RPCHelpMan getmempoolancestors()
637 {
638     return RPCHelpMan{"getmempoolancestors",
639                 "\nIf txid is in the mempool, returns all in-mempool ancestors.\n",
640                 {
641                     {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id (must be in mempool)"},
642                     {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "True for a json object, false for array of transaction ids"},
643                 },
644                 {
645                     RPCResult{"for verbose = false",
646                         RPCResult::Type::ARR, "", "",
647                         {{RPCResult::Type::STR_HEX, "", "The transaction id of an in-mempool ancestor transaction"}}},
648                     RPCResult{"for verbose = true",
649                         RPCResult::Type::OBJ_DYN, "", "",
650                         {
651                             {RPCResult::Type::OBJ, "transactionid", "", MempoolEntryDescription()},
652                         }},
653                 },
654                 RPCExamples{
655                     HelpExampleCli("getmempoolancestors", "\"mytxid\"")
656             + HelpExampleRpc("getmempoolancestors", "\"mytxid\"")
657                 },
658         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
659 {
660     bool fVerbose = false;
661     if (!request.params[1].isNull())
662         fVerbose = request.params[1].get_bool();
663 
664     uint256 hash = ParseHashV(request.params[0], "parameter 1");
665 
666     const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
667     LOCK(mempool.cs);
668 
669     CTxMemPool::txiter it = mempool.mapTx.find(hash);
670     if (it == mempool.mapTx.end()) {
671         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not in mempool");
672     }
673 
674     CTxMemPool::setEntries setAncestors;
675     uint64_t noLimit = std::numeric_limits<uint64_t>::max();
676     std::string dummy;
677     mempool.CalculateMemPoolAncestors(*it, setAncestors, noLimit, noLimit, noLimit, noLimit, dummy, false);
678 
679     if (!fVerbose) {
680         UniValue o(UniValue::VARR);
681         for (CTxMemPool::txiter ancestorIt : setAncestors) {
682             o.push_back(ancestorIt->GetTx().GetHash().ToString());
683         }
684         return o;
685     } else {
686         UniValue o(UniValue::VOBJ);
687         for (CTxMemPool::txiter ancestorIt : setAncestors) {
688             const CTxMemPoolEntry &e = *ancestorIt;
689             const uint256& _hash = e.GetTx().GetHash();
690             UniValue info(UniValue::VOBJ);
691             entryToJSON(mempool, info, e);
692             o.pushKV(_hash.ToString(), info);
693         }
694         return o;
695     }
696 },
697     };
698 }
699 
getmempooldescendants()700 static RPCHelpMan getmempooldescendants()
701 {
702     return RPCHelpMan{"getmempooldescendants",
703                 "\nIf txid is in the mempool, returns all in-mempool descendants.\n",
704                 {
705                     {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id (must be in mempool)"},
706                     {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "True for a json object, false for array of transaction ids"},
707                 },
708                 {
709                     RPCResult{"for verbose = false",
710                         RPCResult::Type::ARR, "", "",
711                         {{RPCResult::Type::STR_HEX, "", "The transaction id of an in-mempool descendant transaction"}}},
712                     RPCResult{"for verbose = true",
713                         RPCResult::Type::OBJ_DYN, "", "",
714                         {
715                             {RPCResult::Type::OBJ, "transactionid", "", MempoolEntryDescription()},
716                         }},
717                 },
718                 RPCExamples{
719                     HelpExampleCli("getmempooldescendants", "\"mytxid\"")
720             + HelpExampleRpc("getmempooldescendants", "\"mytxid\"")
721                 },
722         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
723 {
724     bool fVerbose = false;
725     if (!request.params[1].isNull())
726         fVerbose = request.params[1].get_bool();
727 
728     uint256 hash = ParseHashV(request.params[0], "parameter 1");
729 
730     const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
731     LOCK(mempool.cs);
732 
733     CTxMemPool::txiter it = mempool.mapTx.find(hash);
734     if (it == mempool.mapTx.end()) {
735         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not in mempool");
736     }
737 
738     CTxMemPool::setEntries setDescendants;
739     mempool.CalculateDescendants(it, setDescendants);
740     // CTxMemPool::CalculateDescendants will include the given tx
741     setDescendants.erase(it);
742 
743     if (!fVerbose) {
744         UniValue o(UniValue::VARR);
745         for (CTxMemPool::txiter descendantIt : setDescendants) {
746             o.push_back(descendantIt->GetTx().GetHash().ToString());
747         }
748 
749         return o;
750     } else {
751         UniValue o(UniValue::VOBJ);
752         for (CTxMemPool::txiter descendantIt : setDescendants) {
753             const CTxMemPoolEntry &e = *descendantIt;
754             const uint256& _hash = e.GetTx().GetHash();
755             UniValue info(UniValue::VOBJ);
756             entryToJSON(mempool, info, e);
757             o.pushKV(_hash.ToString(), info);
758         }
759         return o;
760     }
761 },
762     };
763 }
764 
getmempoolentry()765 static RPCHelpMan getmempoolentry()
766 {
767     return RPCHelpMan{"getmempoolentry",
768                 "\nReturns mempool data for given transaction\n",
769                 {
770                     {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id (must be in mempool)"},
771                 },
772                 RPCResult{
773                     RPCResult::Type::OBJ, "", "", MempoolEntryDescription()},
774                 RPCExamples{
775                     HelpExampleCli("getmempoolentry", "\"mytxid\"")
776             + HelpExampleRpc("getmempoolentry", "\"mytxid\"")
777                 },
778         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
779 {
780     uint256 hash = ParseHashV(request.params[0], "parameter 1");
781 
782     const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
783     LOCK(mempool.cs);
784 
785     CTxMemPool::txiter it = mempool.mapTx.find(hash);
786     if (it == mempool.mapTx.end()) {
787         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not in mempool");
788     }
789 
790     const CTxMemPoolEntry &e = *it;
791     UniValue info(UniValue::VOBJ);
792     entryToJSON(mempool, info, e);
793     return info;
794 },
795     };
796 }
797 
getblockhash()798 static RPCHelpMan getblockhash()
799 {
800     return RPCHelpMan{"getblockhash",
801                 "\nReturns hash of block in best-block-chain at height provided.\n",
802                 {
803                     {"height", RPCArg::Type::NUM, RPCArg::Optional::NO, "The height index"},
804                 },
805                 RPCResult{
806                     RPCResult::Type::STR_HEX, "", "The block hash"},
807                 RPCExamples{
808                     HelpExampleCli("getblockhash", "1000")
809             + HelpExampleRpc("getblockhash", "1000")
810                 },
811         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
812 {
813     ChainstateManager& chainman = EnsureAnyChainman(request.context);
814     LOCK(cs_main);
815     const CChain& active_chain = chainman.ActiveChain();
816 
817     int nHeight = request.params[0].get_int();
818     if (nHeight < 0 || nHeight > active_chain.Height())
819         throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");
820 
821     CBlockIndex* pblockindex = active_chain[nHeight];
822     return pblockindex->GetBlockHash().GetHex();
823 },
824     };
825 }
826 
getblockheader()827 static RPCHelpMan getblockheader()
828 {
829     return RPCHelpMan{"getblockheader",
830                 "\nIf verbose is false, returns a string that is serialized, hex-encoded data for blockheader 'hash'.\n"
831                 "If verbose is true, returns an Object with information about blockheader <hash>.\n",
832                 {
833                     {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash"},
834                     {"verbose", RPCArg::Type::BOOL, RPCArg::Default{true}, "true for a json object, false for the hex-encoded data"},
835                 },
836                 {
837                     RPCResult{"for verbose = true",
838                         RPCResult::Type::OBJ, "", "",
839                         {
840                             {RPCResult::Type::STR_HEX, "hash", "the block hash (same as provided)"},
841                             {RPCResult::Type::NUM, "confirmations", "The number of confirmations, or -1 if the block is not on the main chain"},
842                             {RPCResult::Type::NUM, "height", "The block height or index"},
843                             {RPCResult::Type::NUM, "version", "The block version"},
844                             {RPCResult::Type::STR_HEX, "versionHex", "The block version formatted in hexadecimal"},
845                             {RPCResult::Type::STR_HEX, "merkleroot", "The merkle root"},
846                             {RPCResult::Type::NUM_TIME, "time", "The block time expressed in " + UNIX_EPOCH_TIME},
847                             {RPCResult::Type::NUM_TIME, "mediantime", "The median block time expressed in " + UNIX_EPOCH_TIME},
848                             {RPCResult::Type::NUM, "nonce", "The nonce"},
849                             {RPCResult::Type::STR_HEX, "bits", "The bits"},
850                             {RPCResult::Type::NUM, "difficulty", "The difficulty"},
851                             {RPCResult::Type::STR_HEX, "chainwork", "Expected number of hashes required to produce the current chain"},
852                             {RPCResult::Type::NUM, "nTx", "The number of transactions in the block"},
853                             {RPCResult::Type::STR_HEX, "previousblockhash", /* optional */ true, "The hash of the previous block (if available)"},
854                             {RPCResult::Type::STR_HEX, "nextblockhash", /* optional */ true, "The hash of the next block (if available)"},
855                         }},
856                     RPCResult{"for verbose=false",
857                         RPCResult::Type::STR_HEX, "", "A string that is serialized, hex-encoded data for block 'hash'"},
858                 },
859                 RPCExamples{
860                     HelpExampleCli("getblockheader", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
861             + HelpExampleRpc("getblockheader", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
862                 },
863         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
864 {
865     uint256 hash(ParseHashV(request.params[0], "hash"));
866 
867     bool fVerbose = true;
868     if (!request.params[1].isNull())
869         fVerbose = request.params[1].get_bool();
870 
871     const CBlockIndex* pblockindex;
872     const CBlockIndex* tip;
873     {
874         ChainstateManager& chainman = EnsureAnyChainman(request.context);
875         LOCK(cs_main);
876         pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
877         tip = chainman.ActiveChain().Tip();
878     }
879 
880     if (!pblockindex) {
881         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
882     }
883 
884     if (!fVerbose)
885     {
886         CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION);
887         ssBlock << pblockindex->GetBlockHeader();
888         std::string strHex = HexStr(ssBlock);
889         return strHex;
890     }
891 
892     return blockheaderToJSON(tip, pblockindex);
893 },
894     };
895 }
896 
GetBlockChecked(const CBlockIndex * pblockindex)897 static CBlock GetBlockChecked(const CBlockIndex* pblockindex)
898 {
899     CBlock block;
900     if (IsBlockPruned(pblockindex)) {
901         throw JSONRPCError(RPC_MISC_ERROR, "Block not available (pruned data)");
902     }
903 
904     if (!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus())) {
905         // Block not found on disk. This could be because we have the block
906         // header in our index but not yet have the block or did not accept the
907         // block.
908         throw JSONRPCError(RPC_MISC_ERROR, "Block not found on disk");
909     }
910 
911     return block;
912 }
913 
GetUndoChecked(const CBlockIndex * pblockindex)914 static CBlockUndo GetUndoChecked(const CBlockIndex* pblockindex)
915 {
916     CBlockUndo blockUndo;
917     if (IsBlockPruned(pblockindex)) {
918         throw JSONRPCError(RPC_MISC_ERROR, "Undo data not available (pruned data)");
919     }
920 
921     if (!UndoReadFromDisk(blockUndo, pblockindex)) {
922         throw JSONRPCError(RPC_MISC_ERROR, "Can't read undo data from disk");
923     }
924 
925     return blockUndo;
926 }
927 
getblock()928 static RPCHelpMan getblock()
929 {
930     return RPCHelpMan{"getblock",
931                 "\nIf verbosity is 0, returns a string that is serialized, hex-encoded data for block 'hash'.\n"
932                 "If verbosity is 1, returns an Object with information about block <hash>.\n"
933                 "If verbosity is 2, returns an Object with information about block <hash> and information about each transaction. \n",
934                 {
935                     {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash"},
936                     {"verbosity|verbose", RPCArg::Type::NUM, RPCArg::Default{1}, "0 for hex-encoded data, 1 for a json object, and 2 for json object with transaction data"},
937                 },
938                 {
939                     RPCResult{"for verbosity = 0",
940                 RPCResult::Type::STR_HEX, "", "A string that is serialized, hex-encoded data for block 'hash'"},
941                     RPCResult{"for verbosity = 1",
942                 RPCResult::Type::OBJ, "", "",
943                 {
944                     {RPCResult::Type::STR_HEX, "hash", "the block hash (same as provided)"},
945                     {RPCResult::Type::NUM, "confirmations", "The number of confirmations, or -1 if the block is not on the main chain"},
946                     {RPCResult::Type::NUM, "size", "The block size"},
947                     {RPCResult::Type::NUM, "strippedsize", "The block size excluding witness data"},
948                     {RPCResult::Type::NUM, "weight", "The block weight as defined in BIP 141"},
949                     {RPCResult::Type::NUM, "height", "The block height or index"},
950                     {RPCResult::Type::NUM, "version", "The block version"},
951                     {RPCResult::Type::STR_HEX, "versionHex", "The block version formatted in hexadecimal"},
952                     {RPCResult::Type::STR_HEX, "merkleroot", "The merkle root"},
953                     {RPCResult::Type::ARR, "tx", "The transaction ids",
954                         {{RPCResult::Type::STR_HEX, "", "The transaction id"}}},
955                     {RPCResult::Type::NUM_TIME, "time",       "The block time expressed in " + UNIX_EPOCH_TIME},
956                     {RPCResult::Type::NUM_TIME, "mediantime", "The median block time expressed in " + UNIX_EPOCH_TIME},
957                     {RPCResult::Type::NUM, "nonce", "The nonce"},
958                     {RPCResult::Type::STR_HEX, "bits", "The bits"},
959                     {RPCResult::Type::NUM, "difficulty", "The difficulty"},
960                     {RPCResult::Type::STR_HEX, "chainwork", "Expected number of hashes required to produce the chain up to this block (in hex)"},
961                     {RPCResult::Type::NUM, "nTx", "The number of transactions in the block"},
962                     {RPCResult::Type::STR_HEX, "previousblockhash", /* optional */ true, "The hash of the previous block (if available)"},
963                     {RPCResult::Type::STR_HEX, "nextblockhash", /* optional */ true, "The hash of the next block (if available)"},
964                 }},
965                     RPCResult{"for verbosity = 2",
966                 RPCResult::Type::OBJ, "", "",
967                 {
968                     {RPCResult::Type::ELISION, "", "Same output as verbosity = 1"},
969                     {RPCResult::Type::ARR, "tx", "",
970                     {
971                         {RPCResult::Type::OBJ, "", "",
972                         {
973                             {RPCResult::Type::ELISION, "", "The transactions in the format of the getrawtransaction RPC. Different from verbosity = 1 \"tx\" result"},
974                             {RPCResult::Type::NUM, "fee", "The transaction fee in " + CURRENCY_UNIT + ", omitted if block undo data is not available"},
975                         }},
976                     }},
977                 }},
978         },
979                 RPCExamples{
980                     HelpExampleCli("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
981             + HelpExampleRpc("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
982                 },
983         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
984 {
985     uint256 hash(ParseHashV(request.params[0], "blockhash"));
986 
987     int verbosity = 1;
988     if (!request.params[1].isNull()) {
989         if (request.params[1].isBool()) {
990             verbosity = request.params[1].get_bool() ? 1 : 0;
991         } else {
992             verbosity = request.params[1].get_int();
993         }
994     }
995 
996     CBlock block;
997     const CBlockIndex* pblockindex;
998     const CBlockIndex* tip;
999     {
1000         ChainstateManager& chainman = EnsureAnyChainman(request.context);
1001         LOCK(cs_main);
1002         pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
1003         tip = chainman.ActiveChain().Tip();
1004 
1005         if (!pblockindex) {
1006             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
1007         }
1008 
1009         block = GetBlockChecked(pblockindex);
1010     }
1011 
1012     if (verbosity <= 0)
1013     {
1014         CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags());
1015         ssBlock << block;
1016         std::string strHex = HexStr(ssBlock);
1017         return strHex;
1018     }
1019 
1020     return blockToJSON(block, tip, pblockindex, verbosity >= 2);
1021 },
1022     };
1023 }
1024 
pruneblockchain()1025 static RPCHelpMan pruneblockchain()
1026 {
1027     return RPCHelpMan{"pruneblockchain", "",
1028                 {
1029                     {"height", RPCArg::Type::NUM, RPCArg::Optional::NO, "The block height to prune up to. May be set to a discrete height, or to a " + UNIX_EPOCH_TIME + "\n"
1030             "                  to prune blocks whose block time is at least 2 hours older than the provided timestamp."},
1031                 },
1032                 RPCResult{
1033                     RPCResult::Type::NUM, "", "Height of the last block pruned"},
1034                 RPCExamples{
1035                     HelpExampleCli("pruneblockchain", "1000")
1036             + HelpExampleRpc("pruneblockchain", "1000")
1037                 },
1038         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1039 {
1040     if (!fPruneMode)
1041         throw JSONRPCError(RPC_MISC_ERROR, "Cannot prune blocks because node is not in prune mode.");
1042 
1043     ChainstateManager& chainman = EnsureAnyChainman(request.context);
1044     LOCK(cs_main);
1045     CChainState& active_chainstate = chainman.ActiveChainstate();
1046     CChain& active_chain = active_chainstate.m_chain;
1047 
1048     int heightParam = request.params[0].get_int();
1049     if (heightParam < 0)
1050         throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative block height.");
1051 
1052     // Height value more than a billion is too high to be a block height, and
1053     // too low to be a block time (corresponds to timestamp from Sep 2001).
1054     if (heightParam > 1000000000) {
1055         // Add a 2 hour buffer to include blocks which might have had old timestamps
1056         CBlockIndex* pindex = active_chain.FindEarliestAtLeast(heightParam - TIMESTAMP_WINDOW, 0);
1057         if (!pindex) {
1058             throw JSONRPCError(RPC_INVALID_PARAMETER, "Could not find block with at least the specified timestamp.");
1059         }
1060         heightParam = pindex->nHeight;
1061     }
1062 
1063     unsigned int height = (unsigned int) heightParam;
1064     unsigned int chainHeight = (unsigned int) active_chain.Height();
1065     if (chainHeight < Params().PruneAfterHeight())
1066         throw JSONRPCError(RPC_MISC_ERROR, "Blockchain is too short for pruning.");
1067     else if (height > chainHeight)
1068         throw JSONRPCError(RPC_INVALID_PARAMETER, "Blockchain is shorter than the attempted prune height.");
1069     else if (height > chainHeight - MIN_BLOCKS_TO_KEEP) {
1070         LogPrint(BCLog::RPC, "Attempt to prune blocks close to the tip.  Retaining the minimum number of blocks.\n");
1071         height = chainHeight - MIN_BLOCKS_TO_KEEP;
1072     }
1073 
1074     PruneBlockFilesManual(active_chainstate, height);
1075     const CBlockIndex* block = active_chain.Tip();
1076     CHECK_NONFATAL(block);
1077     while (block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA)) {
1078         block = block->pprev;
1079     }
1080     return uint64_t(block->nHeight);
1081 },
1082     };
1083 }
1084 
ParseHashType(const std::string & hash_type_input)1085 CoinStatsHashType ParseHashType(const std::string& hash_type_input)
1086 {
1087     if (hash_type_input == "hash_serialized_2") {
1088         return CoinStatsHashType::HASH_SERIALIZED;
1089     } else if (hash_type_input == "muhash") {
1090         return CoinStatsHashType::MUHASH;
1091     } else if (hash_type_input == "none") {
1092         return CoinStatsHashType::NONE;
1093     } else {
1094         throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("%s is not a valid hash_type", hash_type_input));
1095     }
1096 }
1097 
gettxoutsetinfo()1098 static RPCHelpMan gettxoutsetinfo()
1099 {
1100     return RPCHelpMan{"gettxoutsetinfo",
1101                 "\nReturns statistics about the unspent transaction output set.\n"
1102                 "Note this call may take some time if you are not using coinstatsindex.\n",
1103                 {
1104                     {"hash_type", RPCArg::Type::STR, RPCArg::Default{"hash_serialized_2"}, "Which UTXO set hash should be calculated. Options: 'hash_serialized_2' (the legacy algorithm), 'muhash', 'none'."},
1105                     {"hash_or_height", RPCArg::Type::NUM, RPCArg::Optional::OMITTED_NAMED_ARG, "The block hash or height of the target height (only available with coinstatsindex).", "", {"", "string or numeric"}},
1106                     {"use_index", RPCArg::Type::BOOL, RPCArg::Default{true}, "Use coinstatsindex, if available."},
1107                 },
1108                 RPCResult{
1109                     RPCResult::Type::OBJ, "", "",
1110                     {
1111                         {RPCResult::Type::NUM, "height", "The block height (index) of the returned statistics"},
1112                         {RPCResult::Type::STR_HEX, "bestblock", "The hash of the block at which these statistics are calculated"},
1113                         {RPCResult::Type::NUM, "txouts", "The number of unspent transaction outputs"},
1114                         {RPCResult::Type::NUM, "bogosize", "Database-independent, meaningless metric indicating the UTXO set size"},
1115                         {RPCResult::Type::STR_HEX, "hash_serialized_2", /* optional */ true, "The serialized hash (only present if 'hash_serialized_2' hash_type is chosen)"},
1116                         {RPCResult::Type::STR_HEX, "muhash", /* optional */ true, "The serialized hash (only present if 'muhash' hash_type is chosen)"},
1117                         {RPCResult::Type::NUM, "transactions", "The number of transactions with unspent outputs (not available when coinstatsindex is used)"},
1118                         {RPCResult::Type::NUM, "disk_size", "The estimated size of the chainstate on disk (not available when coinstatsindex is used)"},
1119                         {RPCResult::Type::STR_AMOUNT, "total_amount", "The total amount of coins in the UTXO set"},
1120                         {RPCResult::Type::STR_AMOUNT, "total_unspendable_amount", "The total amount of coins permanently excluded from the UTXO set (only available if coinstatsindex is used)"},
1121                         {RPCResult::Type::OBJ, "block_info", "Info on amounts in the block at this block height (only available if coinstatsindex is used)",
1122                         {
1123                             {RPCResult::Type::STR_AMOUNT, "prevout_spent", ""},
1124                             {RPCResult::Type::STR_AMOUNT, "coinbase", ""},
1125                             {RPCResult::Type::STR_AMOUNT, "new_outputs_ex_coinbase", ""},
1126                             {RPCResult::Type::STR_AMOUNT, "unspendable", ""},
1127                             {RPCResult::Type::OBJ, "unspendables", "Detailed view of the unspendable categories",
1128                             {
1129                                 {RPCResult::Type::STR_AMOUNT, "genesis_block", ""},
1130                                 {RPCResult::Type::STR_AMOUNT, "bip30", "Transactions overridden by duplicates (no longer possible with BIP30)"},
1131                                 {RPCResult::Type::STR_AMOUNT, "scripts", "Amounts sent to scripts that are unspendable (for example OP_RETURN outputs)"},
1132                                 {RPCResult::Type::STR_AMOUNT, "unclaimed_rewards", "Fee rewards that miners did not claim in their coinbase transaction"},
1133                             }}
1134                         }},
1135                     }},
1136                 RPCExamples{
1137                     HelpExampleCli("gettxoutsetinfo", "") +
1138                     HelpExampleCli("gettxoutsetinfo", R"("none")") +
1139                     HelpExampleCli("gettxoutsetinfo", R"("none" 1000)") +
1140                     HelpExampleCli("gettxoutsetinfo", R"("none" '"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09"')") +
1141                     HelpExampleRpc("gettxoutsetinfo", "") +
1142                     HelpExampleRpc("gettxoutsetinfo", R"("none")") +
1143                     HelpExampleRpc("gettxoutsetinfo", R"("none", 1000)") +
1144                     HelpExampleRpc("gettxoutsetinfo", R"("none", "00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09")")
1145                 },
1146         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1147 {
1148     UniValue ret(UniValue::VOBJ);
1149 
1150     CBlockIndex* pindex{nullptr};
1151     const CoinStatsHashType hash_type{request.params[0].isNull() ? CoinStatsHashType::HASH_SERIALIZED : ParseHashType(request.params[0].get_str())};
1152     CCoinsStats stats{hash_type};
1153     stats.index_requested = request.params[2].isNull() || request.params[2].get_bool();
1154 
1155     NodeContext& node = EnsureAnyNodeContext(request.context);
1156     ChainstateManager& chainman = EnsureChainman(node);
1157     CChainState& active_chainstate = chainman.ActiveChainstate();
1158     active_chainstate.ForceFlushStateToDisk();
1159 
1160     CCoinsView* coins_view;
1161     BlockManager* blockman;
1162     {
1163         LOCK(::cs_main);
1164         coins_view = &active_chainstate.CoinsDB();
1165         blockman = &active_chainstate.m_blockman;
1166         pindex = blockman->LookupBlockIndex(coins_view->GetBestBlock());
1167     }
1168 
1169     if (!request.params[1].isNull()) {
1170         if (!g_coin_stats_index) {
1171             throw JSONRPCError(RPC_INVALID_PARAMETER, "Querying specific block heights requires coinstatsindex");
1172         }
1173 
1174         if (stats.m_hash_type == CoinStatsHashType::HASH_SERIALIZED) {
1175             throw JSONRPCError(RPC_INVALID_PARAMETER, "hash_serialized_2 hash type cannot be queried for a specific block");
1176         }
1177 
1178         pindex = ParseHashOrHeight(request.params[1], chainman);
1179     }
1180 
1181     if (GetUTXOStats(coins_view, *blockman, stats, node.rpc_interruption_point, pindex)) {
1182         ret.pushKV("height", (int64_t)stats.nHeight);
1183         ret.pushKV("bestblock", stats.hashBlock.GetHex());
1184         ret.pushKV("txouts", (int64_t)stats.nTransactionOutputs);
1185         ret.pushKV("bogosize", (int64_t)stats.nBogoSize);
1186         if (hash_type == CoinStatsHashType::HASH_SERIALIZED) {
1187             ret.pushKV("hash_serialized_2", stats.hashSerialized.GetHex());
1188         }
1189         if (hash_type == CoinStatsHashType::MUHASH) {
1190               ret.pushKV("muhash", stats.hashSerialized.GetHex());
1191         }
1192         ret.pushKV("total_amount", ValueFromAmount(stats.nTotalAmount));
1193         if (!stats.index_used) {
1194             ret.pushKV("transactions", static_cast<int64_t>(stats.nTransactions));
1195             ret.pushKV("disk_size", stats.nDiskSize);
1196         } else {
1197             ret.pushKV("total_unspendable_amount", ValueFromAmount(stats.block_unspendable_amount));
1198 
1199             CCoinsStats prev_stats{hash_type};
1200 
1201             if (pindex->nHeight > 0) {
1202                 GetUTXOStats(coins_view, *blockman, prev_stats, node.rpc_interruption_point, pindex->pprev);
1203             }
1204 
1205             UniValue block_info(UniValue::VOBJ);
1206             block_info.pushKV("prevout_spent", ValueFromAmount(stats.block_prevout_spent_amount - prev_stats.block_prevout_spent_amount));
1207             block_info.pushKV("coinbase", ValueFromAmount(stats.block_coinbase_amount - prev_stats.block_coinbase_amount));
1208             block_info.pushKV("new_outputs_ex_coinbase", ValueFromAmount(stats.block_new_outputs_ex_coinbase_amount - prev_stats.block_new_outputs_ex_coinbase_amount));
1209             block_info.pushKV("unspendable", ValueFromAmount(stats.block_unspendable_amount - prev_stats.block_unspendable_amount));
1210 
1211             UniValue unspendables(UniValue::VOBJ);
1212             unspendables.pushKV("genesis_block", ValueFromAmount(stats.unspendables_genesis_block - prev_stats.unspendables_genesis_block));
1213             unspendables.pushKV("bip30", ValueFromAmount(stats.unspendables_bip30 - prev_stats.unspendables_bip30));
1214             unspendables.pushKV("scripts", ValueFromAmount(stats.unspendables_scripts - prev_stats.unspendables_scripts));
1215             unspendables.pushKV("unclaimed_rewards", ValueFromAmount(stats.unspendables_unclaimed_rewards - prev_stats.unspendables_unclaimed_rewards));
1216             block_info.pushKV("unspendables", unspendables);
1217 
1218             ret.pushKV("block_info", block_info);
1219         }
1220     } else {
1221         if (g_coin_stats_index) {
1222             const IndexSummary summary{g_coin_stats_index->GetSummary()};
1223 
1224             if (!summary.synced) {
1225                 throw JSONRPCError(RPC_INTERNAL_ERROR, strprintf("Unable to read UTXO set because coinstatsindex is still syncing. Current height: %d", summary.best_block_height));
1226             }
1227         }
1228         throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read UTXO set");
1229     }
1230     return ret;
1231 },
1232     };
1233 }
1234 
gettxout()1235 static RPCHelpMan gettxout()
1236 {
1237     return RPCHelpMan{"gettxout",
1238         "\nReturns details about an unspent transaction output.\n",
1239         {
1240             {"txid", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction id"},
1241             {"n", RPCArg::Type::NUM, RPCArg::Optional::NO, "vout number"},
1242             {"include_mempool", RPCArg::Type::BOOL, RPCArg::Default{true}, "Whether to include the mempool. Note that an unspent output that is spent in the mempool won't appear."},
1243         },
1244         {
1245             RPCResult{"If the UTXO was not found", RPCResult::Type::NONE, "", ""},
1246             RPCResult{"Otherwise", RPCResult::Type::OBJ, "", "", {
1247                 {RPCResult::Type::STR_HEX, "bestblock", "The hash of the block at the tip of the chain"},
1248                 {RPCResult::Type::NUM, "confirmations", "The number of confirmations"},
1249                 {RPCResult::Type::STR_AMOUNT, "value", "The transaction value in " + CURRENCY_UNIT},
1250                 {RPCResult::Type::OBJ, "scriptPubKey", "", {
1251                     {RPCResult::Type::STR, "asm", ""},
1252                     {RPCResult::Type::STR_HEX, "hex", ""},
1253                     {RPCResult::Type::NUM, "reqSigs", /* optional */ true, "(DEPRECATED, returned only if config option -deprecatedrpc=addresses is passed) Number of required signatures"},
1254                     {RPCResult::Type::STR, "type", "The type, eg pubkeyhash"},
1255                     {RPCResult::Type::STR, "address", /* optional */ true, "bitcoin address (only if a well-defined address exists)"},
1256                     {RPCResult::Type::ARR, "addresses", /* optional */ true, "(DEPRECATED, returned only if config option -deprecatedrpc=addresses is passed) Array of bitcoin addresses",
1257                         {{RPCResult::Type::STR, "address", "bitcoin address"}}},
1258                 }},
1259                 {RPCResult::Type::BOOL, "coinbase", "Coinbase or not"},
1260             }},
1261         },
1262         RPCExamples{
1263             "\nGet unspent transactions\n"
1264             + HelpExampleCli("listunspent", "") +
1265             "\nView the details\n"
1266             + HelpExampleCli("gettxout", "\"txid\" 1") +
1267             "\nAs a JSON-RPC call\n"
1268             + HelpExampleRpc("gettxout", "\"txid\", 1")
1269                 },
1270         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1271 {
1272     NodeContext& node = EnsureAnyNodeContext(request.context);
1273     ChainstateManager& chainman = EnsureChainman(node);
1274     LOCK(cs_main);
1275 
1276     UniValue ret(UniValue::VOBJ);
1277 
1278     uint256 hash(ParseHashV(request.params[0], "txid"));
1279     int n = request.params[1].get_int();
1280     COutPoint out(hash, n);
1281     bool fMempool = true;
1282     if (!request.params[2].isNull())
1283         fMempool = request.params[2].get_bool();
1284 
1285     Coin coin;
1286     CChainState& active_chainstate = chainman.ActiveChainstate();
1287     CCoinsViewCache* coins_view = &active_chainstate.CoinsTip();
1288 
1289     if (fMempool) {
1290         const CTxMemPool& mempool = EnsureMemPool(node);
1291         LOCK(mempool.cs);
1292         CCoinsViewMemPool view(coins_view, mempool);
1293         if (!view.GetCoin(out, coin) || mempool.isSpent(out)) {
1294             return NullUniValue;
1295         }
1296     } else {
1297         if (!coins_view->GetCoin(out, coin)) {
1298             return NullUniValue;
1299         }
1300     }
1301 
1302     const CBlockIndex* pindex = active_chainstate.m_blockman.LookupBlockIndex(coins_view->GetBestBlock());
1303     ret.pushKV("bestblock", pindex->GetBlockHash().GetHex());
1304     if (coin.nHeight == MEMPOOL_HEIGHT) {
1305         ret.pushKV("confirmations", 0);
1306     } else {
1307         ret.pushKV("confirmations", (int64_t)(pindex->nHeight - coin.nHeight + 1));
1308     }
1309     ret.pushKV("value", ValueFromAmount(coin.out.nValue));
1310     UniValue o(UniValue::VOBJ);
1311     ScriptPubKeyToUniv(coin.out.scriptPubKey, o, true);
1312     ret.pushKV("scriptPubKey", o);
1313     ret.pushKV("coinbase", (bool)coin.fCoinBase);
1314 
1315     return ret;
1316 },
1317     };
1318 }
1319 
verifychain()1320 static RPCHelpMan verifychain()
1321 {
1322     return RPCHelpMan{"verifychain",
1323                 "\nVerifies blockchain database.\n",
1324                 {
1325                     {"checklevel", RPCArg::Type::NUM, RPCArg::DefaultHint{strprintf("%d, range=0-4", DEFAULT_CHECKLEVEL)},
1326                         strprintf("How thorough the block verification is:\n - %s", Join(CHECKLEVEL_DOC, "\n- "))},
1327                     {"nblocks", RPCArg::Type::NUM, RPCArg::DefaultHint{strprintf("%d, 0=all", DEFAULT_CHECKBLOCKS)}, "The number of blocks to check."},
1328                 },
1329                 RPCResult{
1330                     RPCResult::Type::BOOL, "", "Verified or not"},
1331                 RPCExamples{
1332                     HelpExampleCli("verifychain", "")
1333             + HelpExampleRpc("verifychain", "")
1334                 },
1335         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1336 {
1337     const int check_level(request.params[0].isNull() ? DEFAULT_CHECKLEVEL : request.params[0].get_int());
1338     const int check_depth{request.params[1].isNull() ? DEFAULT_CHECKBLOCKS : request.params[1].get_int()};
1339 
1340     ChainstateManager& chainman = EnsureAnyChainman(request.context);
1341     LOCK(cs_main);
1342 
1343     CChainState& active_chainstate = chainman.ActiveChainstate();
1344     return CVerifyDB().VerifyDB(
1345         active_chainstate, Params(), active_chainstate.CoinsTip(), check_level, check_depth);
1346 },
1347     };
1348 }
1349 
SoftForkDescPushBack(const CBlockIndex * active_chain_tip,UniValue & softforks,const Consensus::Params & params,Consensus::BuriedDeployment dep)1350 static void SoftForkDescPushBack(const CBlockIndex* active_chain_tip, UniValue& softforks, const Consensus::Params& params, Consensus::BuriedDeployment dep)
1351 {
1352     // For buried deployments.
1353 
1354     if (!DeploymentEnabled(params, dep)) return;
1355 
1356     UniValue rv(UniValue::VOBJ);
1357     rv.pushKV("type", "buried");
1358     // getblockchaininfo reports the softfork as active from when the chain height is
1359     // one below the activation height
1360     rv.pushKV("active", DeploymentActiveAfter(active_chain_tip, params, dep));
1361     rv.pushKV("height", params.DeploymentHeight(dep));
1362     softforks.pushKV(DeploymentName(dep), rv);
1363 }
1364 
SoftForkDescPushBack(const CBlockIndex * active_chain_tip,UniValue & softforks,const Consensus::Params & consensusParams,Consensus::DeploymentPos id)1365 static void SoftForkDescPushBack(const CBlockIndex* active_chain_tip, UniValue& softforks, const Consensus::Params& consensusParams, Consensus::DeploymentPos id)
1366 {
1367     // For BIP9 deployments.
1368 
1369     if (!DeploymentEnabled(consensusParams, id)) return;
1370 
1371     UniValue bip9(UniValue::VOBJ);
1372     const ThresholdState thresholdState = g_versionbitscache.State(active_chain_tip, consensusParams, id);
1373     switch (thresholdState) {
1374     case ThresholdState::DEFINED: bip9.pushKV("status", "defined"); break;
1375     case ThresholdState::STARTED: bip9.pushKV("status", "started"); break;
1376     case ThresholdState::LOCKED_IN: bip9.pushKV("status", "locked_in"); break;
1377     case ThresholdState::ACTIVE: bip9.pushKV("status", "active"); break;
1378     case ThresholdState::FAILED: bip9.pushKV("status", "failed"); break;
1379     }
1380     if (ThresholdState::STARTED == thresholdState)
1381     {
1382         bip9.pushKV("bit", consensusParams.vDeployments[id].bit);
1383     }
1384     bip9.pushKV("start_time", consensusParams.vDeployments[id].nStartTime);
1385     bip9.pushKV("timeout", consensusParams.vDeployments[id].nTimeout);
1386     int64_t since_height = g_versionbitscache.StateSinceHeight(active_chain_tip, consensusParams, id);
1387     bip9.pushKV("since", since_height);
1388     if (ThresholdState::STARTED == thresholdState)
1389     {
1390         UniValue statsUV(UniValue::VOBJ);
1391         BIP9Stats statsStruct = g_versionbitscache.Statistics(active_chain_tip, consensusParams, id);
1392         statsUV.pushKV("period", statsStruct.period);
1393         statsUV.pushKV("threshold", statsStruct.threshold);
1394         statsUV.pushKV("elapsed", statsStruct.elapsed);
1395         statsUV.pushKV("count", statsStruct.count);
1396         statsUV.pushKV("possible", statsStruct.possible);
1397         bip9.pushKV("statistics", statsUV);
1398     }
1399     bip9.pushKV("min_activation_height", consensusParams.vDeployments[id].min_activation_height);
1400 
1401     UniValue rv(UniValue::VOBJ);
1402     rv.pushKV("type", "bip9");
1403     rv.pushKV("bip9", bip9);
1404     if (ThresholdState::ACTIVE == thresholdState) {
1405         rv.pushKV("height", since_height);
1406     }
1407     rv.pushKV("active", ThresholdState::ACTIVE == thresholdState);
1408 
1409     softforks.pushKV(DeploymentName(id), rv);
1410 }
1411 
getblockchaininfo()1412 RPCHelpMan getblockchaininfo()
1413 {
1414     return RPCHelpMan{"getblockchaininfo",
1415                 "Returns an object containing various state info regarding blockchain processing.\n",
1416                 {},
1417                 RPCResult{
1418                     RPCResult::Type::OBJ, "", "",
1419                     {
1420                         {RPCResult::Type::STR, "chain", "current network name (main, test, signet, regtest)"},
1421                         {RPCResult::Type::NUM, "blocks", "the height of the most-work fully-validated chain. The genesis block has height 0"},
1422                         {RPCResult::Type::NUM, "headers", "the current number of headers we have validated"},
1423                         {RPCResult::Type::STR, "bestblockhash", "the hash of the currently best block"},
1424                         {RPCResult::Type::NUM, "difficulty", "the current difficulty"},
1425                         {RPCResult::Type::NUM, "mediantime", "median time for the current best block"},
1426                         {RPCResult::Type::NUM, "verificationprogress", "estimate of verification progress [0..1]"},
1427                         {RPCResult::Type::BOOL, "initialblockdownload", "(debug information) estimate of whether this node is in Initial Block Download mode"},
1428                         {RPCResult::Type::STR_HEX, "chainwork", "total amount of work in active chain, in hexadecimal"},
1429                         {RPCResult::Type::NUM, "size_on_disk", "the estimated size of the block and undo files on disk"},
1430                         {RPCResult::Type::BOOL, "pruned", "if the blocks are subject to pruning"},
1431                         {RPCResult::Type::NUM, "pruneheight", "lowest-height complete block stored (only present if pruning is enabled)"},
1432                         {RPCResult::Type::BOOL, "automatic_pruning", "whether automatic pruning is enabled (only present if pruning is enabled)"},
1433                         {RPCResult::Type::NUM, "prune_target_size", "the target size used by pruning (only present if automatic pruning is enabled)"},
1434                         {RPCResult::Type::OBJ_DYN, "softforks", "status of softforks",
1435                         {
1436                             {RPCResult::Type::OBJ, "xxxx", "name of the softfork",
1437                             {
1438                                 {RPCResult::Type::STR, "type", "one of \"buried\", \"bip9\""},
1439                                 {RPCResult::Type::OBJ, "bip9", "status of bip9 softforks (only for \"bip9\" type)",
1440                                 {
1441                                     {RPCResult::Type::STR, "status", "one of \"defined\", \"started\", \"locked_in\", \"active\", \"failed\""},
1442                                     {RPCResult::Type::NUM, "bit", "the bit (0-28) in the block version field used to signal this softfork (only for \"started\" status)"},
1443                                     {RPCResult::Type::NUM_TIME, "start_time", "the minimum median time past of a block at which the bit gains its meaning"},
1444                                     {RPCResult::Type::NUM_TIME, "timeout", "the median time past of a block at which the deployment is considered failed if not yet locked in"},
1445                                     {RPCResult::Type::NUM, "since", "height of the first block to which the status applies"},
1446                                     {RPCResult::Type::NUM, "min_activation_height", "minimum height of blocks for which the rules may be enforced"},
1447                                     {RPCResult::Type::OBJ, "statistics", "numeric statistics about BIP9 signalling for a softfork (only for \"started\" status)",
1448                                     {
1449                                         {RPCResult::Type::NUM, "period", "the length in blocks of the BIP9 signalling period"},
1450                                         {RPCResult::Type::NUM, "threshold", "the number of blocks with the version bit set required to activate the feature"},
1451                                         {RPCResult::Type::NUM, "elapsed", "the number of blocks elapsed since the beginning of the current period"},
1452                                         {RPCResult::Type::NUM, "count", "the number of blocks with the version bit set in the current period"},
1453                                         {RPCResult::Type::BOOL, "possible", "returns false if there are not enough blocks left in this period to pass activation threshold"},
1454                                     }},
1455                                 }},
1456                                 {RPCResult::Type::NUM, "height", "height of the first block which the rules are or will be enforced (only for \"buried\" type, or \"bip9\" type with \"active\" status)"},
1457                                 {RPCResult::Type::BOOL, "active", "true if the rules are enforced for the mempool and the next block"},
1458                             }},
1459                         }},
1460                         {RPCResult::Type::STR, "warnings", "any network and blockchain warnings"},
1461                     }},
1462                 RPCExamples{
1463                     HelpExampleCli("getblockchaininfo", "")
1464             + HelpExampleRpc("getblockchaininfo", "")
1465                 },
1466         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1467 {
1468     ChainstateManager& chainman = EnsureAnyChainman(request.context);
1469     LOCK(cs_main);
1470     CChainState& active_chainstate = chainman.ActiveChainstate();
1471 
1472     const CBlockIndex* tip = active_chainstate.m_chain.Tip();
1473     CHECK_NONFATAL(tip);
1474     const int height = tip->nHeight;
1475     UniValue obj(UniValue::VOBJ);
1476     obj.pushKV("chain",                 Params().NetworkIDString());
1477     obj.pushKV("blocks",                height);
1478     obj.pushKV("headers",               pindexBestHeader ? pindexBestHeader->nHeight : -1);
1479     obj.pushKV("bestblockhash",         tip->GetBlockHash().GetHex());
1480     obj.pushKV("difficulty",            (double)GetDifficulty(tip));
1481     obj.pushKV("mediantime",            (int64_t)tip->GetMedianTimePast());
1482     obj.pushKV("verificationprogress",  GuessVerificationProgress(Params().TxData(), tip));
1483     obj.pushKV("initialblockdownload",  active_chainstate.IsInitialBlockDownload());
1484     obj.pushKV("chainwork",             tip->nChainWork.GetHex());
1485     obj.pushKV("size_on_disk",          CalculateCurrentUsage());
1486     obj.pushKV("pruned",                fPruneMode);
1487     if (fPruneMode) {
1488         const CBlockIndex* block = tip;
1489         CHECK_NONFATAL(block);
1490         while (block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA)) {
1491             block = block->pprev;
1492         }
1493 
1494         obj.pushKV("pruneheight",        block->nHeight);
1495 
1496         // if 0, execution bypasses the whole if block.
1497         bool automatic_pruning = (gArgs.GetArg("-prune", 0) != 1);
1498         obj.pushKV("automatic_pruning",  automatic_pruning);
1499         if (automatic_pruning) {
1500             obj.pushKV("prune_target_size",  nPruneTarget);
1501         }
1502     }
1503 
1504     const Consensus::Params& consensusParams = Params().GetConsensus();
1505     UniValue softforks(UniValue::VOBJ);
1506     SoftForkDescPushBack(tip, softforks, consensusParams, Consensus::DEPLOYMENT_HEIGHTINCB);
1507     SoftForkDescPushBack(tip, softforks, consensusParams, Consensus::DEPLOYMENT_DERSIG);
1508     SoftForkDescPushBack(tip, softforks, consensusParams, Consensus::DEPLOYMENT_CLTV);
1509     SoftForkDescPushBack(tip, softforks, consensusParams, Consensus::DEPLOYMENT_CSV);
1510     SoftForkDescPushBack(tip, softforks, consensusParams, Consensus::DEPLOYMENT_SEGWIT);
1511     SoftForkDescPushBack(tip, softforks, consensusParams, Consensus::DEPLOYMENT_TESTDUMMY);
1512     SoftForkDescPushBack(tip, softforks, consensusParams, Consensus::DEPLOYMENT_TAPROOT);
1513     obj.pushKV("softforks", softforks);
1514 
1515     obj.pushKV("warnings", GetWarnings(false).original);
1516     return obj;
1517 },
1518     };
1519 }
1520 
1521 /** Comparison function for sorting the getchaintips heads.  */
1522 struct CompareBlocksByHeight
1523 {
operator ()CompareBlocksByHeight1524     bool operator()(const CBlockIndex* a, const CBlockIndex* b) const
1525     {
1526         /* Make sure that unequal blocks with the same height do not compare
1527            equal. Use the pointers themselves to make a distinction. */
1528 
1529         if (a->nHeight != b->nHeight)
1530           return (a->nHeight > b->nHeight);
1531 
1532         return a < b;
1533     }
1534 };
1535 
getchaintips()1536 static RPCHelpMan getchaintips()
1537 {
1538     return RPCHelpMan{"getchaintips",
1539                 "Return information about all known tips in the block tree,"
1540                 " including the main chain as well as orphaned branches.\n",
1541                 {},
1542                 RPCResult{
1543                     RPCResult::Type::ARR, "", "",
1544                     {{RPCResult::Type::OBJ, "", "",
1545                         {
1546                             {RPCResult::Type::NUM, "height", "height of the chain tip"},
1547                             {RPCResult::Type::STR_HEX, "hash", "block hash of the tip"},
1548                             {RPCResult::Type::NUM, "branchlen", "zero for main chain, otherwise length of branch connecting the tip to the main chain"},
1549                             {RPCResult::Type::STR, "status", "status of the chain, \"active\" for the main chain\n"
1550             "Possible values for status:\n"
1551             "1.  \"invalid\"               This branch contains at least one invalid block\n"
1552             "2.  \"headers-only\"          Not all blocks for this branch are available, but the headers are valid\n"
1553             "3.  \"valid-headers\"         All blocks are available for this branch, but they were never fully validated\n"
1554             "4.  \"valid-fork\"            This branch is not part of the active chain, but is fully validated\n"
1555             "5.  \"active\"                This is the tip of the active main chain, which is certainly valid"},
1556                         }}}},
1557                 RPCExamples{
1558                     HelpExampleCli("getchaintips", "")
1559             + HelpExampleRpc("getchaintips", "")
1560                 },
1561         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1562 {
1563     ChainstateManager& chainman = EnsureAnyChainman(request.context);
1564     LOCK(cs_main);
1565     CChain& active_chain = chainman.ActiveChain();
1566 
1567     /*
1568      * Idea: The set of chain tips is the active chain tip, plus orphan blocks which do not have another orphan building off of them.
1569      * Algorithm:
1570      *  - Make one pass through BlockIndex(), picking out the orphan blocks, and also storing a set of the orphan block's pprev pointers.
1571      *  - Iterate through the orphan blocks. If the block isn't pointed to by another orphan, it is a chain tip.
1572      *  - Add the active chain tip
1573      */
1574     std::set<const CBlockIndex*, CompareBlocksByHeight> setTips;
1575     std::set<const CBlockIndex*> setOrphans;
1576     std::set<const CBlockIndex*> setPrevs;
1577 
1578     for (const std::pair<const uint256, CBlockIndex*>& item : chainman.BlockIndex()) {
1579         if (!active_chain.Contains(item.second)) {
1580             setOrphans.insert(item.second);
1581             setPrevs.insert(item.second->pprev);
1582         }
1583     }
1584 
1585     for (std::set<const CBlockIndex*>::iterator it = setOrphans.begin(); it != setOrphans.end(); ++it) {
1586         if (setPrevs.erase(*it) == 0) {
1587             setTips.insert(*it);
1588         }
1589     }
1590 
1591     // Always report the currently active tip.
1592     setTips.insert(active_chain.Tip());
1593 
1594     /* Construct the output array.  */
1595     UniValue res(UniValue::VARR);
1596     for (const CBlockIndex* block : setTips) {
1597         UniValue obj(UniValue::VOBJ);
1598         obj.pushKV("height", block->nHeight);
1599         obj.pushKV("hash", block->phashBlock->GetHex());
1600 
1601         const int branchLen = block->nHeight - active_chain.FindFork(block)->nHeight;
1602         obj.pushKV("branchlen", branchLen);
1603 
1604         std::string status;
1605         if (active_chain.Contains(block)) {
1606             // This block is part of the currently active chain.
1607             status = "active";
1608         } else if (block->nStatus & BLOCK_FAILED_MASK) {
1609             // This block or one of its ancestors is invalid.
1610             status = "invalid";
1611         } else if (!block->HaveTxsDownloaded()) {
1612             // This block cannot be connected because full block data for it or one of its parents is missing.
1613             status = "headers-only";
1614         } else if (block->IsValid(BLOCK_VALID_SCRIPTS)) {
1615             // This block is fully validated, but no longer part of the active chain. It was probably the active block once, but was reorganized.
1616             status = "valid-fork";
1617         } else if (block->IsValid(BLOCK_VALID_TREE)) {
1618             // The headers for this block are valid, but it has not been validated. It was probably never part of the most-work chain.
1619             status = "valid-headers";
1620         } else {
1621             // No clue.
1622             status = "unknown";
1623         }
1624         obj.pushKV("status", status);
1625 
1626         res.push_back(obj);
1627     }
1628 
1629     return res;
1630 },
1631     };
1632 }
1633 
MempoolInfoToJSON(const CTxMemPool & pool)1634 UniValue MempoolInfoToJSON(const CTxMemPool& pool)
1635 {
1636     // Make sure this call is atomic in the pool.
1637     LOCK(pool.cs);
1638     UniValue ret(UniValue::VOBJ);
1639     ret.pushKV("loaded", pool.IsLoaded());
1640     ret.pushKV("size", (int64_t)pool.size());
1641     ret.pushKV("bytes", (int64_t)pool.GetTotalTxSize());
1642     ret.pushKV("usage", (int64_t)pool.DynamicMemoryUsage());
1643     ret.pushKV("total_fee", ValueFromAmount(pool.GetTotalFee()));
1644     size_t maxmempool = gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;
1645     ret.pushKV("maxmempool", (int64_t) maxmempool);
1646     ret.pushKV("mempoolminfee", ValueFromAmount(std::max(pool.GetMinFee(maxmempool), ::minRelayTxFee).GetFeePerK()));
1647     ret.pushKV("minrelaytxfee", ValueFromAmount(::minRelayTxFee.GetFeePerK()));
1648     ret.pushKV("unbroadcastcount", uint64_t{pool.GetUnbroadcastTxs().size()});
1649     return ret;
1650 }
1651 
getmempoolinfo()1652 static RPCHelpMan getmempoolinfo()
1653 {
1654     return RPCHelpMan{"getmempoolinfo",
1655                 "\nReturns details on the active state of the TX memory pool.\n",
1656                 {},
1657                 RPCResult{
1658                     RPCResult::Type::OBJ, "", "",
1659                     {
1660                         {RPCResult::Type::BOOL, "loaded", "True if the mempool is fully loaded"},
1661                         {RPCResult::Type::NUM, "size", "Current tx count"},
1662                         {RPCResult::Type::NUM, "bytes", "Sum of all virtual transaction sizes as defined in BIP 141. Differs from actual serialized size because witness data is discounted"},
1663                         {RPCResult::Type::NUM, "usage", "Total memory usage for the mempool"},
1664                         {RPCResult::Type::STR_AMOUNT, "total_fee", "Total fees for the mempool in " + CURRENCY_UNIT + ", ignoring modified fees through prioritizetransaction"},
1665                         {RPCResult::Type::NUM, "maxmempool", "Maximum memory usage for the mempool"},
1666                         {RPCResult::Type::STR_AMOUNT, "mempoolminfee", "Minimum fee rate in " + CURRENCY_UNIT + "/kvB for tx to be accepted. Is the maximum of minrelaytxfee and minimum mempool fee"},
1667                         {RPCResult::Type::STR_AMOUNT, "minrelaytxfee", "Current minimum relay fee for transactions"},
1668                         {RPCResult::Type::NUM, "unbroadcastcount", "Current number of transactions that haven't passed initial broadcast yet"}
1669                     }},
1670                 RPCExamples{
1671                     HelpExampleCli("getmempoolinfo", "")
1672             + HelpExampleRpc("getmempoolinfo", "")
1673                 },
1674         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1675 {
1676     return MempoolInfoToJSON(EnsureAnyMemPool(request.context));
1677 },
1678     };
1679 }
1680 
preciousblock()1681 static RPCHelpMan preciousblock()
1682 {
1683     return RPCHelpMan{"preciousblock",
1684                 "\nTreats a block as if it were received before others with the same work.\n"
1685                 "\nA later preciousblock call can override the effect of an earlier one.\n"
1686                 "\nThe effects of preciousblock are not retained across restarts.\n",
1687                 {
1688                     {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hash of the block to mark as precious"},
1689                 },
1690                 RPCResult{RPCResult::Type::NONE, "", ""},
1691                 RPCExamples{
1692                     HelpExampleCli("preciousblock", "\"blockhash\"")
1693             + HelpExampleRpc("preciousblock", "\"blockhash\"")
1694                 },
1695         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1696 {
1697     uint256 hash(ParseHashV(request.params[0], "blockhash"));
1698     CBlockIndex* pblockindex;
1699 
1700     ChainstateManager& chainman = EnsureAnyChainman(request.context);
1701     {
1702         LOCK(cs_main);
1703         pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
1704         if (!pblockindex) {
1705             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
1706         }
1707     }
1708 
1709     BlockValidationState state;
1710     chainman.ActiveChainstate().PreciousBlock(state, pblockindex);
1711 
1712     if (!state.IsValid()) {
1713         throw JSONRPCError(RPC_DATABASE_ERROR, state.ToString());
1714     }
1715 
1716     return NullUniValue;
1717 },
1718     };
1719 }
1720 
invalidateblock()1721 static RPCHelpMan invalidateblock()
1722 {
1723     return RPCHelpMan{"invalidateblock",
1724                 "\nPermanently marks a block as invalid, as if it violated a consensus rule.\n",
1725                 {
1726                     {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hash of the block to mark as invalid"},
1727                 },
1728                 RPCResult{RPCResult::Type::NONE, "", ""},
1729                 RPCExamples{
1730                     HelpExampleCli("invalidateblock", "\"blockhash\"")
1731             + HelpExampleRpc("invalidateblock", "\"blockhash\"")
1732                 },
1733         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1734 {
1735     uint256 hash(ParseHashV(request.params[0], "blockhash"));
1736     BlockValidationState state;
1737 
1738     ChainstateManager& chainman = EnsureAnyChainman(request.context);
1739     CBlockIndex* pblockindex;
1740     {
1741         LOCK(cs_main);
1742         pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
1743         if (!pblockindex) {
1744             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
1745         }
1746     }
1747     chainman.ActiveChainstate().InvalidateBlock(state, pblockindex);
1748 
1749     if (state.IsValid()) {
1750         chainman.ActiveChainstate().ActivateBestChain(state);
1751     }
1752 
1753     if (!state.IsValid()) {
1754         throw JSONRPCError(RPC_DATABASE_ERROR, state.ToString());
1755     }
1756 
1757     return NullUniValue;
1758 },
1759     };
1760 }
1761 
reconsiderblock()1762 static RPCHelpMan reconsiderblock()
1763 {
1764     return RPCHelpMan{"reconsiderblock",
1765                 "\nRemoves invalidity status of a block, its ancestors and its descendants, reconsider them for activation.\n"
1766                 "This can be used to undo the effects of invalidateblock.\n",
1767                 {
1768                     {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hash of the block to reconsider"},
1769                 },
1770                 RPCResult{RPCResult::Type::NONE, "", ""},
1771                 RPCExamples{
1772                     HelpExampleCli("reconsiderblock", "\"blockhash\"")
1773             + HelpExampleRpc("reconsiderblock", "\"blockhash\"")
1774                 },
1775         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1776 {
1777     ChainstateManager& chainman = EnsureAnyChainman(request.context);
1778     uint256 hash(ParseHashV(request.params[0], "blockhash"));
1779 
1780     {
1781         LOCK(cs_main);
1782         CBlockIndex* pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
1783         if (!pblockindex) {
1784             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
1785         }
1786 
1787         chainman.ActiveChainstate().ResetBlockFailureFlags(pblockindex);
1788     }
1789 
1790     BlockValidationState state;
1791     chainman.ActiveChainstate().ActivateBestChain(state);
1792 
1793     if (!state.IsValid()) {
1794         throw JSONRPCError(RPC_DATABASE_ERROR, state.ToString());
1795     }
1796 
1797     return NullUniValue;
1798 },
1799     };
1800 }
1801 
getchaintxstats()1802 static RPCHelpMan getchaintxstats()
1803 {
1804     return RPCHelpMan{"getchaintxstats",
1805                 "\nCompute statistics about the total number and rate of transactions in the chain.\n",
1806                 {
1807                     {"nblocks", RPCArg::Type::NUM, RPCArg::DefaultHint{"one month"}, "Size of the window in number of blocks"},
1808                     {"blockhash", RPCArg::Type::STR_HEX, RPCArg::DefaultHint{"chain tip"}, "The hash of the block that ends the window."},
1809                 },
1810                 RPCResult{
1811                     RPCResult::Type::OBJ, "", "",
1812                     {
1813                         {RPCResult::Type::NUM_TIME, "time", "The timestamp for the final block in the window, expressed in " + UNIX_EPOCH_TIME},
1814                         {RPCResult::Type::NUM, "txcount", "The total number of transactions in the chain up to that point"},
1815                         {RPCResult::Type::STR_HEX, "window_final_block_hash", "The hash of the final block in the window"},
1816                         {RPCResult::Type::NUM, "window_final_block_height", "The height of the final block in the window."},
1817                         {RPCResult::Type::NUM, "window_block_count", "Size of the window in number of blocks"},
1818                         {RPCResult::Type::NUM, "window_tx_count", /* optional */ true, "The number of transactions in the window. Only returned if \"window_block_count\" is > 0"},
1819                         {RPCResult::Type::NUM, "window_interval", /* optional */ true, "The elapsed time in the window in seconds. Only returned if \"window_block_count\" is > 0"},
1820                         {RPCResult::Type::NUM, "txrate", /* optional */ true, "The average rate of transactions per second in the window. Only returned if \"window_interval\" is > 0"},
1821                     }},
1822                 RPCExamples{
1823                     HelpExampleCli("getchaintxstats", "")
1824             + HelpExampleRpc("getchaintxstats", "2016")
1825                 },
1826         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1827 {
1828     ChainstateManager& chainman = EnsureAnyChainman(request.context);
1829     const CBlockIndex* pindex;
1830     int blockcount = 30 * 24 * 60 * 60 / Params().GetConsensus().nPowTargetSpacing; // By default: 1 month
1831 
1832     if (request.params[1].isNull()) {
1833         LOCK(cs_main);
1834         pindex = chainman.ActiveChain().Tip();
1835     } else {
1836         uint256 hash(ParseHashV(request.params[1], "blockhash"));
1837         LOCK(cs_main);
1838         pindex = chainman.m_blockman.LookupBlockIndex(hash);
1839         if (!pindex) {
1840             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
1841         }
1842         if (!chainman.ActiveChain().Contains(pindex)) {
1843             throw JSONRPCError(RPC_INVALID_PARAMETER, "Block is not in main chain");
1844         }
1845     }
1846 
1847     CHECK_NONFATAL(pindex != nullptr);
1848 
1849     if (request.params[0].isNull()) {
1850         blockcount = std::max(0, std::min(blockcount, pindex->nHeight - 1));
1851     } else {
1852         blockcount = request.params[0].get_int();
1853 
1854         if (blockcount < 0 || (blockcount > 0 && blockcount >= pindex->nHeight)) {
1855             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid block count: should be between 0 and the block's height - 1");
1856         }
1857     }
1858 
1859     const CBlockIndex* pindexPast = pindex->GetAncestor(pindex->nHeight - blockcount);
1860     int nTimeDiff = pindex->GetMedianTimePast() - pindexPast->GetMedianTimePast();
1861     int nTxDiff = pindex->nChainTx - pindexPast->nChainTx;
1862 
1863     UniValue ret(UniValue::VOBJ);
1864     ret.pushKV("time", (int64_t)pindex->nTime);
1865     ret.pushKV("txcount", (int64_t)pindex->nChainTx);
1866     ret.pushKV("window_final_block_hash", pindex->GetBlockHash().GetHex());
1867     ret.pushKV("window_final_block_height", pindex->nHeight);
1868     ret.pushKV("window_block_count", blockcount);
1869     if (blockcount > 0) {
1870         ret.pushKV("window_tx_count", nTxDiff);
1871         ret.pushKV("window_interval", nTimeDiff);
1872         if (nTimeDiff > 0) {
1873             ret.pushKV("txrate", ((double)nTxDiff) / nTimeDiff);
1874         }
1875     }
1876 
1877     return ret;
1878 },
1879     };
1880 }
1881 
1882 template<typename T>
CalculateTruncatedMedian(std::vector<T> & scores)1883 static T CalculateTruncatedMedian(std::vector<T>& scores)
1884 {
1885     size_t size = scores.size();
1886     if (size == 0) {
1887         return 0;
1888     }
1889 
1890     std::sort(scores.begin(), scores.end());
1891     if (size % 2 == 0) {
1892         return (scores[size / 2 - 1] + scores[size / 2]) / 2;
1893     } else {
1894         return scores[size / 2];
1895     }
1896 }
1897 
CalculatePercentilesByWeight(CAmount result[NUM_GETBLOCKSTATS_PERCENTILES],std::vector<std::pair<CAmount,int64_t>> & scores,int64_t total_weight)1898 void CalculatePercentilesByWeight(CAmount result[NUM_GETBLOCKSTATS_PERCENTILES], std::vector<std::pair<CAmount, int64_t>>& scores, int64_t total_weight)
1899 {
1900     if (scores.empty()) {
1901         return;
1902     }
1903 
1904     std::sort(scores.begin(), scores.end());
1905 
1906     // 10th, 25th, 50th, 75th, and 90th percentile weight units.
1907     const double weights[NUM_GETBLOCKSTATS_PERCENTILES] = {
1908         total_weight / 10.0, total_weight / 4.0, total_weight / 2.0, (total_weight * 3.0) / 4.0, (total_weight * 9.0) / 10.0
1909     };
1910 
1911     int64_t next_percentile_index = 0;
1912     int64_t cumulative_weight = 0;
1913     for (const auto& element : scores) {
1914         cumulative_weight += element.second;
1915         while (next_percentile_index < NUM_GETBLOCKSTATS_PERCENTILES && cumulative_weight >= weights[next_percentile_index]) {
1916             result[next_percentile_index] = element.first;
1917             ++next_percentile_index;
1918         }
1919     }
1920 
1921     // Fill any remaining percentiles with the last value.
1922     for (int64_t i = next_percentile_index; i < NUM_GETBLOCKSTATS_PERCENTILES; i++) {
1923         result[i] = scores.back().first;
1924     }
1925 }
1926 
ScriptPubKeyToUniv(const CScript & scriptPubKey,UniValue & out,bool fIncludeHex)1927 void ScriptPubKeyToUniv(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex)
1928 {
1929     ScriptPubKeyToUniv(scriptPubKey, out, fIncludeHex, IsDeprecatedRPCEnabled("addresses"));
1930 }
1931 
TxToUniv(const CTransaction & tx,const uint256 & hashBlock,UniValue & entry,bool include_hex,int serialize_flags,const CTxUndo * txundo)1932 void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex, int serialize_flags, const CTxUndo* txundo)
1933 {
1934     TxToUniv(tx, hashBlock, IsDeprecatedRPCEnabled("addresses"), entry, include_hex, serialize_flags, txundo);
1935 }
1936 
1937 template<typename T>
SetHasKeys(const std::set<T> & set)1938 static inline bool SetHasKeys(const std::set<T>& set) {return false;}
1939 template<typename T, typename Tk, typename... Args>
SetHasKeys(const std::set<T> & set,const Tk & key,const Args &...args)1940 static inline bool SetHasKeys(const std::set<T>& set, const Tk& key, const Args&... args)
1941 {
1942     return (set.count(key) != 0) || SetHasKeys(set, args...);
1943 }
1944 
1945 // outpoint (needed for the utxo index) + nHeight + fCoinBase
1946 static constexpr size_t PER_UTXO_OVERHEAD = sizeof(COutPoint) + sizeof(uint32_t) + sizeof(bool);
1947 
getblockstats()1948 static RPCHelpMan getblockstats()
1949 {
1950     return RPCHelpMan{"getblockstats",
1951                 "\nCompute per block statistics for a given window. All amounts are in satoshis.\n"
1952                 "It won't work for some heights with pruning.\n",
1953                 {
1954                     {"hash_or_height", RPCArg::Type::NUM, RPCArg::Optional::NO, "The block hash or height of the target block", "", {"", "string or numeric"}},
1955                     {"stats", RPCArg::Type::ARR, RPCArg::DefaultHint{"all values"}, "Values to plot (see result below)",
1956                         {
1957                             {"height", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Selected statistic"},
1958                             {"time", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Selected statistic"},
1959                         },
1960                         "stats"},
1961                 },
1962                 RPCResult{
1963             RPCResult::Type::OBJ, "", "",
1964             {
1965                 {RPCResult::Type::NUM, "avgfee", "Average fee in the block"},
1966                 {RPCResult::Type::NUM, "avgfeerate", "Average feerate (in satoshis per virtual byte)"},
1967                 {RPCResult::Type::NUM, "avgtxsize", "Average transaction size"},
1968                 {RPCResult::Type::STR_HEX, "blockhash", "The block hash (to check for potential reorgs)"},
1969                 {RPCResult::Type::ARR_FIXED, "feerate_percentiles", "Feerates at the 10th, 25th, 50th, 75th, and 90th percentile weight unit (in satoshis per virtual byte)",
1970                 {
1971                     {RPCResult::Type::NUM, "10th_percentile_feerate", "The 10th percentile feerate"},
1972                     {RPCResult::Type::NUM, "25th_percentile_feerate", "The 25th percentile feerate"},
1973                     {RPCResult::Type::NUM, "50th_percentile_feerate", "The 50th percentile feerate"},
1974                     {RPCResult::Type::NUM, "75th_percentile_feerate", "The 75th percentile feerate"},
1975                     {RPCResult::Type::NUM, "90th_percentile_feerate", "The 90th percentile feerate"},
1976                 }},
1977                 {RPCResult::Type::NUM, "height", "The height of the block"},
1978                 {RPCResult::Type::NUM, "ins", "The number of inputs (excluding coinbase)"},
1979                 {RPCResult::Type::NUM, "maxfee", "Maximum fee in the block"},
1980                 {RPCResult::Type::NUM, "maxfeerate", "Maximum feerate (in satoshis per virtual byte)"},
1981                 {RPCResult::Type::NUM, "maxtxsize", "Maximum transaction size"},
1982                 {RPCResult::Type::NUM, "medianfee", "Truncated median fee in the block"},
1983                 {RPCResult::Type::NUM, "mediantime", "The block median time past"},
1984                 {RPCResult::Type::NUM, "mediantxsize", "Truncated median transaction size"},
1985                 {RPCResult::Type::NUM, "minfee", "Minimum fee in the block"},
1986                 {RPCResult::Type::NUM, "minfeerate", "Minimum feerate (in satoshis per virtual byte)"},
1987                 {RPCResult::Type::NUM, "mintxsize", "Minimum transaction size"},
1988                 {RPCResult::Type::NUM, "outs", "The number of outputs"},
1989                 {RPCResult::Type::NUM, "subsidy", "The block subsidy"},
1990                 {RPCResult::Type::NUM, "swtotal_size", "Total size of all segwit transactions"},
1991                 {RPCResult::Type::NUM, "swtotal_weight", "Total weight of all segwit transactions"},
1992                 {RPCResult::Type::NUM, "swtxs", "The number of segwit transactions"},
1993                 {RPCResult::Type::NUM, "time", "The block time"},
1994                 {RPCResult::Type::NUM, "total_out", "Total amount in all outputs (excluding coinbase and thus reward [ie subsidy + totalfee])"},
1995                 {RPCResult::Type::NUM, "total_size", "Total size of all non-coinbase transactions"},
1996                 {RPCResult::Type::NUM, "total_weight", "Total weight of all non-coinbase transactions"},
1997                 {RPCResult::Type::NUM, "totalfee", "The fee total"},
1998                 {RPCResult::Type::NUM, "txs", "The number of transactions (including coinbase)"},
1999                 {RPCResult::Type::NUM, "utxo_increase", "The increase/decrease in the number of unspent outputs"},
2000                 {RPCResult::Type::NUM, "utxo_size_inc", "The increase/decrease in size for the utxo index (not discounting op_return and similar)"},
2001             }},
2002                 RPCExamples{
2003                     HelpExampleCli("getblockstats", R"('"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09"' '["minfeerate","avgfeerate"]')") +
2004                     HelpExampleCli("getblockstats", R"(1000 '["minfeerate","avgfeerate"]')") +
2005                     HelpExampleRpc("getblockstats", R"("00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09", ["minfeerate","avgfeerate"])") +
2006                     HelpExampleRpc("getblockstats", R"(1000, ["minfeerate","avgfeerate"])")
2007                 },
2008         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
2009 {
2010     ChainstateManager& chainman = EnsureAnyChainman(request.context);
2011     LOCK(cs_main);
2012     CBlockIndex* pindex{ParseHashOrHeight(request.params[0], chainman)};
2013     CHECK_NONFATAL(pindex != nullptr);
2014 
2015     std::set<std::string> stats;
2016     if (!request.params[1].isNull()) {
2017         const UniValue stats_univalue = request.params[1].get_array();
2018         for (unsigned int i = 0; i < stats_univalue.size(); i++) {
2019             const std::string stat = stats_univalue[i].get_str();
2020             stats.insert(stat);
2021         }
2022     }
2023 
2024     const CBlock block = GetBlockChecked(pindex);
2025     const CBlockUndo blockUndo = GetUndoChecked(pindex);
2026 
2027     const bool do_all = stats.size() == 0; // Calculate everything if nothing selected (default)
2028     const bool do_mediantxsize = do_all || stats.count("mediantxsize") != 0;
2029     const bool do_medianfee = do_all || stats.count("medianfee") != 0;
2030     const bool do_feerate_percentiles = do_all || stats.count("feerate_percentiles") != 0;
2031     const bool loop_inputs = do_all || do_medianfee || do_feerate_percentiles ||
2032         SetHasKeys(stats, "utxo_size_inc", "totalfee", "avgfee", "avgfeerate", "minfee", "maxfee", "minfeerate", "maxfeerate");
2033     const bool loop_outputs = do_all || loop_inputs || stats.count("total_out");
2034     const bool do_calculate_size = do_mediantxsize ||
2035         SetHasKeys(stats, "total_size", "avgtxsize", "mintxsize", "maxtxsize", "swtotal_size");
2036     const bool do_calculate_weight = do_all || SetHasKeys(stats, "total_weight", "avgfeerate", "swtotal_weight", "avgfeerate", "feerate_percentiles", "minfeerate", "maxfeerate");
2037     const bool do_calculate_sw = do_all || SetHasKeys(stats, "swtxs", "swtotal_size", "swtotal_weight");
2038 
2039     CAmount maxfee = 0;
2040     CAmount maxfeerate = 0;
2041     CAmount minfee = MAX_MONEY;
2042     CAmount minfeerate = MAX_MONEY;
2043     CAmount total_out = 0;
2044     CAmount totalfee = 0;
2045     int64_t inputs = 0;
2046     int64_t maxtxsize = 0;
2047     int64_t mintxsize = MAX_BLOCK_SERIALIZED_SIZE;
2048     int64_t outputs = 0;
2049     int64_t swtotal_size = 0;
2050     int64_t swtotal_weight = 0;
2051     int64_t swtxs = 0;
2052     int64_t total_size = 0;
2053     int64_t total_weight = 0;
2054     int64_t utxo_size_inc = 0;
2055     std::vector<CAmount> fee_array;
2056     std::vector<std::pair<CAmount, int64_t>> feerate_array;
2057     std::vector<int64_t> txsize_array;
2058 
2059     for (size_t i = 0; i < block.vtx.size(); ++i) {
2060         const auto& tx = block.vtx.at(i);
2061         outputs += tx->vout.size();
2062 
2063         CAmount tx_total_out = 0;
2064         if (loop_outputs) {
2065             for (const CTxOut& out : tx->vout) {
2066                 tx_total_out += out.nValue;
2067                 utxo_size_inc += GetSerializeSize(out, PROTOCOL_VERSION) + PER_UTXO_OVERHEAD;
2068             }
2069         }
2070 
2071         if (tx->IsCoinBase()) {
2072             continue;
2073         }
2074 
2075         inputs += tx->vin.size(); // Don't count coinbase's fake input
2076         total_out += tx_total_out; // Don't count coinbase reward
2077 
2078         int64_t tx_size = 0;
2079         if (do_calculate_size) {
2080 
2081             tx_size = tx->GetTotalSize();
2082             if (do_mediantxsize) {
2083                 txsize_array.push_back(tx_size);
2084             }
2085             maxtxsize = std::max(maxtxsize, tx_size);
2086             mintxsize = std::min(mintxsize, tx_size);
2087             total_size += tx_size;
2088         }
2089 
2090         int64_t weight = 0;
2091         if (do_calculate_weight) {
2092             weight = GetTransactionWeight(*tx);
2093             total_weight += weight;
2094         }
2095 
2096         if (do_calculate_sw && tx->HasWitness()) {
2097             ++swtxs;
2098             swtotal_size += tx_size;
2099             swtotal_weight += weight;
2100         }
2101 
2102         if (loop_inputs) {
2103             CAmount tx_total_in = 0;
2104             const auto& txundo = blockUndo.vtxundo.at(i - 1);
2105             for (const Coin& coin: txundo.vprevout) {
2106                 const CTxOut& prevoutput = coin.out;
2107 
2108                 tx_total_in += prevoutput.nValue;
2109                 utxo_size_inc -= GetSerializeSize(prevoutput, PROTOCOL_VERSION) + PER_UTXO_OVERHEAD;
2110             }
2111 
2112             CAmount txfee = tx_total_in - tx_total_out;
2113             CHECK_NONFATAL(MoneyRange(txfee));
2114             if (do_medianfee) {
2115                 fee_array.push_back(txfee);
2116             }
2117             maxfee = std::max(maxfee, txfee);
2118             minfee = std::min(minfee, txfee);
2119             totalfee += txfee;
2120 
2121             // New feerate uses satoshis per virtual byte instead of per serialized byte
2122             CAmount feerate = weight ? (txfee * WITNESS_SCALE_FACTOR) / weight : 0;
2123             if (do_feerate_percentiles) {
2124                 feerate_array.emplace_back(std::make_pair(feerate, weight));
2125             }
2126             maxfeerate = std::max(maxfeerate, feerate);
2127             minfeerate = std::min(minfeerate, feerate);
2128         }
2129     }
2130 
2131     CAmount feerate_percentiles[NUM_GETBLOCKSTATS_PERCENTILES] = { 0 };
2132     CalculatePercentilesByWeight(feerate_percentiles, feerate_array, total_weight);
2133 
2134     UniValue feerates_res(UniValue::VARR);
2135     for (int64_t i = 0; i < NUM_GETBLOCKSTATS_PERCENTILES; i++) {
2136         feerates_res.push_back(feerate_percentiles[i]);
2137     }
2138 
2139     UniValue ret_all(UniValue::VOBJ);
2140     ret_all.pushKV("avgfee", (block.vtx.size() > 1) ? totalfee / (block.vtx.size() - 1) : 0);
2141     ret_all.pushKV("avgfeerate", total_weight ? (totalfee * WITNESS_SCALE_FACTOR) / total_weight : 0); // Unit: sat/vbyte
2142     ret_all.pushKV("avgtxsize", (block.vtx.size() > 1) ? total_size / (block.vtx.size() - 1) : 0);
2143     ret_all.pushKV("blockhash", pindex->GetBlockHash().GetHex());
2144     ret_all.pushKV("feerate_percentiles", feerates_res);
2145     ret_all.pushKV("height", (int64_t)pindex->nHeight);
2146     ret_all.pushKV("ins", inputs);
2147     ret_all.pushKV("maxfee", maxfee);
2148     ret_all.pushKV("maxfeerate", maxfeerate);
2149     ret_all.pushKV("maxtxsize", maxtxsize);
2150     ret_all.pushKV("medianfee", CalculateTruncatedMedian(fee_array));
2151     ret_all.pushKV("mediantime", pindex->GetMedianTimePast());
2152     ret_all.pushKV("mediantxsize", CalculateTruncatedMedian(txsize_array));
2153     ret_all.pushKV("minfee", (minfee == MAX_MONEY) ? 0 : minfee);
2154     ret_all.pushKV("minfeerate", (minfeerate == MAX_MONEY) ? 0 : minfeerate);
2155     ret_all.pushKV("mintxsize", mintxsize == MAX_BLOCK_SERIALIZED_SIZE ? 0 : mintxsize);
2156     ret_all.pushKV("outs", outputs);
2157     ret_all.pushKV("subsidy", GetBlockSubsidy(pindex->nHeight, Params().GetConsensus()));
2158     ret_all.pushKV("swtotal_size", swtotal_size);
2159     ret_all.pushKV("swtotal_weight", swtotal_weight);
2160     ret_all.pushKV("swtxs", swtxs);
2161     ret_all.pushKV("time", pindex->GetBlockTime());
2162     ret_all.pushKV("total_out", total_out);
2163     ret_all.pushKV("total_size", total_size);
2164     ret_all.pushKV("total_weight", total_weight);
2165     ret_all.pushKV("totalfee", totalfee);
2166     ret_all.pushKV("txs", (int64_t)block.vtx.size());
2167     ret_all.pushKV("utxo_increase", outputs - inputs);
2168     ret_all.pushKV("utxo_size_inc", utxo_size_inc);
2169 
2170     if (do_all) {
2171         return ret_all;
2172     }
2173 
2174     UniValue ret(UniValue::VOBJ);
2175     for (const std::string& stat : stats) {
2176         const UniValue& value = ret_all[stat];
2177         if (value.isNull()) {
2178             throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid selected statistic %s", stat));
2179         }
2180         ret.pushKV(stat, value);
2181     }
2182     return ret;
2183 },
2184     };
2185 }
2186 
savemempool()2187 static RPCHelpMan savemempool()
2188 {
2189     return RPCHelpMan{"savemempool",
2190                 "\nDumps the mempool to disk. It will fail until the previous dump is fully loaded.\n",
2191                 {},
2192                 RPCResult{RPCResult::Type::NONE, "", ""},
2193                 RPCExamples{
2194                     HelpExampleCli("savemempool", "")
2195             + HelpExampleRpc("savemempool", "")
2196                 },
2197         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
2198 {
2199     const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
2200 
2201     if (!mempool.IsLoaded()) {
2202         throw JSONRPCError(RPC_MISC_ERROR, "The mempool was not loaded yet");
2203     }
2204 
2205     if (!DumpMempool(mempool)) {
2206         throw JSONRPCError(RPC_MISC_ERROR, "Unable to dump mempool to disk");
2207     }
2208 
2209     return NullUniValue;
2210 },
2211     };
2212 }
2213 
2214 namespace {
2215 //! Search for a given set of pubkey scripts
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,std::function<void ()> & interruption_point)2216 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, std::function<void()>& interruption_point)
2217 {
2218     scan_progress = 0;
2219     count = 0;
2220     while (cursor->Valid()) {
2221         COutPoint key;
2222         Coin coin;
2223         if (!cursor->GetKey(key) || !cursor->GetValue(coin)) return false;
2224         if (++count % 8192 == 0) {
2225             interruption_point();
2226             if (should_abort) {
2227                 // allow to abort the scan via the abort reference
2228                 return false;
2229             }
2230         }
2231         if (count % 256 == 0) {
2232             // update progress reference every 256 item
2233             uint32_t high = 0x100 * *key.hash.begin() + *(key.hash.begin() + 1);
2234             scan_progress = (int)(high * 100.0 / 65536.0 + 0.5);
2235         }
2236         if (needles.count(coin.out.scriptPubKey)) {
2237             out_results.emplace(key, coin);
2238         }
2239         cursor->Next();
2240     }
2241     scan_progress = 100;
2242     return true;
2243 }
2244 } // namespace
2245 
2246 /** RAII object to prevent concurrency issue when scanning the txout set */
2247 static std::atomic<int> g_scan_progress;
2248 static std::atomic<bool> g_scan_in_progress;
2249 static std::atomic<bool> g_should_abort_scan;
2250 class CoinsViewScanReserver
2251 {
2252 private:
2253     bool m_could_reserve;
2254 public:
CoinsViewScanReserver()2255     explicit CoinsViewScanReserver() : m_could_reserve(false) {}
2256 
reserve()2257     bool reserve() {
2258         CHECK_NONFATAL(!m_could_reserve);
2259         if (g_scan_in_progress.exchange(true)) {
2260             return false;
2261         }
2262         CHECK_NONFATAL(g_scan_progress == 0);
2263         m_could_reserve = true;
2264         return true;
2265     }
2266 
~CoinsViewScanReserver()2267     ~CoinsViewScanReserver() {
2268         if (m_could_reserve) {
2269             g_scan_in_progress = false;
2270             g_scan_progress = 0;
2271         }
2272     }
2273 };
2274 
scantxoutset()2275 static RPCHelpMan scantxoutset()
2276 {
2277     return RPCHelpMan{"scantxoutset",
2278         "\nScans the unspent transaction output set for entries that match certain output descriptors.\n"
2279         "Examples of output descriptors are:\n"
2280         "    addr(<address>)                      Outputs whose scriptPubKey corresponds to the specified address (does not include P2PK)\n"
2281         "    raw(<hex script>)                    Outputs whose scriptPubKey equals the specified hex scripts\n"
2282         "    combo(<pubkey>)                      P2PK, P2PKH, P2WPKH, and P2SH-P2WPKH outputs for the given pubkey\n"
2283         "    pkh(<pubkey>)                        P2PKH outputs for the given pubkey\n"
2284         "    sh(multi(<n>,<pubkey>,<pubkey>,...)) P2SH-multisig outputs for the given threshold and pubkeys\n"
2285         "\nIn the above, <pubkey> either refers to a fixed public key in hexadecimal notation, or to an xpub/xprv optionally followed by one\n"
2286         "or more path elements separated by \"/\", and optionally ending in \"/*\" (unhardened), or \"/*'\" or \"/*h\" (hardened) to specify all\n"
2287         "unhardened or hardened child keys.\n"
2288         "In the latter case, a range needs to be specified by below if different from 1000.\n"
2289         "For more information on output descriptors, see the documentation in the doc/descriptors.md file.\n",
2290         {
2291             {"action", RPCArg::Type::STR, RPCArg::Optional::NO, "The action to execute\n"
2292                 "\"start\" for starting a scan\n"
2293                 "\"abort\" for aborting the current scan (returns true when abort was successful)\n"
2294                 "\"status\" for progress report (in %) of the current scan"},
2295             {"scanobjects", RPCArg::Type::ARR, RPCArg::Optional::OMITTED, "Array of scan objects. Required for \"start\" action\n"
2296                 "Every scan object is either a string descriptor or an object:",
2297             {
2298                 {"descriptor", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "An output descriptor"},
2299                 {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "An object with output descriptor and metadata",
2300                 {
2301                     {"desc", RPCArg::Type::STR, RPCArg::Optional::NO, "An output descriptor"},
2302                     {"range", RPCArg::Type::RANGE, RPCArg::Default{1000}, "The range of HD chain indexes to explore (either end or [begin,end])"},
2303                 }},
2304             },
2305                         "[scanobjects,...]"},
2306         },
2307         {
2308             RPCResult{"When action=='abort'", RPCResult::Type::BOOL, "", ""},
2309             RPCResult{"When action=='status' and no scan is in progress", RPCResult::Type::NONE, "", ""},
2310             RPCResult{"When action=='status' and scan is in progress", RPCResult::Type::OBJ, "", "",
2311             {
2312                 {RPCResult::Type::NUM, "progress", "The scan progress"},
2313             }},
2314             RPCResult{"When action=='start'", RPCResult::Type::OBJ, "", "", {
2315                 {RPCResult::Type::BOOL, "success", "Whether the scan was completed"},
2316                 {RPCResult::Type::NUM, "txouts", "The number of unspent transaction outputs scanned"},
2317                 {RPCResult::Type::NUM, "height", "The current block height (index)"},
2318                 {RPCResult::Type::STR_HEX, "bestblock", "The hash of the block at the tip of the chain"},
2319                 {RPCResult::Type::ARR, "unspents", "",
2320                 {
2321                     {RPCResult::Type::OBJ, "", "",
2322                     {
2323                         {RPCResult::Type::STR_HEX, "txid", "The transaction id"},
2324                         {RPCResult::Type::NUM, "vout", "The vout value"},
2325                         {RPCResult::Type::STR_HEX, "scriptPubKey", "The script key"},
2326                         {RPCResult::Type::STR, "desc", "A specialized descriptor for the matched scriptPubKey"},
2327                         {RPCResult::Type::STR_AMOUNT, "amount", "The total amount in " + CURRENCY_UNIT + " of the unspent output"},
2328                         {RPCResult::Type::NUM, "height", "Height of the unspent transaction output"},
2329                     }},
2330                 }},
2331                 {RPCResult::Type::STR_AMOUNT, "total_amount", "The total amount of all found unspent outputs in " + CURRENCY_UNIT},
2332             }},
2333         },
2334         RPCExamples{""},
2335         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
2336 {
2337     RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR});
2338 
2339     UniValue result(UniValue::VOBJ);
2340     if (request.params[0].get_str() == "status") {
2341         CoinsViewScanReserver reserver;
2342         if (reserver.reserve()) {
2343             // no scan in progress
2344             return NullUniValue;
2345         }
2346         result.pushKV("progress", g_scan_progress);
2347         return result;
2348     } else if (request.params[0].get_str() == "abort") {
2349         CoinsViewScanReserver reserver;
2350         if (reserver.reserve()) {
2351             // reserve was possible which means no scan was running
2352             return false;
2353         }
2354         // set the abort flag
2355         g_should_abort_scan = true;
2356         return true;
2357     } else if (request.params[0].get_str() == "start") {
2358         CoinsViewScanReserver reserver;
2359         if (!reserver.reserve()) {
2360             throw JSONRPCError(RPC_INVALID_PARAMETER, "Scan already in progress, use action \"abort\" or \"status\"");
2361         }
2362 
2363         if (request.params.size() < 2) {
2364             throw JSONRPCError(RPC_MISC_ERROR, "scanobjects argument is required for the start action");
2365         }
2366 
2367         std::set<CScript> needles;
2368         std::map<CScript, std::string> descriptors;
2369         CAmount total_in = 0;
2370 
2371         // loop through the scan objects
2372         for (const UniValue& scanobject : request.params[1].get_array().getValues()) {
2373             FlatSigningProvider provider;
2374             auto scripts = EvalDescriptorStringOrObject(scanobject, provider);
2375             for (const auto& script : scripts) {
2376                 std::string inferred = InferDescriptor(script, provider)->ToString();
2377                 needles.emplace(script);
2378                 descriptors.emplace(std::move(script), std::move(inferred));
2379             }
2380         }
2381 
2382         // Scan the unspent transaction output set for inputs
2383         UniValue unspents(UniValue::VARR);
2384         std::vector<CTxOut> input_txos;
2385         std::map<COutPoint, Coin> coins;
2386         g_should_abort_scan = false;
2387         int64_t count = 0;
2388         std::unique_ptr<CCoinsViewCursor> pcursor;
2389         CBlockIndex* tip;
2390         NodeContext& node = EnsureAnyNodeContext(request.context);
2391         {
2392             ChainstateManager& chainman = EnsureChainman(node);
2393             LOCK(cs_main);
2394             CChainState& active_chainstate = chainman.ActiveChainstate();
2395             active_chainstate.ForceFlushStateToDisk();
2396             pcursor = active_chainstate.CoinsDB().Cursor();
2397             CHECK_NONFATAL(pcursor);
2398             tip = active_chainstate.m_chain.Tip();
2399             CHECK_NONFATAL(tip);
2400         }
2401         bool res = FindScriptPubKey(g_scan_progress, g_should_abort_scan, count, pcursor.get(), needles, coins, node.rpc_interruption_point);
2402         result.pushKV("success", res);
2403         result.pushKV("txouts", count);
2404         result.pushKV("height", tip->nHeight);
2405         result.pushKV("bestblock", tip->GetBlockHash().GetHex());
2406 
2407         for (const auto& it : coins) {
2408             const COutPoint& outpoint = it.first;
2409             const Coin& coin = it.second;
2410             const CTxOut& txo = coin.out;
2411             input_txos.push_back(txo);
2412             total_in += txo.nValue;
2413 
2414             UniValue unspent(UniValue::VOBJ);
2415             unspent.pushKV("txid", outpoint.hash.GetHex());
2416             unspent.pushKV("vout", (int32_t)outpoint.n);
2417             unspent.pushKV("scriptPubKey", HexStr(txo.scriptPubKey));
2418             unspent.pushKV("desc", descriptors[txo.scriptPubKey]);
2419             unspent.pushKV("amount", ValueFromAmount(txo.nValue));
2420             unspent.pushKV("height", (int32_t)coin.nHeight);
2421 
2422             unspents.push_back(unspent);
2423         }
2424         result.pushKV("unspents", unspents);
2425         result.pushKV("total_amount", ValueFromAmount(total_in));
2426     } else {
2427         throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid command");
2428     }
2429     return result;
2430 },
2431     };
2432 }
2433 
getblockfilter()2434 static RPCHelpMan getblockfilter()
2435 {
2436     return RPCHelpMan{"getblockfilter",
2437                 "\nRetrieve a BIP 157 content filter for a particular block.\n",
2438                 {
2439                     {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hash of the block"},
2440                     {"filtertype", RPCArg::Type::STR, RPCArg::Default{"basic"}, "The type name of the filter"},
2441                 },
2442                 RPCResult{
2443                     RPCResult::Type::OBJ, "", "",
2444                     {
2445                         {RPCResult::Type::STR_HEX, "filter", "the hex-encoded filter data"},
2446                         {RPCResult::Type::STR_HEX, "header", "the hex-encoded filter header"},
2447                     }},
2448                 RPCExamples{
2449                     HelpExampleCli("getblockfilter", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\" \"basic\"") +
2450                     HelpExampleRpc("getblockfilter", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\", \"basic\"")
2451                 },
2452         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
2453 {
2454     uint256 block_hash = ParseHashV(request.params[0], "blockhash");
2455     std::string filtertype_name = "basic";
2456     if (!request.params[1].isNull()) {
2457         filtertype_name = request.params[1].get_str();
2458     }
2459 
2460     BlockFilterType filtertype;
2461     if (!BlockFilterTypeByName(filtertype_name, filtertype)) {
2462         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unknown filtertype");
2463     }
2464 
2465     BlockFilterIndex* index = GetBlockFilterIndex(filtertype);
2466     if (!index) {
2467         throw JSONRPCError(RPC_MISC_ERROR, "Index is not enabled for filtertype " + filtertype_name);
2468     }
2469 
2470     const CBlockIndex* block_index;
2471     bool block_was_connected;
2472     {
2473         ChainstateManager& chainman = EnsureAnyChainman(request.context);
2474         LOCK(cs_main);
2475         block_index = chainman.m_blockman.LookupBlockIndex(block_hash);
2476         if (!block_index) {
2477             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
2478         }
2479         block_was_connected = block_index->IsValid(BLOCK_VALID_SCRIPTS);
2480     }
2481 
2482     bool index_ready = index->BlockUntilSyncedToCurrentChain();
2483 
2484     BlockFilter filter;
2485     uint256 filter_header;
2486     if (!index->LookupFilter(block_index, filter) ||
2487         !index->LookupFilterHeader(block_index, filter_header)) {
2488         int err_code;
2489         std::string errmsg = "Filter not found.";
2490 
2491         if (!block_was_connected) {
2492             err_code = RPC_INVALID_ADDRESS_OR_KEY;
2493             errmsg += " Block was not connected to active chain.";
2494         } else if (!index_ready) {
2495             err_code = RPC_MISC_ERROR;
2496             errmsg += " Block filters are still in the process of being indexed.";
2497         } else {
2498             err_code = RPC_INTERNAL_ERROR;
2499             errmsg += " This error is unexpected and indicates index corruption.";
2500         }
2501 
2502         throw JSONRPCError(err_code, errmsg);
2503     }
2504 
2505     UniValue ret(UniValue::VOBJ);
2506     ret.pushKV("filter", HexStr(filter.GetEncodedFilter()));
2507     ret.pushKV("header", filter_header.GetHex());
2508     return ret;
2509 },
2510     };
2511 }
2512 
2513 /**
2514  * Serialize the UTXO set to a file for loading elsewhere.
2515  *
2516  * @see SnapshotMetadata
2517  */
dumptxoutset()2518 static RPCHelpMan dumptxoutset()
2519 {
2520     return RPCHelpMan{
2521         "dumptxoutset",
2522         "\nWrite the serialized UTXO set to disk.\n",
2523         {
2524             {"path",
2525                 RPCArg::Type::STR,
2526                 RPCArg::Optional::NO,
2527                 /* default_val */ "",
2528                 "path to the output file. If relative, will be prefixed by datadir."},
2529         },
2530         RPCResult{
2531             RPCResult::Type::OBJ, "", "",
2532                 {
2533                     {RPCResult::Type::NUM, "coins_written", "the number of coins written in the snapshot"},
2534                     {RPCResult::Type::STR_HEX, "base_hash", "the hash of the base of the snapshot"},
2535                     {RPCResult::Type::NUM, "base_height", "the height of the base of the snapshot"},
2536                     {RPCResult::Type::STR, "path", "the absolute path that the snapshot was written to"},
2537                 }
2538         },
2539         RPCExamples{
2540             HelpExampleCli("dumptxoutset", "utxo.dat")
2541         },
2542         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
2543 {
2544     const fs::path path = fsbridge::AbsPathJoin(gArgs.GetDataDirNet(), request.params[0].get_str());
2545     // Write to a temporary path and then move into `path` on completion
2546     // to avoid confusion due to an interruption.
2547     const fs::path temppath = fsbridge::AbsPathJoin(gArgs.GetDataDirNet(), request.params[0].get_str() + ".incomplete");
2548 
2549     if (fs::exists(path)) {
2550         throw JSONRPCError(
2551             RPC_INVALID_PARAMETER,
2552             path.string() + " already exists. If you are sure this is what you want, "
2553             "move it out of the way first");
2554     }
2555 
2556     FILE* file{fsbridge::fopen(temppath, "wb")};
2557     CAutoFile afile{file, SER_DISK, CLIENT_VERSION};
2558     NodeContext& node = EnsureAnyNodeContext(request.context);
2559     UniValue result = CreateUTXOSnapshot(node, node.chainman->ActiveChainstate(), afile);
2560     fs::rename(temppath, path);
2561 
2562     result.pushKV("path", path.string());
2563     return result;
2564 },
2565     };
2566 }
2567 
CreateUTXOSnapshot(NodeContext & node,CChainState & chainstate,CAutoFile & afile)2568 UniValue CreateUTXOSnapshot(NodeContext& node, CChainState& chainstate, CAutoFile& afile)
2569 {
2570     std::unique_ptr<CCoinsViewCursor> pcursor;
2571     CCoinsStats stats{CoinStatsHashType::NONE};
2572     CBlockIndex* tip;
2573 
2574     {
2575         // We need to lock cs_main to ensure that the coinsdb isn't written to
2576         // between (i) flushing coins cache to disk (coinsdb), (ii) getting stats
2577         // based upon the coinsdb, and (iii) constructing a cursor to the
2578         // coinsdb for use below this block.
2579         //
2580         // Cursors returned by leveldb iterate over snapshots, so the contents
2581         // of the pcursor will not be affected by simultaneous writes during
2582         // use below this block.
2583         //
2584         // See discussion here:
2585         //   https://github.com/bitcoin/bitcoin/pull/15606#discussion_r274479369
2586         //
2587         LOCK(::cs_main);
2588 
2589         chainstate.ForceFlushStateToDisk();
2590 
2591         if (!GetUTXOStats(&chainstate.CoinsDB(), chainstate.m_blockman, stats, node.rpc_interruption_point)) {
2592             throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read UTXO set");
2593         }
2594 
2595         pcursor = chainstate.CoinsDB().Cursor();
2596         tip = chainstate.m_blockman.LookupBlockIndex(stats.hashBlock);
2597         CHECK_NONFATAL(tip);
2598     }
2599 
2600     SnapshotMetadata metadata{tip->GetBlockHash(), stats.coins_count, tip->nChainTx};
2601 
2602     afile << metadata;
2603 
2604     COutPoint key;
2605     Coin coin;
2606     unsigned int iter{0};
2607 
2608     while (pcursor->Valid()) {
2609         if (iter % 5000 == 0) node.rpc_interruption_point();
2610         ++iter;
2611         if (pcursor->GetKey(key) && pcursor->GetValue(coin)) {
2612             afile << key;
2613             afile << coin;
2614         }
2615 
2616         pcursor->Next();
2617     }
2618 
2619     afile.fclose();
2620 
2621     UniValue result(UniValue::VOBJ);
2622     result.pushKV("coins_written", stats.coins_count);
2623     result.pushKV("base_hash", tip->GetBlockHash().ToString());
2624     result.pushKV("base_height", tip->nHeight);
2625 
2626     return result;
2627 }
2628 
RegisterBlockchainRPCCommands(CRPCTable & t)2629 void RegisterBlockchainRPCCommands(CRPCTable &t)
2630 {
2631 // clang-format off
2632 static const CRPCCommand commands[] =
2633 { //  category              actor (function)
2634   //  --------------------- ------------------------
2635     { "blockchain",         &getblockchaininfo,                  },
2636     { "blockchain",         &getchaintxstats,                    },
2637     { "blockchain",         &getblockstats,                      },
2638     { "blockchain",         &getbestblockhash,                   },
2639     { "blockchain",         &getblockcount,                      },
2640     { "blockchain",         &getblock,                           },
2641     { "blockchain",         &getblockhash,                       },
2642     { "blockchain",         &getblockheader,                     },
2643     { "blockchain",         &getchaintips,                       },
2644     { "blockchain",         &getdifficulty,                      },
2645     { "blockchain",         &getmempoolancestors,                },
2646     { "blockchain",         &getmempooldescendants,              },
2647     { "blockchain",         &getmempoolentry,                    },
2648     { "blockchain",         &getmempoolinfo,                     },
2649     { "blockchain",         &getrawmempool,                      },
2650     { "blockchain",         &gettxout,                           },
2651     { "blockchain",         &gettxoutsetinfo,                    },
2652     { "blockchain",         &pruneblockchain,                    },
2653     { "blockchain",         &savemempool,                        },
2654     { "blockchain",         &verifychain,                        },
2655 
2656     { "blockchain",         &preciousblock,                      },
2657     { "blockchain",         &scantxoutset,                       },
2658     { "blockchain",         &getblockfilter,                     },
2659 
2660     /* Not shown in help */
2661     { "hidden",              &invalidateblock,                   },
2662     { "hidden",              &reconsiderblock,                   },
2663     { "hidden",              &waitfornewblock,                   },
2664     { "hidden",              &waitforblock,                      },
2665     { "hidden",              &waitforblockheight,                },
2666     { "hidden",              &syncwithvalidationinterfacequeue,  },
2667     { "hidden",              &dumptxoutset,                      },
2668 };
2669 // clang-format on
2670     for (const auto& c : commands) {
2671         t.appendCommand(c.name, &c);
2672     }
2673 }
2674