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