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